From b7f1ec17f98bd015414a9d7baf99c122c9ae9b2f Mon Sep 17 00:00:00 2001 From: lucas picollo Date: Thu, 29 Jan 2026 11:46:58 -0300 Subject: [PATCH 01/16] refactor: decouple api from indexer --- .eslintrc.json | 3 +- apps/api/.eslintrc.json | 3 + apps/api/drizzle.config.ts | 5 + apps/api/jest.config.js | 8 + apps/api/package.json | 43 + .../src}/cache/dao-cache.interface.ts | 0 .../src/api => api/src}/cache/dao-cache.ts | 2 +- apps/api/src/clients/comp/abi/governor.ts | 1157 +++++++++ apps/api/src/clients/comp/abi/index.ts | 2 + apps/api/src/clients/comp/abi/token.ts | 298 +++ apps/api/src/clients/comp/index.ts | 121 + apps/api/src/clients/ens/abi/governor.ts | 443 ++++ apps/api/src/clients/ens/abi/index.ts | 2 + apps/api/src/clients/ens/abi/token.ts | 454 ++++ apps/api/src/clients/ens/index.ts | 117 + apps/api/src/clients/governor.base.ts | 88 + apps/api/src/clients/gtc/abi/governor.ts | 647 +++++ apps/api/src/clients/gtc/abi/index.ts | 2 + apps/api/src/clients/gtc/abi/token.ts | 396 ++++ apps/api/src/clients/gtc/index.ts | 121 + apps/api/src/clients/index.ts | 9 + apps/api/src/clients/nouns/abi/auction.ts | 611 +++++ apps/api/src/clients/nouns/abi/governor.ts | 1936 +++++++++++++++ apps/api/src/clients/nouns/abi/index.ts | 4 + .../src/clients/nouns/abi/legacyGovernor.ts | 2098 +++++++++++++++++ apps/api/src/clients/nouns/abi/token.ts | 681 ++++++ apps/api/src/clients/nouns/index.ts | 125 + apps/api/src/clients/obol/abi/governor.ts | 882 +++++++ apps/api/src/clients/obol/abi/index.ts | 2 + apps/api/src/clients/obol/abi/token.ts | 465 ++++ apps/api/src/clients/obol/index.ts | 117 + apps/api/src/clients/op/abi/governor.ts | 1134 +++++++++ apps/api/src/clients/op/abi/index.ts | 3 + apps/api/src/clients/op/abi/legacyGovernor.ts | 1064 +++++++++ apps/api/src/clients/op/abi/token.ts | 364 +++ apps/api/src/clients/op/index.ts | 97 + apps/api/src/clients/scr/abi/governor.ts | 1124 +++++++++ apps/api/src/clients/scr/abi/index.ts | 2 + apps/api/src/clients/scr/abi/token.ts | 720 ++++++ apps/api/src/clients/scr/index.ts | 115 + apps/api/src/clients/uni/abi/governor.ts | 777 ++++++ apps/api/src/clients/uni/abi/index.ts | 2 + apps/api/src/clients/uni/abi/token.ts | 408 ++++ apps/api/src/clients/uni/index.ts | 115 + apps/api/src/clients/zk/abi/governor.ts | 839 +++++++ apps/api/src/clients/zk/abi/index.ts | 2 + apps/api/src/clients/zk/abi/token.ts | 547 +++++ apps/api/src/clients/zk/index.ts | 119 + .../controllers/account-balance/historical.ts | 4 +- .../src}/controllers/account-balance/index.ts | 0 .../account-balance/interactions.ts | 0 .../controllers/account-balance/listing.ts | 6 +- .../controllers/account-balance/variations.ts | 4 +- .../api => api/src}/controllers/dao/index.ts | 4 +- .../delegation-percentage/index.ts | 4 +- .../controllers/delegations/delegations.ts | 4 +- .../controllers/delegations/historical.ts | 4 +- .../src}/controllers/delegations/index.ts | 0 .../governance-activity/controller.ts | 3 + .../controllers/governance-activity/index.ts | 0 .../controllers/governance-activity/types.ts | 0 .../src/api => api/src}/controllers/index.ts | 0 .../src}/controllers/last-update/index.ts | 6 +- .../src}/controllers/proposals/index.ts | 0 .../proposals/proposals-activity.ts | 6 +- .../src}/controllers/proposals/proposals.ts | 4 +- .../src}/controllers/token-metrics/index.ts | 4 +- .../src}/controllers/token/index.ts | 0 .../controllers/token/token-distribution.ts | 3 + .../token/token-historical-data.ts | 2 +- .../controllers/token/token-properties.ts | 4 +- .../src}/controllers/transactions/index.ts | 4 +- .../src}/controllers/transfers/index.ts | 4 +- .../src}/controllers/treasury/index.ts | 4 +- .../controllers/voting-power/historical.ts | 4 +- .../src}/controllers/voting-power/index.ts | 0 .../src}/controllers/voting-power/listing.ts | 6 +- .../controllers/voting-power/variations.ts | 4 +- apps/api/src/database/index.ts | 32 + apps/api/src/database/schema.ts | 252 ++ apps/{indexer/src/api => api/src}/docs.ts | 0 apps/api/src/env.ts | 34 + apps/{indexer/src/api => api/src}/index.ts | 24 +- apps/api/src/lib/blockTime.ts | 15 + apps/api/src/lib/client.ts | 70 + apps/api/src/lib/constants.ts | 347 +++ apps/api/src/lib/date-helpers.ts | 62 + apps/api/src/lib/enums.ts | 29 + apps/api/src/lib/query-helpers.ts | 104 + apps/api/src/lib/time-series.ts | 105 + apps/api/src/lib/utils.ts | 5 + .../src}/mappers/account-balance/general.ts | 21 +- .../mappers/account-balance/historical.ts | 6 +- .../src}/mappers/account-balance/index.ts | 0 .../mappers/account-balance/interactions.ts | 2 +- .../mappers/account-balance/variations.ts | 0 .../src/api => api/src}/mappers/constants.ts | 0 .../src/api => api/src}/mappers/dao/index.ts | 0 .../mappers/delegation-percentage/index.ts | 0 .../src}/mappers/delegations/delegations.ts | 2 +- .../src}/mappers/delegations/historical.ts | 0 .../src}/mappers/delegations/index.ts | 0 .../src/api => api/src}/mappers/index.ts | 0 .../src}/mappers/last-update/index.ts | 0 .../src}/mappers/proposals/activity.ts | 0 .../src}/mappers/proposals/index.ts | 0 .../src}/mappers/proposals/proposals.ts | 2 +- .../src}/mappers/proposals/voters.ts | 0 .../src}/mappers/proposals/votes.ts | 2 +- .../src/api => api/src}/mappers/shared.ts | 0 .../src}/mappers/token-metrics/index.ts | 0 .../api => api/src}/mappers/token/index.ts | 2 +- .../src}/mappers/transactions/index.ts | 2 +- .../src}/mappers/transfers/index.ts | 2 +- .../api => api/src}/mappers/treasury/index.ts | 0 .../src}/mappers/voting-power/historical.ts | 4 +- .../src}/mappers/voting-power/index.ts | 0 .../src}/mappers/voting-power/variations.ts | 2 +- .../src}/middlewares/errorHandler.ts | 0 .../src/api => api/src}/middlewares/index.ts | 0 .../account-balance/historical.ts | 12 +- .../repositories/account-balance/index.ts | 0 .../account-balance/interactions.ts | 28 +- .../repositories/account-balance/listing.ts | 14 +- .../account-balance/variations.ts | 24 +- .../repositories/daoMetricsDayBucket/index.ts | 8 +- .../src}/repositories/delegations/general.ts | 10 +- .../repositories/delegations/historical.ts | 12 +- .../src}/repositories/delegations/index.ts | 0 .../src}/repositories/drizzle/index.ts | 48 +- .../src/api => api/src}/repositories/index.ts | 0 .../src}/repositories/last-update/index.ts | 16 +- .../repositories/proposals-activity/index.ts | 18 +- .../src}/repositories/token/erc20.ts | 10 +- .../src}/repositories/token/index.ts | 0 .../api => api/src}/repositories/token/nft.ts | 14 +- .../src}/repositories/transactions/index.ts | 12 +- .../src}/repositories/transfers/index.ts | 12 +- .../src}/repositories/treasury/index.ts | 12 +- .../src}/repositories/voting-power/general.ts | 92 +- .../src}/repositories/voting-power/index.ts | 0 .../src}/repositories/voting-power/nouns.ts | 12 +- .../services/account-balance/historical.ts | 5 +- .../src}/services/account-balance/index.ts | 0 .../src}/services/account-balance/listing.ts | 5 +- .../services/account-balance/variations.ts | 8 +- .../src}/services/coingecko/index.ts | 4 +- .../src}/services/coingecko/types.ts | 0 .../src/api => api/src}/services/dao/index.ts | 4 +- .../delegation-percentage.service.test.ts | 2 +- .../delegation-percentage.test.ts | 2 +- .../delegation-percentage.ts | 4 +- .../services/delegation-percentage/index.ts | 0 .../src}/services/delegations/current.ts | 5 +- .../src}/services/delegations/historical.ts | 5 +- .../src}/services/delegations/index.ts | 0 .../api => api/src}/services/dune/index.ts | 0 .../api => api/src}/services/dune/service.ts | 0 .../src/api => api/src}/services/index.ts | 0 .../src}/services/last-update/index.ts | 4 +- .../src}/services/nft-price/index.ts | 7 +- .../src}/services/proposals-activity/index.ts | 4 +- .../src}/services/proposals/index.ts | 5 +- .../src}/services/token-metrics/index.ts | 4 +- .../api => api/src}/services/token/index.ts | 0 .../api => api/src}/services/token/token.ts | 5 +- .../src}/services/transactions/index.ts | 5 +- .../src}/services/transfers/index.ts | 5 +- .../src}/services/treasury/index.ts | 0 .../treasury/providers/compound-provider.ts | 0 .../treasury/providers/defillama-provider.ts | 0 .../treasury/providers/dune-provider.ts | 0 .../src}/services/treasury/providers/index.ts | 0 .../treasury/providers/provider-cache.ts | 0 .../providers/treasury-provider.interface.ts | 0 .../treasury/treasury-provider-factory.ts | 2 +- .../services/treasury/treasury.service.ts | 2 +- .../src}/services/treasury/types.ts | 0 .../src}/services/voting-power/index.ts | 8 +- .../services/voting-power/voting-power.ts | 8 +- apps/api/tsconfig.json | 28 + apps/indexer/src/api/.gitkeep | 0 package.json | 3 +- pnpm-lock.yaml | 145 +- 184 files changed, 19800 insertions(+), 321 deletions(-) create mode 100644 apps/api/.eslintrc.json create mode 100644 apps/api/drizzle.config.ts create mode 100644 apps/api/jest.config.js create mode 100644 apps/api/package.json rename apps/{indexer/src/api => api/src}/cache/dao-cache.interface.ts (100%) rename apps/{indexer/src/api => api/src}/cache/dao-cache.ts (96%) create mode 100644 apps/api/src/clients/comp/abi/governor.ts create mode 100644 apps/api/src/clients/comp/abi/index.ts create mode 100644 apps/api/src/clients/comp/abi/token.ts create mode 100644 apps/api/src/clients/comp/index.ts create mode 100644 apps/api/src/clients/ens/abi/governor.ts create mode 100644 apps/api/src/clients/ens/abi/index.ts create mode 100644 apps/api/src/clients/ens/abi/token.ts create mode 100644 apps/api/src/clients/ens/index.ts create mode 100644 apps/api/src/clients/governor.base.ts create mode 100644 apps/api/src/clients/gtc/abi/governor.ts create mode 100644 apps/api/src/clients/gtc/abi/index.ts create mode 100644 apps/api/src/clients/gtc/abi/token.ts create mode 100644 apps/api/src/clients/gtc/index.ts create mode 100644 apps/api/src/clients/index.ts create mode 100644 apps/api/src/clients/nouns/abi/auction.ts create mode 100644 apps/api/src/clients/nouns/abi/governor.ts create mode 100644 apps/api/src/clients/nouns/abi/index.ts create mode 100644 apps/api/src/clients/nouns/abi/legacyGovernor.ts create mode 100644 apps/api/src/clients/nouns/abi/token.ts create mode 100644 apps/api/src/clients/nouns/index.ts create mode 100644 apps/api/src/clients/obol/abi/governor.ts create mode 100644 apps/api/src/clients/obol/abi/index.ts create mode 100644 apps/api/src/clients/obol/abi/token.ts create mode 100644 apps/api/src/clients/obol/index.ts create mode 100644 apps/api/src/clients/op/abi/governor.ts create mode 100644 apps/api/src/clients/op/abi/index.ts create mode 100644 apps/api/src/clients/op/abi/legacyGovernor.ts create mode 100644 apps/api/src/clients/op/abi/token.ts create mode 100644 apps/api/src/clients/op/index.ts create mode 100644 apps/api/src/clients/scr/abi/governor.ts create mode 100644 apps/api/src/clients/scr/abi/index.ts create mode 100644 apps/api/src/clients/scr/abi/token.ts create mode 100644 apps/api/src/clients/scr/index.ts create mode 100644 apps/api/src/clients/uni/abi/governor.ts create mode 100644 apps/api/src/clients/uni/abi/index.ts create mode 100644 apps/api/src/clients/uni/abi/token.ts create mode 100644 apps/api/src/clients/uni/index.ts create mode 100644 apps/api/src/clients/zk/abi/governor.ts create mode 100644 apps/api/src/clients/zk/abi/index.ts create mode 100644 apps/api/src/clients/zk/abi/token.ts create mode 100644 apps/api/src/clients/zk/index.ts rename apps/{indexer/src/api => api/src}/controllers/account-balance/historical.ts (94%) rename apps/{indexer/src/api => api/src}/controllers/account-balance/index.ts (100%) rename apps/{indexer/src/api => api/src}/controllers/account-balance/interactions.ts (100%) rename apps/{indexer/src/api => api/src}/controllers/account-balance/listing.ts (96%) rename apps/{indexer/src/api => api/src}/controllers/account-balance/variations.ts (97%) rename apps/{indexer/src/api => api/src}/controllers/dao/index.ts (88%) rename apps/{indexer/src/api => api/src}/controllers/delegation-percentage/index.ts (92%) rename apps/{indexer/src/api => api/src}/controllers/delegations/delegations.ts (90%) rename apps/{indexer/src/api => api/src}/controllers/delegations/historical.ts (93%) rename apps/{indexer/src/api => api/src}/controllers/delegations/index.ts (100%) rename apps/{indexer/src/api => api/src}/controllers/governance-activity/controller.ts (99%) rename apps/{indexer/src/api => api/src}/controllers/governance-activity/index.ts (100%) rename apps/{indexer/src/api => api/src}/controllers/governance-activity/types.ts (100%) rename apps/{indexer/src/api => api/src}/controllers/index.ts (100%) rename apps/{indexer/src/api => api/src}/controllers/last-update/index.ts (85%) rename apps/{indexer/src/api => api/src}/controllers/proposals/index.ts (100%) rename apps/{indexer/src/api => api/src}/controllers/proposals/proposals-activity.ts (93%) rename apps/{indexer/src/api => api/src}/controllers/proposals/proposals.ts (98%) rename apps/{indexer/src/api => api/src}/controllers/token-metrics/index.ts (91%) rename apps/{indexer/src/api => api/src}/controllers/token/index.ts (100%) rename apps/{indexer/src/api => api/src}/controllers/token/token-distribution.ts (98%) rename apps/{indexer/src/api => api/src}/controllers/token/token-historical-data.ts (98%) rename apps/{indexer/src/api => api/src}/controllers/token/token-properties.ts (93%) rename apps/{indexer/src/api => api/src}/controllers/transactions/index.ts (95%) rename apps/{indexer/src/api => api/src}/controllers/transfers/index.ts (95%) rename apps/{indexer/src/api => api/src}/controllers/treasury/index.ts (97%) rename apps/{indexer/src/api => api/src}/controllers/voting-power/historical.ts (97%) rename apps/{indexer/src/api => api/src}/controllers/voting-power/index.ts (100%) rename apps/{indexer/src/api => api/src}/controllers/voting-power/listing.ts (94%) rename apps/{indexer/src/api => api/src}/controllers/voting-power/variations.ts (97%) create mode 100644 apps/api/src/database/index.ts create mode 100644 apps/api/src/database/schema.ts rename apps/{indexer/src/api => api/src}/docs.ts (100%) create mode 100644 apps/api/src/env.ts rename apps/{indexer/src/api => api/src}/index.ts (92%) create mode 100644 apps/api/src/lib/blockTime.ts create mode 100644 apps/api/src/lib/client.ts create mode 100644 apps/api/src/lib/constants.ts create mode 100644 apps/api/src/lib/date-helpers.ts create mode 100644 apps/api/src/lib/enums.ts create mode 100644 apps/api/src/lib/query-helpers.ts create mode 100644 apps/api/src/lib/time-series.ts create mode 100644 apps/api/src/lib/utils.ts rename apps/{indexer/src/api => api/src}/mappers/account-balance/general.ts (86%) rename apps/{indexer/src/api => api/src}/mappers/account-balance/historical.ts (94%) rename apps/{indexer/src/api => api/src}/mappers/account-balance/index.ts (100%) rename apps/{indexer/src/api => api/src}/mappers/account-balance/interactions.ts (97%) rename apps/{indexer/src/api => api/src}/mappers/account-balance/variations.ts (100%) rename apps/{indexer/src/api => api/src}/mappers/constants.ts (100%) rename apps/{indexer/src/api => api/src}/mappers/dao/index.ts (100%) rename apps/{indexer/src/api => api/src}/mappers/delegation-percentage/index.ts (100%) rename apps/{indexer/src/api => api/src}/mappers/delegations/delegations.ts (95%) rename apps/{indexer/src/api => api/src}/mappers/delegations/historical.ts (100%) rename apps/{indexer/src/api => api/src}/mappers/delegations/index.ts (100%) rename apps/{indexer/src/api => api/src}/mappers/index.ts (100%) rename apps/{indexer/src/api => api/src}/mappers/last-update/index.ts (100%) rename apps/{indexer/src/api => api/src}/mappers/proposals/activity.ts (100%) rename apps/{indexer/src/api => api/src}/mappers/proposals/index.ts (100%) rename apps/{indexer/src/api => api/src}/mappers/proposals/proposals.ts (98%) rename apps/{indexer/src/api => api/src}/mappers/proposals/voters.ts (100%) rename apps/{indexer/src/api => api/src}/mappers/proposals/votes.ts (97%) rename apps/{indexer/src/api => api/src}/mappers/shared.ts (100%) rename apps/{indexer/src/api => api/src}/mappers/token-metrics/index.ts (100%) rename apps/{indexer/src/api => api/src}/mappers/token/index.ts (97%) rename apps/{indexer/src/api => api/src}/mappers/transactions/index.ts (99%) rename apps/{indexer/src/api => api/src}/mappers/transfers/index.ts (98%) rename apps/{indexer/src/api => api/src}/mappers/treasury/index.ts (100%) rename apps/{indexer/src/api => api/src}/mappers/voting-power/historical.ts (96%) rename apps/{indexer/src/api => api/src}/mappers/voting-power/index.ts (100%) rename apps/{indexer/src/api => api/src}/mappers/voting-power/variations.ts (99%) rename apps/{indexer/src/api => api/src}/middlewares/errorHandler.ts (100%) rename apps/{indexer/src/api => api/src}/middlewares/index.ts (100%) rename apps/{indexer/src/api => api/src}/repositories/account-balance/historical.ts (88%) rename apps/{indexer/src/api => api/src}/repositories/account-balance/index.ts (100%) rename apps/{indexer/src/api => api/src}/repositories/account-balance/interactions.ts (89%) rename apps/{indexer/src/api => api/src}/repositories/account-balance/listing.ts (88%) rename apps/{indexer/src/api => api/src}/repositories/account-balance/variations.ts (89%) rename apps/{indexer/src/api => api/src}/repositories/daoMetricsDayBucket/index.ts (88%) rename apps/{indexer/src/api => api/src}/repositories/delegations/general.ts (59%) rename apps/{indexer/src/api => api/src}/repositories/delegations/historical.ts (87%) rename apps/{indexer/src/api => api/src}/repositories/delegations/index.ts (100%) rename apps/{indexer/src/api => api/src}/repositories/drizzle/index.ts (90%) rename apps/{indexer/src/api => api/src}/repositories/index.ts (100%) rename apps/{indexer/src/api => api/src}/repositories/last-update/index.ts (79%) rename apps/{indexer/src/api => api/src}/repositories/proposals-activity/index.ts (94%) rename apps/{indexer/src/api => api/src}/repositories/token/erc20.ts (55%) rename apps/{indexer/src/api => api/src}/repositories/token/index.ts (100%) rename apps/{indexer/src/api => api/src}/repositories/token/nft.ts (74%) rename apps/{indexer/src/api => api/src}/repositories/transactions/index.ts (97%) rename apps/{indexer/src/api => api/src}/repositories/transfers/index.ts (91%) rename apps/{indexer/src/api => api/src}/repositories/treasury/index.ts (82%) rename apps/{indexer/src/api => api/src}/repositories/voting-power/general.ts (84%) rename apps/{indexer/src/api => api/src}/repositories/voting-power/index.ts (100%) rename apps/{indexer/src/api => api/src}/repositories/voting-power/nouns.ts (92%) rename apps/{indexer/src/api => api/src}/services/account-balance/historical.ts (92%) rename apps/{indexer/src/api => api/src}/services/account-balance/index.ts (100%) rename apps/{indexer/src/api => api/src}/services/account-balance/listing.ts (92%) rename apps/{indexer/src/api => api/src}/services/account-balance/variations.ts (96%) rename apps/{indexer/src/api => api/src}/services/coingecko/index.ts (96%) rename apps/{indexer/src/api => api/src}/services/coingecko/types.ts (100%) rename apps/{indexer/src/api => api/src}/services/dao/index.ts (92%) rename apps/{indexer/src/api => api/src}/services/delegation-percentage/delegation-percentage.service.test.ts (99%) rename apps/{indexer/src/api => api/src}/services/delegation-percentage/delegation-percentage.test.ts (99%) rename apps/{indexer/src/api => api/src}/services/delegation-percentage/delegation-percentage.ts (98%) rename apps/{indexer/src/api => api/src}/services/delegation-percentage/index.ts (100%) rename apps/{indexer/src/api => api/src}/services/delegations/current.ts (79%) rename apps/{indexer/src/api => api/src}/services/delegations/historical.ts (91%) rename apps/{indexer/src/api => api/src}/services/delegations/index.ts (100%) rename apps/{indexer/src/api => api/src}/services/dune/index.ts (100%) rename apps/{indexer/src/api => api/src}/services/dune/service.ts (100%) rename apps/{indexer/src/api => api/src}/services/index.ts (100%) rename apps/{indexer/src/api => api/src}/services/last-update/index.ts (78%) rename apps/{indexer/src/api => api/src}/services/nft-price/index.ts (95%) rename apps/{indexer/src/api => api/src}/services/proposals-activity/index.ts (99%) rename apps/{indexer/src/api => api/src}/services/proposals/index.ts (98%) rename apps/{indexer/src/api => api/src}/services/token-metrics/index.ts (97%) rename apps/{indexer/src/api => api/src}/services/token/index.ts (100%) rename apps/{indexer/src/api => api/src}/services/token/token.ts (83%) rename apps/{indexer/src/api => api/src}/services/transactions/index.ts (92%) rename apps/{indexer/src/api => api/src}/services/transfers/index.ts (91%) rename apps/{indexer/src/api => api/src}/services/treasury/index.ts (100%) rename apps/{indexer/src/api => api/src}/services/treasury/providers/compound-provider.ts (100%) rename apps/{indexer/src/api => api/src}/services/treasury/providers/defillama-provider.ts (100%) rename apps/{indexer/src/api => api/src}/services/treasury/providers/dune-provider.ts (100%) rename apps/{indexer/src/api => api/src}/services/treasury/providers/index.ts (100%) rename apps/{indexer/src/api => api/src}/services/treasury/providers/provider-cache.ts (100%) rename apps/{indexer/src/api => api/src}/services/treasury/providers/treasury-provider.interface.ts (100%) rename apps/{indexer/src/api => api/src}/services/treasury/treasury-provider-factory.ts (97%) rename apps/{indexer/src/api => api/src}/services/treasury/treasury.service.ts (98%) rename apps/{indexer/src/api => api/src}/services/treasury/types.ts (100%) rename apps/{indexer/src/api => api/src}/services/voting-power/index.ts (97%) rename apps/{indexer/src/api => api/src}/services/voting-power/voting-power.ts (91%) create mode 100644 apps/api/tsconfig.json create mode 100644 apps/indexer/src/api/.gitkeep diff --git a/.eslintrc.json b/.eslintrc.json index 63a8e1329..db4f424fc 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -3,7 +3,8 @@ "extends": [ "eslint:recommended", "plugin:@typescript-eslint/recommended", - "prettier" + "prettier", + "plugin:import/recommended" ], "parser": "@typescript-eslint/parser", "plugins": ["@typescript-eslint", "prettier"], diff --git a/apps/api/.eslintrc.json b/apps/api/.eslintrc.json new file mode 100644 index 000000000..c2594e335 --- /dev/null +++ b/apps/api/.eslintrc.json @@ -0,0 +1,3 @@ +{ + "extends": ["../../.eslintrc.json"] +} diff --git a/apps/api/drizzle.config.ts b/apps/api/drizzle.config.ts new file mode 100644 index 000000000..e38ddbb82 --- /dev/null +++ b/apps/api/drizzle.config.ts @@ -0,0 +1,5 @@ +import { defineConfig } from "drizzle-kit"; +export default defineConfig({ + dialect: "postgresql", + schema: "./src/db", +}); diff --git a/apps/api/jest.config.js b/apps/api/jest.config.js new file mode 100644 index 000000000..ba20b9b7c --- /dev/null +++ b/apps/api/jest.config.js @@ -0,0 +1,8 @@ +module.exports = { + preset: "ts-jest", + testEnvironment: "node", + testMatch: ["**/*.test.ts"], + moduleNameMapper: { + "^@/(.*)$": "/src/$1", + }, +}; diff --git a/apps/api/package.json b/apps/api/package.json new file mode 100644 index 000000000..54359ae2b --- /dev/null +++ b/apps/api/package.json @@ -0,0 +1,43 @@ +{ + "name": "@anticapture/api", + "version": "1.0.0", + "main": "dist/index.js", + "scripts": { + "typecheck": "tsc --noEmit", + "test": "jest", + "test:watch": "jest --watch", + "clean": "rm -rf node_modules *.tsbuildinfo dist", + "start": "node dist/index.js", + "build": "tsc", + "build:watch": "tsc --watch", + "dev": "tsc src/index.ts --watch" + }, + "keywords": [], + "author": "", + "license": "ISC", + "description": "", + "dependencies": { + "@hono/zod-openapi": "^0.19.6", + "axios": "^1.9.0", + "drizzle-kit": "^0.31.4", + "drizzle-orm": "~0.41.0", + "hono": "^4.7.10", + "viem": "^2.41.2", + "zod": "^3.25.3", + "zod-validation-error": "^3.4.1" + }, + "devDependencies": { + "@types/jest": "^29.5.14", + "@types/node": "^20.16.5", + "@types/pg": "^8.15.6", + "dotenv": "^16.5.0", + "eslint": "^8.53.0", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-prettier": "^5.2.1", + "jest": "^29.7.0", + "prettier": "^3.5.3", + "ts-jest": "^29.4.1", + "ts-node": "^10.9.2", + "typescript": "^5.8.3" + } +} diff --git a/apps/indexer/src/api/cache/dao-cache.interface.ts b/apps/api/src/cache/dao-cache.interface.ts similarity index 100% rename from apps/indexer/src/api/cache/dao-cache.interface.ts rename to apps/api/src/cache/dao-cache.interface.ts diff --git a/apps/indexer/src/api/cache/dao-cache.ts b/apps/api/src/cache/dao-cache.ts similarity index 96% rename from apps/indexer/src/api/cache/dao-cache.ts rename to apps/api/src/cache/dao-cache.ts index d21f0a751..8a51c6a2d 100644 --- a/apps/indexer/src/api/cache/dao-cache.ts +++ b/apps/api/src/cache/dao-cache.ts @@ -1,4 +1,4 @@ -import { DaoResponse } from "@/api/mappers"; +import { DaoResponse } from "@/mappers"; import { DaoDataCache } from "./dao-cache.interface"; /** diff --git a/apps/api/src/clients/comp/abi/governor.ts b/apps/api/src/clients/comp/abi/governor.ts new file mode 100644 index 000000000..a28f75df0 --- /dev/null +++ b/apps/api/src/clients/comp/abi/governor.ts @@ -0,0 +1,1157 @@ +export const GovernorAbi = [ + { inputs: [], stateMutability: "nonpayable", type: "constructor" }, + { inputs: [], name: "CheckpointUnorderedInsertion", type: "error" }, + { inputs: [], name: "FailedCall", type: "error" }, + { + inputs: [{ internalType: "address", name: "voter", type: "address" }], + name: "GovernorAlreadyCastVote", + type: "error", + }, + { + inputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + name: "GovernorAlreadyQueuedProposal", + type: "error", + }, + { inputs: [], name: "GovernorDisabledDeposit", type: "error" }, + { + inputs: [ + { internalType: "address", name: "voter", type: "address" }, + { internalType: "uint256", name: "usedVotes", type: "uint256" }, + { internalType: "uint256", name: "remainingWeight", type: "uint256" }, + ], + name: "GovernorExceedRemainingWeight", + type: "error", + }, + { + inputs: [ + { internalType: "address", name: "proposer", type: "address" }, + { internalType: "uint256", name: "votes", type: "uint256" }, + { internalType: "uint256", name: "threshold", type: "uint256" }, + ], + name: "GovernorInsufficientProposerVotes", + type: "error", + }, + { + inputs: [ + { internalType: "uint256", name: "targets", type: "uint256" }, + { internalType: "uint256", name: "calldatas", type: "uint256" }, + { internalType: "uint256", name: "values", type: "uint256" }, + ], + name: "GovernorInvalidProposalLength", + type: "error", + }, + { + inputs: [{ internalType: "address", name: "voter", type: "address" }], + name: "GovernorInvalidSignature", + type: "error", + }, + { inputs: [], name: "GovernorInvalidVoteParams", type: "error" }, + { inputs: [], name: "GovernorInvalidVoteType", type: "error" }, + { + inputs: [ + { internalType: "uint256", name: "votingPeriod", type: "uint256" }, + ], + name: "GovernorInvalidVotingPeriod", + type: "error", + }, + { + inputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + name: "GovernorNonexistentProposal", + type: "error", + }, + { + inputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + name: "GovernorNotQueuedProposal", + type: "error", + }, + { + inputs: [{ internalType: "address", name: "account", type: "address" }], + name: "GovernorOnlyExecutor", + type: "error", + }, + { + inputs: [{ internalType: "address", name: "account", type: "address" }], + name: "GovernorOnlyProposer", + type: "error", + }, + { inputs: [], name: "GovernorQueueNotImplemented", type: "error" }, + { + inputs: [{ internalType: "address", name: "proposer", type: "address" }], + name: "GovernorRestrictedProposer", + type: "error", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { + internalType: "enum IGovernor.ProposalState", + name: "current", + type: "uint8", + }, + { internalType: "bytes32", name: "expectedStates", type: "bytes32" }, + ], + name: "GovernorUnexpectedProposalState", + type: "error", + }, + { + inputs: [ + { internalType: "uint256", name: "balance", type: "uint256" }, + { internalType: "uint256", name: "needed", type: "uint256" }, + ], + name: "InsufficientBalance", + type: "error", + }, + { + inputs: [ + { internalType: "address", name: "account", type: "address" }, + { internalType: "uint256", name: "currentNonce", type: "uint256" }, + ], + name: "InvalidAccountNonce", + type: "error", + }, + { inputs: [], name: "InvalidInitialization", type: "error" }, + { inputs: [], name: "NotInitializing", type: "error" }, + { inputs: [], name: "ProposalIdAlreadySet", type: "error" }, + { + inputs: [ + { internalType: "address", name: "proposer", type: "address" }, + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { + internalType: "enum IGovernor.ProposalState", + name: "state", + type: "uint8", + }, + ], + name: "ProposerActiveProposal", + type: "error", + }, + { + inputs: [ + { internalType: "uint8", name: "bits", type: "uint8" }, + { internalType: "uint256", name: "value", type: "uint256" }, + ], + name: "SafeCastOverflowedUintDowncast", + type: "error", + }, + { + inputs: [ + { internalType: "bytes32", name: "reason", type: "bytes32" }, + { internalType: "address", name: "caller", type: "address" }, + ], + name: "Unauthorized", + type: "error", + }, + { anonymous: false, inputs: [], name: "EIP712DomainChanged", type: "event" }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint64", + name: "version", + type: "uint64", + }, + ], + name: "Initialized", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint64", + name: "oldVoteExtension", + type: "uint64", + }, + { + indexed: false, + internalType: "uint64", + name: "newVoteExtension", + type: "uint64", + }, + ], + name: "LateQuorumVoteExtensionSet", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "proposalId", + type: "uint256", + }, + ], + name: "ProposalCanceled", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "proposalId", + type: "uint256", + }, + { + indexed: false, + internalType: "address", + name: "proposer", + type: "address", + }, + { + indexed: false, + internalType: "address[]", + name: "targets", + type: "address[]", + }, + { + indexed: false, + internalType: "uint256[]", + name: "values", + type: "uint256[]", + }, + { + indexed: false, + internalType: "string[]", + name: "signatures", + type: "string[]", + }, + { + indexed: false, + internalType: "bytes[]", + name: "calldatas", + type: "bytes[]", + }, + { + indexed: false, + internalType: "uint256", + name: "voteStart", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "voteEnd", + type: "uint256", + }, + { + indexed: false, + internalType: "string", + name: "description", + type: "string", + }, + ], + name: "ProposalCreated", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "proposalId", + type: "uint256", + }, + ], + name: "ProposalExecuted", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "uint256", + name: "proposalId", + type: "uint256", + }, + { + indexed: false, + internalType: "uint64", + name: "extendedDeadline", + type: "uint64", + }, + ], + name: "ProposalExtended", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "oldProposalGuardian", + type: "address", + }, + { + indexed: false, + internalType: "uint96", + name: "oldProposalGuardianExpiry", + type: "uint96", + }, + { + indexed: false, + internalType: "address", + name: "newProposalGuardian", + type: "address", + }, + { + indexed: false, + internalType: "uint96", + name: "newProposalGuardianExpiry", + type: "uint96", + }, + ], + name: "ProposalGuardianSet", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "proposalId", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "etaSeconds", + type: "uint256", + }, + ], + name: "ProposalQueued", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "oldProposalThreshold", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "newProposalThreshold", + type: "uint256", + }, + ], + name: "ProposalThresholdSet", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "oldQuorum", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "newQuorum", + type: "uint256", + }, + ], + name: "QuorumUpdated", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "oldTimelock", + type: "address", + }, + { + indexed: false, + internalType: "address", + name: "newTimelock", + type: "address", + }, + ], + name: "TimelockChange", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "voter", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "proposalId", + type: "uint256", + }, + { indexed: false, internalType: "uint8", name: "support", type: "uint8" }, + { + indexed: false, + internalType: "uint256", + name: "weight", + type: "uint256", + }, + { + indexed: false, + internalType: "string", + name: "reason", + type: "string", + }, + ], + name: "VoteCast", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "voter", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "proposalId", + type: "uint256", + }, + { indexed: false, internalType: "uint8", name: "support", type: "uint8" }, + { + indexed: false, + internalType: "uint256", + name: "weight", + type: "uint256", + }, + { + indexed: false, + internalType: "string", + name: "reason", + type: "string", + }, + { indexed: false, internalType: "bytes", name: "params", type: "bytes" }, + ], + name: "VoteCastWithParams", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "oldVotingDelay", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "newVotingDelay", + type: "uint256", + }, + ], + name: "VotingDelaySet", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "oldVotingPeriod", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "newVotingPeriod", + type: "uint256", + }, + ], + name: "VotingPeriodSet", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "account", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "expiration", + type: "uint256", + }, + ], + name: "WhitelistAccountExpirationSet", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "oldGuardian", + type: "address", + }, + { + indexed: false, + internalType: "address", + name: "newGuardian", + type: "address", + }, + ], + name: "WhitelistGuardianSet", + type: "event", + }, + { + inputs: [], + name: "BALLOT_TYPEHASH", + outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "CLOCK_MODE", + outputs: [{ internalType: "string", name: "", type: "string" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "COUNTING_MODE", + outputs: [{ internalType: "string", name: "", type: "string" }], + stateMutability: "pure", + type: "function", + }, + { + inputs: [], + name: "EXTENDED_BALLOT_TYPEHASH", + outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "__acceptAdmin", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "_proposalId", type: "uint256" }], + name: "cancel", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address[]", name: "_targets", type: "address[]" }, + { internalType: "uint256[]", name: "_values", type: "uint256[]" }, + { internalType: "bytes[]", name: "_calldatas", type: "bytes[]" }, + { internalType: "bytes32", name: "_descriptionHash", type: "bytes32" }, + ], + name: "cancel", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "uint8", name: "support", type: "uint8" }, + ], + name: "castVote", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "uint8", name: "support", type: "uint8" }, + { internalType: "address", name: "voter", type: "address" }, + { internalType: "bytes", name: "signature", type: "bytes" }, + ], + name: "castVoteBySig", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "uint8", name: "support", type: "uint8" }, + { internalType: "string", name: "reason", type: "string" }, + ], + name: "castVoteWithReason", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "uint8", name: "support", type: "uint8" }, + { internalType: "string", name: "reason", type: "string" }, + { internalType: "bytes", name: "params", type: "bytes" }, + ], + name: "castVoteWithReasonAndParams", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "uint8", name: "support", type: "uint8" }, + { internalType: "address", name: "voter", type: "address" }, + { internalType: "string", name: "reason", type: "string" }, + { internalType: "bytes", name: "params", type: "bytes" }, + { internalType: "bytes", name: "signature", type: "bytes" }, + ], + name: "castVoteWithReasonAndParamsBySig", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "clock", + outputs: [{ internalType: "uint48", name: "", type: "uint48" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "eip712Domain", + outputs: [ + { internalType: "bytes1", name: "fields", type: "bytes1" }, + { internalType: "string", name: "name", type: "string" }, + { internalType: "string", name: "version", type: "string" }, + { internalType: "uint256", name: "chainId", type: "uint256" }, + { internalType: "address", name: "verifyingContract", type: "address" }, + { internalType: "bytes32", name: "salt", type: "bytes32" }, + { internalType: "uint256[]", name: "extensions", type: "uint256[]" }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address[]", name: "targets", type: "address[]" }, + { internalType: "uint256[]", name: "values", type: "uint256[]" }, + { internalType: "bytes[]", name: "calldatas", type: "bytes[]" }, + { internalType: "bytes32", name: "descriptionHash", type: "bytes32" }, + ], + name: "execute", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "payable", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "_proposalId", type: "uint256" }], + name: "execute", + outputs: [], + stateMutability: "payable", + type: "function", + }, + { + inputs: [], + name: "getNextProposalId", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "account", type: "address" }, + { internalType: "uint256", name: "timepoint", type: "uint256" }, + ], + name: "getVotes", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "account", type: "address" }, + { internalType: "uint256", name: "timepoint", type: "uint256" }, + { internalType: "bytes", name: "params", type: "bytes" }, + ], + name: "getVotesWithParams", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "address", name: "account", type: "address" }, + ], + name: "hasVoted", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address[]", name: "_targets", type: "address[]" }, + { internalType: "uint256[]", name: "_values", type: "uint256[]" }, + { internalType: "bytes[]", name: "_calldatas", type: "bytes[]" }, + { internalType: "bytes32", name: "_descriptionHash", type: "bytes32" }, + ], + name: "hashProposal", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint48", name: "_initialVotingDelay", type: "uint48" }, + { internalType: "uint32", name: "_initialVotingPeriod", type: "uint32" }, + { + internalType: "uint256", + name: "_initialProposalThreshold", + type: "uint256", + }, + { internalType: "contract IComp", name: "_compAddress", type: "address" }, + { internalType: "uint256", name: "_quorumVotes", type: "uint256" }, + { + internalType: "contract ICompoundTimelock", + name: "_timelockAddress", + type: "address", + }, + { internalType: "uint48", name: "_initialVoteExtension", type: "uint48" }, + { internalType: "address", name: "_whitelistGuardian", type: "address" }, + { + components: [ + { internalType: "address", name: "account", type: "address" }, + { internalType: "uint96", name: "expiration", type: "uint96" }, + ], + internalType: "struct CompoundGovernor.ProposalGuardian", + name: "_proposalGuardian", + type: "tuple", + }, + ], + name: "initialize", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "_account", type: "address" }], + name: "isWhitelisted", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "lateQuorumVoteExtension", + outputs: [{ internalType: "uint48", name: "", type: "uint48" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "proposer", type: "address" }], + name: "latestProposalIds", + outputs: [ + { internalType: "uint256", name: "latestProposalId", type: "uint256" }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "name", + outputs: [{ internalType: "string", name: "", type: "string" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "owner", type: "address" }], + name: "nonces", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "", type: "address" }, + { internalType: "address", name: "", type: "address" }, + { internalType: "uint256[]", name: "", type: "uint256[]" }, + { internalType: "uint256[]", name: "", type: "uint256[]" }, + { internalType: "bytes", name: "", type: "bytes" }, + ], + name: "onERC1155BatchReceived", + outputs: [{ internalType: "bytes4", name: "", type: "bytes4" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "", type: "address" }, + { internalType: "address", name: "", type: "address" }, + { internalType: "uint256", name: "", type: "uint256" }, + { internalType: "uint256", name: "", type: "uint256" }, + { internalType: "bytes", name: "", type: "bytes" }, + ], + name: "onERC1155Received", + outputs: [{ internalType: "bytes4", name: "", type: "bytes4" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "", type: "address" }, + { internalType: "address", name: "", type: "address" }, + { internalType: "uint256", name: "", type: "uint256" }, + { internalType: "bytes", name: "", type: "bytes" }, + ], + name: "onERC721Received", + outputs: [{ internalType: "bytes4", name: "", type: "bytes4" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "proposalCount", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "_proposalId", type: "uint256" }], + name: "proposalDeadline", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "_proposalId", type: "uint256" }], + name: "proposalDetails", + outputs: [ + { internalType: "address[]", name: "", type: "address[]" }, + { internalType: "uint256[]", name: "", type: "uint256[]" }, + { internalType: "bytes[]", name: "", type: "bytes[]" }, + { internalType: "bytes32", name: "", type: "bytes32" }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + name: "proposalEta", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "proposalGuardian", + outputs: [ + { internalType: "address", name: "account", type: "address" }, + { internalType: "uint96", name: "expiration", type: "uint96" }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "_proposalId", type: "uint256" }], + name: "proposalNeedsQueuing", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + name: "proposalProposer", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + name: "proposalSnapshot", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "proposalThreshold", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + name: "proposalVotes", + outputs: [ + { internalType: "uint256", name: "againstVotes", type: "uint256" }, + { internalType: "uint256", name: "forVotes", type: "uint256" }, + { internalType: "uint256", name: "abstainVotes", type: "uint256" }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address[]", name: "_targets", type: "address[]" }, + { internalType: "uint256[]", name: "_values", type: "uint256[]" }, + { internalType: "bytes[]", name: "_calldatas", type: "bytes[]" }, + { internalType: "string", name: "_description", type: "string" }, + ], + name: "propose", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address[]", name: "targets", type: "address[]" }, + { internalType: "uint256[]", name: "values", type: "uint256[]" }, + { internalType: "bytes[]", name: "calldatas", type: "bytes[]" }, + { internalType: "bytes32", name: "descriptionHash", type: "bytes32" }, + ], + name: "queue", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "_proposalId", type: "uint256" }], + name: "queue", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "_voteStart", type: "uint256" }], + name: "quorum", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "target", type: "address" }, + { internalType: "uint256", name: "value", type: "uint256" }, + { internalType: "bytes", name: "data", type: "bytes" }, + ], + name: "relay", + outputs: [], + stateMutability: "payable", + type: "function", + }, + { + inputs: [ + { internalType: "uint48", name: "newVoteExtension", type: "uint48" }, + ], + name: "setLateQuorumVoteExtension", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "setNextProposalId", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + components: [ + { internalType: "address", name: "account", type: "address" }, + { internalType: "uint96", name: "expiration", type: "uint96" }, + ], + internalType: "struct CompoundGovernor.ProposalGuardian", + name: "_newProposalGuardian", + type: "tuple", + }, + ], + name: "setProposalGuardian", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "uint256", + name: "newProposalThreshold", + type: "uint256", + }, + ], + name: "setProposalThreshold", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "_amount", type: "uint256" }], + name: "setQuorum", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint48", name: "newVotingDelay", type: "uint48" }, + ], + name: "setVotingDelay", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint32", name: "newVotingPeriod", type: "uint32" }, + ], + name: "setVotingPeriod", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "_account", type: "address" }, + { internalType: "uint256", name: "_expiration", type: "uint256" }, + ], + name: "setWhitelistAccountExpiration", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "_newWhitelistGuardian", + type: "address", + }, + ], + name: "setWhitelistGuardian", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "_proposalId", type: "uint256" }], + name: "state", + outputs: [ + { internalType: "enum IGovernor.ProposalState", name: "", type: "uint8" }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "bytes4", name: "interfaceId", type: "bytes4" }], + name: "supportsInterface", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "timelock", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "token", + outputs: [{ internalType: "contract IComp", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "contract ICompoundTimelock", + name: "newTimelock", + type: "address", + }, + ], + name: "updateTimelock", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "address", name: "account", type: "address" }, + ], + name: "usedVotes", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "version", + outputs: [{ internalType: "string", name: "", type: "string" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "votingDelay", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "votingPeriod", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "account", type: "address" }], + name: "whitelistAccountExpirations", + outputs: [{ internalType: "uint256", name: "timestamp", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "whitelistGuardian", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { stateMutability: "payable", type: "receive" }, +] as const; diff --git a/apps/api/src/clients/comp/abi/index.ts b/apps/api/src/clients/comp/abi/index.ts new file mode 100644 index 000000000..c3304e098 --- /dev/null +++ b/apps/api/src/clients/comp/abi/index.ts @@ -0,0 +1,2 @@ +export { GovernorAbi as COMPGovernorAbi } from "./governor"; +export { TokenAbi as COMPTokenAbi } from "./token"; diff --git a/apps/api/src/clients/comp/abi/token.ts b/apps/api/src/clients/comp/abi/token.ts new file mode 100644 index 000000000..8b359ce7e --- /dev/null +++ b/apps/api/src/clients/comp/abi/token.ts @@ -0,0 +1,298 @@ +export const TokenAbi = [ + { + inputs: [{ internalType: "address", name: "account", type: "address" }], + payable: false, + stateMutability: "nonpayable", + type: "constructor", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "owner", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "spender", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "amount", + type: "uint256", + }, + ], + name: "Approval", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "delegator", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "fromDelegate", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "toDelegate", + type: "address", + }, + ], + name: "DelegateChanged", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "delegate", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "previousBalance", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "newBalance", + type: "uint256", + }, + ], + name: "DelegateVotesChanged", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "address", name: "from", type: "address" }, + { indexed: true, internalType: "address", name: "to", type: "address" }, + { + indexed: false, + internalType: "uint256", + name: "amount", + type: "uint256", + }, + ], + name: "Transfer", + type: "event", + }, + { + constant: true, + inputs: [], + name: "DELEGATION_TYPEHASH", + outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], + payable: false, + stateMutability: "view", + type: "function", + }, + { + constant: true, + inputs: [], + name: "DOMAIN_TYPEHASH", + outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], + payable: false, + stateMutability: "view", + type: "function", + }, + { + constant: true, + inputs: [ + { internalType: "address", name: "account", type: "address" }, + { internalType: "address", name: "spender", type: "address" }, + ], + name: "allowance", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + payable: false, + stateMutability: "view", + type: "function", + }, + { + constant: false, + inputs: [ + { internalType: "address", name: "spender", type: "address" }, + { internalType: "uint256", name: "rawAmount", type: "uint256" }, + ], + name: "approve", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + payable: false, + stateMutability: "nonpayable", + type: "function", + }, + { + constant: true, + inputs: [{ internalType: "address", name: "account", type: "address" }], + name: "balanceOf", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + payable: false, + stateMutability: "view", + type: "function", + }, + { + constant: true, + inputs: [ + { internalType: "address", name: "", type: "address" }, + { internalType: "uint32", name: "", type: "uint32" }, + ], + name: "checkpoints", + outputs: [ + { internalType: "uint32", name: "fromBlock", type: "uint32" }, + { internalType: "uint96", name: "votes", type: "uint96" }, + ], + payable: false, + stateMutability: "view", + type: "function", + }, + { + constant: true, + inputs: [], + name: "decimals", + outputs: [{ internalType: "uint8", name: "", type: "uint8" }], + payable: false, + stateMutability: "view", + type: "function", + }, + { + constant: false, + inputs: [{ internalType: "address", name: "delegatee", type: "address" }], + name: "delegate", + outputs: [], + payable: false, + stateMutability: "nonpayable", + type: "function", + }, + { + constant: false, + inputs: [ + { internalType: "address", name: "delegatee", type: "address" }, + { internalType: "uint256", name: "nonce", type: "uint256" }, + { internalType: "uint256", name: "expiry", type: "uint256" }, + { internalType: "uint8", name: "v", type: "uint8" }, + { internalType: "bytes32", name: "r", type: "bytes32" }, + { internalType: "bytes32", name: "s", type: "bytes32" }, + ], + name: "delegateBySig", + outputs: [], + payable: false, + stateMutability: "nonpayable", + type: "function", + }, + { + constant: true, + inputs: [{ internalType: "address", name: "", type: "address" }], + name: "delegates", + outputs: [{ internalType: "address", name: "", type: "address" }], + payable: false, + stateMutability: "view", + type: "function", + }, + { + constant: true, + inputs: [{ internalType: "address", name: "account", type: "address" }], + name: "getCurrentVotes", + outputs: [{ internalType: "uint96", name: "", type: "uint96" }], + payable: false, + stateMutability: "view", + type: "function", + }, + { + constant: true, + inputs: [ + { internalType: "address", name: "account", type: "address" }, + { internalType: "uint256", name: "blockNumber", type: "uint256" }, + ], + name: "getPriorVotes", + outputs: [{ internalType: "uint96", name: "", type: "uint96" }], + payable: false, + stateMutability: "view", + type: "function", + }, + { + constant: true, + inputs: [], + name: "name", + outputs: [{ internalType: "string", name: "", type: "string" }], + payable: false, + stateMutability: "view", + type: "function", + }, + { + constant: true, + inputs: [{ internalType: "address", name: "", type: "address" }], + name: "nonces", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + payable: false, + stateMutability: "view", + type: "function", + }, + { + constant: true, + inputs: [{ internalType: "address", name: "", type: "address" }], + name: "numCheckpoints", + outputs: [{ internalType: "uint32", name: "", type: "uint32" }], + payable: false, + stateMutability: "view", + type: "function", + }, + { + constant: true, + inputs: [], + name: "symbol", + outputs: [{ internalType: "string", name: "", type: "string" }], + payable: false, + stateMutability: "view", + type: "function", + }, + { + constant: true, + inputs: [], + name: "totalSupply", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + payable: false, + stateMutability: "view", + type: "function", + }, + { + constant: false, + inputs: [ + { internalType: "address", name: "dst", type: "address" }, + { internalType: "uint256", name: "rawAmount", type: "uint256" }, + ], + name: "transfer", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + payable: false, + stateMutability: "nonpayable", + type: "function", + }, + { + constant: false, + inputs: [ + { internalType: "address", name: "src", type: "address" }, + { internalType: "address", name: "dst", type: "address" }, + { internalType: "uint256", name: "rawAmount", type: "uint256" }, + ], + name: "transferFrom", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + payable: false, + stateMutability: "nonpayable", + type: "function", + }, +] as const; diff --git a/apps/api/src/clients/comp/index.ts b/apps/api/src/clients/comp/index.ts new file mode 100644 index 000000000..306d0d551 --- /dev/null +++ b/apps/api/src/clients/comp/index.ts @@ -0,0 +1,121 @@ +import { + Account, + Address, + Chain, + Client, + fromHex, + toHex, + Transport, +} from "viem"; + +import { DAOClient } from "@/interfaces/client"; +import { GovernorBase } from "../governor.base"; +import { COMPGovernorAbi } from "./abi"; +import { getBlockNumber, readContract } from "viem/actions"; + +export class COMPClient< + TTransport extends Transport = Transport, + TChain extends Chain = Chain, + TAccount extends Account | undefined = Account | undefined, +> + extends GovernorBase + implements DAOClient +{ + private abi: typeof COMPGovernorAbi; + private address: Address; + + constructor(client: Client, address: Address) { + super(client); + this.address = address; + this.abi = COMPGovernorAbi; + } + + getDaoId(): string { + return "COMP"; + } + + async getQuorum(): Promise { + const blockNumber = await getBlockNumber(this.client); + const targetBlock = blockNumber - 10n; + return readContract(this.client, { + abi: this.abi, + address: this.address, + functionName: "quorum", + args: [targetBlock < 0n ? 0n : targetBlock], + }); + } + + async getProposalThreshold(): Promise { + return readContract(this.client, { + abi: this.abi, + address: this.address, + functionName: "proposalThreshold", + }); + } + + async getVotingDelay(): Promise { + return readContract(this.client, { + abi: this.abi, + address: this.address, + functionName: "votingDelay", + }); + } + + async getVotingPeriod(): Promise { + return readContract(this.client, { + abi: this.abi, + address: this.address, + functionName: "votingPeriod", + }); + } + + async getTimelockDelay(): Promise { + const timelockAddress = await readContract(this.client, { + abi: this.abi, + address: this.address, + functionName: "timelock", + }); + return readContract(this.client, { + abi: [ + { + inputs: [], + name: "delay", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, + ], + address: timelockAddress, + functionName: "delay", + }); + } + + async getCurrentBlockNumber(): Promise { + const result = await this.client.request({ + method: "eth_blockNumber", + }); + return fromHex(result, "number"); + } + + async getBlockTime(blockNumber: number): Promise { + const block = await this.client.request({ + method: "eth_getBlockByNumber", + params: [toHex(blockNumber), false], + }); + return block?.timestamp ? fromHex(block.timestamp, "number") : null; + } + + calculateQuorum(votes: { + forVotes: bigint; + againstVotes: bigint; + abstainVotes: bigint; + }): bigint { + return votes.forVotes; + } +} diff --git a/apps/api/src/clients/ens/abi/governor.ts b/apps/api/src/clients/ens/abi/governor.ts new file mode 100644 index 000000000..787305172 --- /dev/null +++ b/apps/api/src/clients/ens/abi/governor.ts @@ -0,0 +1,443 @@ +export const GovernorAbi = [ + { + inputs: [ + { internalType: "contract ERC20Votes", name: "_token", type: "address" }, + { + internalType: "contract TimelockController", + name: "_timelock", + type: "address", + }, + ], + stateMutability: "nonpayable", + type: "constructor", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "proposalId", + type: "uint256", + }, + ], + name: "ProposalCanceled", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "proposalId", + type: "uint256", + }, + { + indexed: false, + internalType: "address", + name: "proposer", + type: "address", + }, + { + indexed: false, + internalType: "address[]", + name: "targets", + type: "address[]", + }, + { + indexed: false, + internalType: "uint256[]", + name: "values", + type: "uint256[]", + }, + { + indexed: false, + internalType: "string[]", + name: "signatures", + type: "string[]", + }, + { + indexed: false, + internalType: "bytes[]", + name: "calldatas", + type: "bytes[]", + }, + { + indexed: false, + internalType: "uint256", + name: "startBlock", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "endBlock", + type: "uint256", + }, + { + indexed: false, + internalType: "string", + name: "description", + type: "string", + }, + ], + name: "ProposalCreated", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "proposalId", + type: "uint256", + }, + ], + name: "ProposalExecuted", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "proposalId", + type: "uint256", + }, + { indexed: false, internalType: "uint256", name: "eta", type: "uint256" }, + ], + name: "ProposalQueued", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "oldQuorumNumerator", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "newQuorumNumerator", + type: "uint256", + }, + ], + name: "QuorumNumeratorUpdated", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "oldTimelock", + type: "address", + }, + { + indexed: false, + internalType: "address", + name: "newTimelock", + type: "address", + }, + ], + name: "TimelockChange", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "voter", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "proposalId", + type: "uint256", + }, + { indexed: false, internalType: "uint8", name: "support", type: "uint8" }, + { + indexed: false, + internalType: "uint256", + name: "weight", + type: "uint256", + }, + { + indexed: false, + internalType: "string", + name: "reason", + type: "string", + }, + ], + name: "VoteCast", + type: "event", + }, + { + inputs: [], + name: "BALLOT_TYPEHASH", + outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "COUNTING_MODE", + outputs: [{ internalType: "string", name: "", type: "string" }], + stateMutability: "pure", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "uint8", name: "support", type: "uint8" }, + ], + name: "castVote", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "uint8", name: "support", type: "uint8" }, + { internalType: "uint8", name: "v", type: "uint8" }, + { internalType: "bytes32", name: "r", type: "bytes32" }, + { internalType: "bytes32", name: "s", type: "bytes32" }, + ], + name: "castVoteBySig", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "uint8", name: "support", type: "uint8" }, + { internalType: "string", name: "reason", type: "string" }, + ], + name: "castVoteWithReason", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address[]", name: "targets", type: "address[]" }, + { internalType: "uint256[]", name: "values", type: "uint256[]" }, + { internalType: "bytes[]", name: "calldatas", type: "bytes[]" }, + { internalType: "bytes32", name: "descriptionHash", type: "bytes32" }, + ], + name: "execute", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "payable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "account", type: "address" }, + { internalType: "uint256", name: "blockNumber", type: "uint256" }, + ], + name: "getVotes", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "address", name: "account", type: "address" }, + ], + name: "hasVoted", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address[]", name: "targets", type: "address[]" }, + { internalType: "uint256[]", name: "values", type: "uint256[]" }, + { internalType: "bytes[]", name: "calldatas", type: "bytes[]" }, + { internalType: "bytes32", name: "descriptionHash", type: "bytes32" }, + ], + name: "hashProposal", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "pure", + type: "function", + }, + { + inputs: [], + name: "name", + outputs: [{ internalType: "string", name: "", type: "string" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + name: "proposalDeadline", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + name: "proposalEta", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + name: "proposalSnapshot", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "proposalThreshold", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "pure", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + name: "proposalVotes", + outputs: [ + { internalType: "uint256", name: "againstVotes", type: "uint256" }, + { internalType: "uint256", name: "forVotes", type: "uint256" }, + { internalType: "uint256", name: "abstainVotes", type: "uint256" }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address[]", name: "targets", type: "address[]" }, + { internalType: "uint256[]", name: "values", type: "uint256[]" }, + { internalType: "bytes[]", name: "calldatas", type: "bytes[]" }, + { internalType: "string", name: "description", type: "string" }, + ], + name: "propose", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address[]", name: "targets", type: "address[]" }, + { internalType: "uint256[]", name: "values", type: "uint256[]" }, + { internalType: "bytes[]", name: "calldatas", type: "bytes[]" }, + { internalType: "bytes32", name: "descriptionHash", type: "bytes32" }, + ], + name: "queue", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "blockNumber", type: "uint256" }], + name: "quorum", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "quorumDenominator", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "pure", + type: "function", + }, + { + inputs: [], + name: "quorumNumerator", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + name: "state", + outputs: [ + { internalType: "enum IGovernor.ProposalState", name: "", type: "uint8" }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "bytes4", name: "interfaceId", type: "bytes4" }], + name: "supportsInterface", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "timelock", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "token", + outputs: [ + { internalType: "contract ERC20Votes", name: "", type: "address" }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "newQuorumNumerator", type: "uint256" }, + ], + name: "updateQuorumNumerator", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "contract TimelockController", + name: "newTimelock", + type: "address", + }, + ], + name: "updateTimelock", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "version", + outputs: [{ internalType: "string", name: "", type: "string" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "votingDelay", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "pure", + type: "function", + }, + { + inputs: [], + name: "votingPeriod", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "pure", + type: "function", + }, +] as const; diff --git a/apps/api/src/clients/ens/abi/index.ts b/apps/api/src/clients/ens/abi/index.ts new file mode 100644 index 000000000..05b364bef --- /dev/null +++ b/apps/api/src/clients/ens/abi/index.ts @@ -0,0 +1,2 @@ +export { GovernorAbi as ENSGovernorAbi } from "./governor"; +export { TokenAbi as ENSTokenAbi } from "./token"; diff --git a/apps/api/src/clients/ens/abi/token.ts b/apps/api/src/clients/ens/abi/token.ts new file mode 100644 index 000000000..7a8b5f7dd --- /dev/null +++ b/apps/api/src/clients/ens/abi/token.ts @@ -0,0 +1,454 @@ +export const TokenAbi = [ + { + inputs: [ + { internalType: "uint256", name: "freeSupply", type: "uint256" }, + { internalType: "uint256", name: "airdropSupply", type: "uint256" }, + { internalType: "uint256", name: "_claimPeriodEnds", type: "uint256" }, + ], + stateMutability: "nonpayable", + type: "constructor", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "owner", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "spender", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "value", + type: "uint256", + }, + ], + name: "Approval", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "claimant", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "amount", + type: "uint256", + }, + ], + name: "Claim", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "delegator", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "fromDelegate", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "toDelegate", + type: "address", + }, + ], + name: "DelegateChanged", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "delegate", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "previousBalance", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "newBalance", + type: "uint256", + }, + ], + name: "DelegateVotesChanged", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "bytes32", + name: "merkleRoot", + type: "bytes32", + }, + ], + name: "MerkleRootChanged", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "previousOwner", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "newOwner", + type: "address", + }, + ], + name: "OwnershipTransferred", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "address", name: "from", type: "address" }, + { indexed: true, internalType: "address", name: "to", type: "address" }, + { + indexed: false, + internalType: "uint256", + name: "value", + type: "uint256", + }, + ], + name: "Transfer", + type: "event", + }, + { + inputs: [], + name: "DOMAIN_SEPARATOR", + outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "owner", type: "address" }, + { internalType: "address", name: "spender", type: "address" }, + ], + name: "allowance", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "spender", type: "address" }, + { internalType: "uint256", name: "amount", type: "uint256" }, + ], + name: "approve", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "account", type: "address" }], + name: "balanceOf", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "account", type: "address" }, + { internalType: "uint32", name: "pos", type: "uint32" }, + ], + name: "checkpoints", + outputs: [ + { + components: [ + { internalType: "uint32", name: "fromBlock", type: "uint32" }, + { internalType: "uint224", name: "votes", type: "uint224" }, + ], + internalType: "struct ERC20Votes.Checkpoint", + name: "", + type: "tuple", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "claimPeriodEnds", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "amount", type: "uint256" }, + { internalType: "address", name: "delegate", type: "address" }, + { internalType: "bytes32[]", name: "merkleProof", type: "bytes32[]" }, + ], + name: "claimTokens", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "decimals", + outputs: [{ internalType: "uint8", name: "", type: "uint8" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "spender", type: "address" }, + { internalType: "uint256", name: "subtractedValue", type: "uint256" }, + ], + name: "decreaseAllowance", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "delegatee", type: "address" }], + name: "delegate", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "delegatee", type: "address" }, + { internalType: "uint256", name: "nonce", type: "uint256" }, + { internalType: "uint256", name: "expiry", type: "uint256" }, + { internalType: "uint8", name: "v", type: "uint8" }, + { internalType: "bytes32", name: "r", type: "bytes32" }, + { internalType: "bytes32", name: "s", type: "bytes32" }, + ], + name: "delegateBySig", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "account", type: "address" }], + name: "delegates", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "blockNumber", type: "uint256" }], + name: "getPastTotalSupply", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "account", type: "address" }, + { internalType: "uint256", name: "blockNumber", type: "uint256" }, + ], + name: "getPastVotes", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "account", type: "address" }], + name: "getVotes", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "spender", type: "address" }, + { internalType: "uint256", name: "addedValue", type: "uint256" }, + ], + name: "increaseAllowance", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "index", type: "uint256" }], + name: "isClaimed", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "merkleRoot", + outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "minimumMintInterval", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "dest", type: "address" }, + { internalType: "uint256", name: "amount", type: "uint256" }, + ], + name: "mint", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "mintCap", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "name", + outputs: [{ internalType: "string", name: "", type: "string" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "nextMint", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "owner", type: "address" }], + name: "nonces", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "account", type: "address" }], + name: "numCheckpoints", + outputs: [{ internalType: "uint32", name: "", type: "uint32" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "owner", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "owner", type: "address" }, + { internalType: "address", name: "spender", type: "address" }, + { internalType: "uint256", name: "value", type: "uint256" }, + { internalType: "uint256", name: "deadline", type: "uint256" }, + { internalType: "uint8", name: "v", type: "uint8" }, + { internalType: "bytes32", name: "r", type: "bytes32" }, + { internalType: "bytes32", name: "s", type: "bytes32" }, + ], + name: "permit", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "renounceOwnership", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "bytes32", name: "_merkleRoot", type: "bytes32" }], + name: "setMerkleRoot", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "dest", type: "address" }], + name: "sweep", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "symbol", + outputs: [{ internalType: "string", name: "", type: "string" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "totalSupply", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "recipient", type: "address" }, + { internalType: "uint256", name: "amount", type: "uint256" }, + ], + name: "transfer", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "sender", type: "address" }, + { internalType: "address", name: "recipient", type: "address" }, + { internalType: "uint256", name: "amount", type: "uint256" }, + ], + name: "transferFrom", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "newOwner", type: "address" }], + name: "transferOwnership", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, +] as const; diff --git a/apps/api/src/clients/ens/index.ts b/apps/api/src/clients/ens/index.ts new file mode 100644 index 000000000..065355692 --- /dev/null +++ b/apps/api/src/clients/ens/index.ts @@ -0,0 +1,117 @@ +import { + Account, + Address, + Chain, + Client, + fromHex, + toHex, + Transport, +} from "viem"; +import { getBlockNumber, readContract } from "viem/actions"; + +import { DAOClient } from "@/interfaces/client"; +import { ENSGovernorAbi } from "./abi"; +import { GovernorBase } from "../governor.base"; + +export class ENSClient< + TTransport extends Transport = Transport, + TChain extends Chain = Chain, + TAccount extends Account | undefined = Account | undefined, + > + extends GovernorBase + implements DAOClient +{ + private abi: typeof ENSGovernorAbi; + private address: Address; + + constructor(client: Client, address: Address) { + super(client); + this.address = address; + this.abi = ENSGovernorAbi; + } + + getDaoId(): string { + return "ENS"; + } + + async getQuorum(): Promise { + const blockNumber = await getBlockNumber(this.client); + const targetBlock = blockNumber - 10n; + return readContract(this.client, { + abi: this.abi, + address: this.address, + functionName: "quorum", + args: [targetBlock < 0n ? 0n : targetBlock], + }); + } + + async getProposalThreshold(): Promise { + return readContract(this.client, { + abi: this.abi, + address: this.address, + functionName: "proposalThreshold", + }); + } + + async getVotingDelay(): Promise { + return readContract(this.client, { + abi: this.abi, + address: this.address, + functionName: "votingDelay", + }); + } + + async getVotingPeriod(): Promise { + return readContract(this.client, { + abi: this.abi, + address: this.address, + functionName: "votingPeriod", + }); + } + + async getTimelockDelay(): Promise { + const timelockAddress = await readContract(this.client, { + abi: this.abi, + address: this.address, + functionName: "timelock", + }); + return readContract(this.client, { + abi: [ + { + constant: true, + inputs: [], + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + payable: false, + stateMutability: "view", + type: "function", + name: "getMinDelay", + }, + ], + address: timelockAddress, + functionName: "getMinDelay", + }); + } + + async getCurrentBlockNumber(): Promise { + const result = await this.client.request({ + method: "eth_blockNumber", + }); + return fromHex(result, "number"); + } + + async getBlockTime(blockNumber: number): Promise { + const block = await this.client.request({ + method: "eth_getBlockByNumber", + params: [toHex(blockNumber), false], + }); + return block?.timestamp ? fromHex(block.timestamp, "number") : null; + } + + calculateQuorum(votes: { + forVotes: bigint; + againstVotes: bigint; + abstainVotes: bigint; + }): bigint { + return votes.forVotes + votes.abstainVotes; + } +} diff --git a/apps/api/src/clients/governor.base.ts b/apps/api/src/clients/governor.base.ts new file mode 100644 index 000000000..b170848a0 --- /dev/null +++ b/apps/api/src/clients/governor.base.ts @@ -0,0 +1,88 @@ +import { Account, Chain, Client, Transport } from "viem"; + +import { DBProposal } from "../api/mappers"; +import { ProposalStatus } from "../lib/constants"; + +/** + * Base implementation for EVM Compound-based governance contracts. + * Provides common functionality for proposal status calculation + * not handled by the indexing process. + */ + +export abstract class GovernorBase< + TTransport extends Transport = Transport, + TChain extends Chain = Chain, + TAccount extends Account | undefined = Account | undefined, +> { + constructor(protected client: Client) {} + + abstract calculateQuorum(votes: { + forVotes: bigint; + againstVotes: bigint; + abstainVotes: bigint; + }): bigint; + + abstract getCurrentBlockNumber(): Promise; + + abstract getQuorum(proposalId: string | null): Promise; + + async getProposalStatus( + proposal: Pick< + DBProposal, + | "id" + | "status" + | "startBlock" + | "endBlock" + | "forVotes" + | "againstVotes" + | "abstainVotes" + >, + ): Promise { + const currentBlock = await this.getCurrentBlockNumber(); + + // Skip proposals already finalized via event + if ( + [ + ProposalStatus.CANCELED, + ProposalStatus.QUEUED, + ProposalStatus.EXECUTED, + ].includes(proposal.status as ProposalStatus) + ) { + return proposal.status; + } + + if (currentBlock < proposal.startBlock) { + return ProposalStatus.PENDING; + } + + if ( + currentBlock >= proposal.startBlock && + currentBlock < proposal.endBlock + ) { + return ProposalStatus.ACTIVE; + } + + // After voting period ends + if (currentBlock >= proposal.endBlock) { + const proposalQuorum = this.calculateQuorum({ + forVotes: proposal.forVotes, + againstVotes: proposal.againstVotes, + abstainVotes: proposal.abstainVotes, + }); + + const quorum = await this.getQuorum(proposal.id); + const voteSum = + proposal.forVotes + proposal.againstVotes + proposal.abstainVotes; + + const hasMajority = proposal.forVotes > proposal.againstVotes; + if (voteSum > quorum && !hasMajority) return ProposalStatus.DEFEATED; + + const hasQuorum = proposalQuorum >= quorum; + if (!hasQuorum) return ProposalStatus.NO_QUORUM; + + return ProposalStatus.SUCCEEDED; + } + + return proposal.status; + } +} diff --git a/apps/api/src/clients/gtc/abi/governor.ts b/apps/api/src/clients/gtc/abi/governor.ts new file mode 100644 index 000000000..4964f587b --- /dev/null +++ b/apps/api/src/clients/gtc/abi/governor.ts @@ -0,0 +1,647 @@ +export const GovernorAbi = [ + { + inputs: [ + { internalType: "uint256", name: "_initialVotingDelay", type: "uint256" }, + { + internalType: "uint256", + name: "_initialVotingPeriod", + type: "uint256", + }, + { + internalType: "uint256", + name: "_initialProposalThreshold", + type: "uint256", + }, + ], + stateMutability: "nonpayable", + type: "constructor", + }, + { inputs: [], name: "Empty", type: "error" }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "proposalId", + type: "uint256", + }, + ], + name: "ProposalCanceled", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "proposalId", + type: "uint256", + }, + { + indexed: false, + internalType: "address", + name: "proposer", + type: "address", + }, + { + indexed: false, + internalType: "address[]", + name: "targets", + type: "address[]", + }, + { + indexed: false, + internalType: "uint256[]", + name: "values", + type: "uint256[]", + }, + { + indexed: false, + internalType: "string[]", + name: "signatures", + type: "string[]", + }, + { + indexed: false, + internalType: "bytes[]", + name: "calldatas", + type: "bytes[]", + }, + { + indexed: false, + internalType: "uint256", + name: "startBlock", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "endBlock", + type: "uint256", + }, + { + indexed: false, + internalType: "string", + name: "description", + type: "string", + }, + ], + name: "ProposalCreated", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "proposalId", + type: "uint256", + }, + ], + name: "ProposalExecuted", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "proposalId", + type: "uint256", + }, + { indexed: false, internalType: "uint256", name: "eta", type: "uint256" }, + ], + name: "ProposalQueued", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "oldProposalThreshold", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "newProposalThreshold", + type: "uint256", + }, + ], + name: "ProposalThresholdSet", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "oldTimelock", + type: "address", + }, + { + indexed: false, + internalType: "address", + name: "newTimelock", + type: "address", + }, + ], + name: "TimelockChange", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "voter", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "proposalId", + type: "uint256", + }, + { indexed: false, internalType: "uint8", name: "support", type: "uint8" }, + { + indexed: false, + internalType: "uint256", + name: "weight", + type: "uint256", + }, + { + indexed: false, + internalType: "string", + name: "reason", + type: "string", + }, + ], + name: "VoteCast", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "voter", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "proposalId", + type: "uint256", + }, + { indexed: false, internalType: "uint8", name: "support", type: "uint8" }, + { + indexed: false, + internalType: "uint256", + name: "weight", + type: "uint256", + }, + { + indexed: false, + internalType: "string", + name: "reason", + type: "string", + }, + { indexed: false, internalType: "bytes", name: "params", type: "bytes" }, + ], + name: "VoteCastWithParams", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "oldVotingDelay", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "newVotingDelay", + type: "uint256", + }, + ], + name: "VotingDelaySet", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "oldVotingPeriod", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "newVotingPeriod", + type: "uint256", + }, + ], + name: "VotingPeriodSet", + type: "event", + }, + { + inputs: [], + name: "BALLOT_TYPEHASH", + outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "COUNTING_MODE", + outputs: [{ internalType: "string", name: "", type: "string" }], + stateMutability: "pure", + type: "function", + }, + { + inputs: [], + name: "EXTENDED_BALLOT_TYPEHASH", + outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "__acceptAdmin", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "uint8", name: "support", type: "uint8" }, + ], + name: "castVote", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "uint8", name: "support", type: "uint8" }, + { internalType: "uint8", name: "v", type: "uint8" }, + { internalType: "bytes32", name: "r", type: "bytes32" }, + { internalType: "bytes32", name: "s", type: "bytes32" }, + ], + name: "castVoteBySig", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "uint8", name: "support", type: "uint8" }, + { internalType: "string", name: "reason", type: "string" }, + ], + name: "castVoteWithReason", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "uint8", name: "support", type: "uint8" }, + { internalType: "string", name: "reason", type: "string" }, + { internalType: "bytes", name: "params", type: "bytes" }, + ], + name: "castVoteWithReasonAndParams", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "uint8", name: "support", type: "uint8" }, + { internalType: "string", name: "reason", type: "string" }, + { internalType: "bytes", name: "params", type: "bytes" }, + { internalType: "uint8", name: "v", type: "uint8" }, + { internalType: "bytes32", name: "r", type: "bytes32" }, + { internalType: "bytes32", name: "s", type: "bytes32" }, + ], + name: "castVoteWithReasonAndParamsBySig", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address[]", name: "targets", type: "address[]" }, + { internalType: "uint256[]", name: "values", type: "uint256[]" }, + { internalType: "bytes[]", name: "calldatas", type: "bytes[]" }, + { internalType: "bytes32", name: "descriptionHash", type: "bytes32" }, + ], + name: "execute", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "payable", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "", type: "address" }], + name: "fractionalVoteNonce", + outputs: [{ internalType: "uint128", name: "", type: "uint128" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "account", type: "address" }, + { internalType: "uint256", name: "blockNumber", type: "uint256" }, + ], + name: "getVotes", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "account", type: "address" }, + { internalType: "uint256", name: "blockNumber", type: "uint256" }, + { internalType: "bytes", name: "params", type: "bytes" }, + ], + name: "getVotesWithParams", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "address", name: "account", type: "address" }, + ], + name: "hasVoted", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address[]", name: "targets", type: "address[]" }, + { internalType: "uint256[]", name: "values", type: "uint256[]" }, + { internalType: "bytes[]", name: "calldatas", type: "bytes[]" }, + { internalType: "bytes32", name: "descriptionHash", type: "bytes32" }, + ], + name: "hashProposal", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "pure", + type: "function", + }, + { + inputs: [], + name: "name", + outputs: [{ internalType: "string", name: "", type: "string" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "", type: "address" }, + { internalType: "address", name: "", type: "address" }, + { internalType: "uint256[]", name: "", type: "uint256[]" }, + { internalType: "uint256[]", name: "", type: "uint256[]" }, + { internalType: "bytes", name: "", type: "bytes" }, + ], + name: "onERC1155BatchReceived", + outputs: [{ internalType: "bytes4", name: "", type: "bytes4" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "", type: "address" }, + { internalType: "address", name: "", type: "address" }, + { internalType: "uint256", name: "", type: "uint256" }, + { internalType: "uint256", name: "", type: "uint256" }, + { internalType: "bytes", name: "", type: "bytes" }, + ], + name: "onERC1155Received", + outputs: [{ internalType: "bytes4", name: "", type: "bytes4" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "", type: "address" }, + { internalType: "address", name: "", type: "address" }, + { internalType: "uint256", name: "", type: "uint256" }, + { internalType: "bytes", name: "", type: "bytes" }, + ], + name: "onERC721Received", + outputs: [{ internalType: "bytes4", name: "", type: "bytes4" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + name: "proposalDeadline", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + name: "proposalEta", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + name: "proposalSnapshot", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "proposalThreshold", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + name: "proposalVotes", + outputs: [ + { internalType: "uint256", name: "againstVotes", type: "uint256" }, + { internalType: "uint256", name: "forVotes", type: "uint256" }, + { internalType: "uint256", name: "abstainVotes", type: "uint256" }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address[]", name: "targets", type: "address[]" }, + { internalType: "uint256[]", name: "values", type: "uint256[]" }, + { internalType: "bytes[]", name: "calldatas", type: "bytes[]" }, + { internalType: "string", name: "description", type: "string" }, + ], + name: "propose", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address[]", name: "targets", type: "address[]" }, + { internalType: "uint256[]", name: "values", type: "uint256[]" }, + { internalType: "bytes[]", name: "calldatas", type: "bytes[]" }, + { internalType: "bytes32", name: "descriptionHash", type: "bytes32" }, + ], + name: "queue", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "", type: "uint256" }], + name: "quorum", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "pure", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "target", type: "address" }, + { internalType: "uint256", name: "value", type: "uint256" }, + { internalType: "bytes", name: "data", type: "bytes" }, + ], + name: "relay", + outputs: [], + stateMutability: "payable", + type: "function", + }, + { + inputs: [ + { + internalType: "uint256", + name: "newProposalThreshold", + type: "uint256", + }, + ], + name: "setProposalThreshold", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "newVotingDelay", type: "uint256" }, + ], + name: "setVotingDelay", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "newVotingPeriod", type: "uint256" }, + ], + name: "setVotingPeriod", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + name: "state", + outputs: [ + { internalType: "enum IGovernor.ProposalState", name: "", type: "uint8" }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "bytes4", name: "interfaceId", type: "bytes4" }], + name: "supportsInterface", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "timelock", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "token", + outputs: [ + { internalType: "contract ERC20VotesComp", name: "", type: "address" }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "contract ICompoundTimelock", + name: "newTimelock", + type: "address", + }, + ], + name: "updateTimelock", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "version", + outputs: [{ internalType: "string", name: "", type: "string" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "address", name: "account", type: "address" }, + ], + name: "voteWeightCast", + outputs: [{ internalType: "uint128", name: "", type: "uint128" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "votingDelay", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "votingPeriod", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { stateMutability: "payable", type: "receive" }, +] as const; diff --git a/apps/api/src/clients/gtc/abi/index.ts b/apps/api/src/clients/gtc/abi/index.ts new file mode 100644 index 000000000..e0776d35e --- /dev/null +++ b/apps/api/src/clients/gtc/abi/index.ts @@ -0,0 +1,2 @@ +export { GovernorAbi } from "./governor"; +export { TokenAbi } from "./token"; diff --git a/apps/api/src/clients/gtc/abi/token.ts b/apps/api/src/clients/gtc/abi/token.ts new file mode 100644 index 000000000..4f2105b63 --- /dev/null +++ b/apps/api/src/clients/gtc/abi/token.ts @@ -0,0 +1,396 @@ +export const TokenAbi = [ + { + inputs: [ + { internalType: "address", name: "account", type: "address" }, + { internalType: "address", name: "minter_", type: "address" }, + { + internalType: "uint256", + name: "mintingAllowedAfter_", + type: "uint256", + }, + ], + stateMutability: "nonpayable", + type: "constructor", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "owner", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "spender", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "amount", + type: "uint256", + }, + ], + name: "Approval", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "delegator", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "fromDelegate", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "toDelegate", + type: "address", + }, + ], + name: "DelegateChanged", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "delegate", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "previousBalance", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "newBalance", + type: "uint256", + }, + ], + name: "DelegateVotesChanged", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "delegator", + type: "address", + }, + { + indexed: false, + internalType: "address", + name: "delegatee", + type: "address", + }, + ], + name: "GTCDistChanged", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "minter", + type: "address", + }, + { + indexed: false, + internalType: "address", + name: "newMinter", + type: "address", + }, + ], + name: "MinterChanged", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "address", name: "from", type: "address" }, + { indexed: true, internalType: "address", name: "to", type: "address" }, + { + indexed: false, + internalType: "uint256", + name: "amount", + type: "uint256", + }, + ], + name: "Transfer", + type: "event", + }, + { + inputs: [], + name: "DELEGATION_TYPEHASH", + outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "DOMAIN_TYPEHASH", + outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "GTCDist", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "PERMIT_TYPEHASH", + outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "account", type: "address" }, + { internalType: "address", name: "spender", type: "address" }, + ], + name: "allowance", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "spender", type: "address" }, + { internalType: "uint256", name: "rawAmount", type: "uint256" }, + ], + name: "approve", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "account", type: "address" }], + name: "balanceOf", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "", type: "address" }, + { internalType: "uint32", name: "", type: "uint32" }, + ], + name: "checkpoints", + outputs: [ + { internalType: "uint32", name: "fromBlock", type: "uint32" }, + { internalType: "uint96", name: "votes", type: "uint96" }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "decimals", + outputs: [{ internalType: "uint8", name: "", type: "uint8" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "delegatee", type: "address" }], + name: "delegate", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "delegatee", type: "address" }, + { internalType: "uint256", name: "nonce", type: "uint256" }, + { internalType: "uint256", name: "expiry", type: "uint256" }, + { internalType: "uint8", name: "v", type: "uint8" }, + { internalType: "bytes32", name: "r", type: "bytes32" }, + { internalType: "bytes32", name: "s", type: "bytes32" }, + ], + name: "delegateBySig", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "delegator", type: "address" }, + { internalType: "address", name: "delegatee", type: "address" }, + ], + name: "delegateOnDist", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "", type: "address" }], + name: "delegates", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "account", type: "address" }], + name: "getCurrentVotes", + outputs: [{ internalType: "uint96", name: "", type: "uint96" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "account", type: "address" }, + { internalType: "uint256", name: "blockNumber", type: "uint256" }, + ], + name: "getPriorVotes", + outputs: [{ internalType: "uint96", name: "", type: "uint96" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "minimumTimeBetweenMints", + outputs: [{ internalType: "uint32", name: "", type: "uint32" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "dst", type: "address" }, + { internalType: "uint256", name: "rawAmount", type: "uint256" }, + ], + name: "mint", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "mintCap", + outputs: [{ internalType: "uint8", name: "", type: "uint8" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "minter", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "mintingAllowedAfter", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "name", + outputs: [{ internalType: "string", name: "", type: "string" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "", type: "address" }], + name: "nonces", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "", type: "address" }], + name: "numCheckpoints", + outputs: [{ internalType: "uint32", name: "", type: "uint32" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "owner", type: "address" }, + { internalType: "address", name: "spender", type: "address" }, + { internalType: "uint256", name: "rawAmount", type: "uint256" }, + { internalType: "uint256", name: "deadline", type: "uint256" }, + { internalType: "uint8", name: "v", type: "uint8" }, + { internalType: "bytes32", name: "r", type: "bytes32" }, + { internalType: "bytes32", name: "s", type: "bytes32" }, + ], + name: "permit", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "GTCDist_", type: "address" }], + name: "setGTCDist", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "minter_", type: "address" }], + name: "setMinter", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "symbol", + outputs: [{ internalType: "string", name: "", type: "string" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "totalSupply", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "dst", type: "address" }, + { internalType: "uint256", name: "rawAmount", type: "uint256" }, + ], + name: "transfer", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "src", type: "address" }, + { internalType: "address", name: "dst", type: "address" }, + { internalType: "uint256", name: "rawAmount", type: "uint256" }, + ], + name: "transferFrom", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "nonpayable", + type: "function", + }, +] as const; diff --git a/apps/api/src/clients/gtc/index.ts b/apps/api/src/clients/gtc/index.ts new file mode 100644 index 000000000..d7fc3f151 --- /dev/null +++ b/apps/api/src/clients/gtc/index.ts @@ -0,0 +1,121 @@ +import { + Account, + Address, + Chain, + Client, + fromHex, + toHex, + Transport, +} from "viem"; +import { getBlockNumber, readContract } from "viem/actions"; + +import { DAOClient } from "@/interfaces/client"; +import { GovernorAbi } from "./abi/governor"; +import { GovernorBase } from "../governor.base"; + +export class GTCClient< + TTransport extends Transport = Transport, + TChain extends Chain = Chain, + TAccount extends Account | undefined = Account | undefined, + > + extends GovernorBase + implements DAOClient +{ + private abi: typeof GovernorAbi; + private address: Address; + + constructor(client: Client, address: Address) { + super(client); + this.address = address; + this.abi = GovernorAbi; + } + + getDaoId(): string { + return "GTC"; + } + + async getQuorum(): Promise { + const blockNumber = await getBlockNumber(this.client); + const targetBlock = blockNumber - 10n; + return readContract(this.client, { + abi: this.abi, + address: this.address, + functionName: "quorum", + args: [targetBlock < 0n ? 0n : targetBlock], + }); + } + + async getProposalThreshold(): Promise { + return readContract(this.client, { + abi: this.abi, + address: this.address, + functionName: "proposalThreshold", + }); + } + + async getVotingDelay(): Promise { + return readContract(this.client, { + abi: this.abi, + address: this.address, + functionName: "votingDelay", + }); + } + + async getVotingPeriod(): Promise { + return readContract(this.client, { + abi: this.abi, + address: this.address, + functionName: "votingPeriod", + }); + } + + async getTimelockDelay(): Promise { + const timelockAddress = await readContract(this.client, { + abi: this.abi, + address: this.address, + functionName: "timelock", + }); + return readContract(this.client, { + abi: [ + { + inputs: [], + name: "delay", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, + ], + address: timelockAddress, + functionName: "delay", + }); + } + + async getCurrentBlockNumber(): Promise { + const result = await this.client.request({ + method: "eth_blockNumber", + }); + return fromHex(result, "number"); + } + + async getBlockTime(blockNumber: number): Promise { + const block = await this.client.request({ + method: "eth_getBlockByNumber", + params: [toHex(blockNumber), false], + }); + return block?.timestamp ? fromHex(block.timestamp, "number") : null; + } + + calculateQuorum(votes: { + forVotes: bigint; + againstVotes: bigint; + abstainVotes: bigint; + }): bigint { + return votes.forVotes + votes.abstainVotes; + } +} diff --git a/apps/api/src/clients/index.ts b/apps/api/src/clients/index.ts new file mode 100644 index 000000000..86006d04f --- /dev/null +++ b/apps/api/src/clients/index.ts @@ -0,0 +1,9 @@ +export * from "./ens"; +export * from "./op"; +export * from "./gtc"; +export * from "./nouns"; +export * from "./scr"; +export * from "./comp"; +export * from "./obol"; +export * from "./zk"; +export * from "./uni"; diff --git a/apps/api/src/clients/nouns/abi/auction.ts b/apps/api/src/clients/nouns/abi/auction.ts new file mode 100644 index 000000000..8db33f107 --- /dev/null +++ b/apps/api/src/clients/nouns/abi/auction.ts @@ -0,0 +1,611 @@ +export const AuctionAbi = [ + { + inputs: [ + { + internalType: "contract INounsToken", + name: "_nouns", + type: "address", + }, + { internalType: "address", name: "_weth", type: "address" }, + { internalType: "uint256", name: "_duration", type: "uint256" }, + ], + stateMutability: "nonpayable", + type: "constructor", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "uint256", + name: "nounId", + type: "uint256", + }, + { + indexed: false, + internalType: "address", + name: "sender", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "value", + type: "uint256", + }, + { + indexed: false, + internalType: "bool", + name: "extended", + type: "bool", + }, + ], + name: "AuctionBid", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "uint256", + name: "nounId", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "value", + type: "uint256", + }, + { + indexed: true, + internalType: "uint32", + name: "clientId", + type: "uint32", + }, + ], + name: "AuctionBidWithClientId", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "uint256", + name: "nounId", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "startTime", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "endTime", + type: "uint256", + }, + ], + name: "AuctionCreated", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "uint256", + name: "nounId", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "endTime", + type: "uint256", + }, + ], + name: "AuctionExtended", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "minBidIncrementPercentage", + type: "uint256", + }, + ], + name: "AuctionMinBidIncrementPercentageUpdated", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "reservePrice", + type: "uint256", + }, + ], + name: "AuctionReservePriceUpdated", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "uint256", + name: "nounId", + type: "uint256", + }, + { + indexed: false, + internalType: "address", + name: "winner", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "amount", + type: "uint256", + }, + ], + name: "AuctionSettled", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "uint256", + name: "nounId", + type: "uint256", + }, + { + indexed: true, + internalType: "uint32", + name: "clientId", + type: "uint32", + }, + ], + name: "AuctionSettledWithClientId", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "timeBuffer", + type: "uint256", + }, + ], + name: "AuctionTimeBufferUpdated", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "previousOwner", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "newOwner", + type: "address", + }, + ], + name: "OwnershipTransferred", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "account", + type: "address", + }, + ], + name: "Paused", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "newSanctionsOracle", + type: "address", + }, + ], + name: "SanctionsOracleSet", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "account", + type: "address", + }, + ], + name: "Unpaused", + type: "event", + }, + { + inputs: [], + name: "MAX_TIME_BUFFER", + outputs: [{ internalType: "uint56", name: "", type: "uint56" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "auction", + outputs: [ + { + components: [ + { internalType: "uint96", name: "nounId", type: "uint96" }, + { internalType: "uint128", name: "amount", type: "uint128" }, + { internalType: "uint40", name: "startTime", type: "uint40" }, + { internalType: "uint40", name: "endTime", type: "uint40" }, + { + internalType: "address payable", + name: "bidder", + type: "address", + }, + { internalType: "bool", name: "settled", type: "bool" }, + ], + internalType: "struct INounsAuctionHouseV3.AuctionV2View", + name: "", + type: "tuple", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "auctionStorage", + outputs: [ + { internalType: "uint96", name: "nounId", type: "uint96" }, + { internalType: "uint32", name: "clientId", type: "uint32" }, + { internalType: "uint128", name: "amount", type: "uint128" }, + { internalType: "uint40", name: "startTime", type: "uint40" }, + { internalType: "uint40", name: "endTime", type: "uint40" }, + { internalType: "address payable", name: "bidder", type: "address" }, + { internalType: "bool", name: "settled", type: "bool" }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "nounId", type: "uint256" }], + name: "biddingClient", + outputs: [{ internalType: "uint32", name: "", type: "uint32" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "nounId", type: "uint256" }], + name: "createBid", + outputs: [], + stateMutability: "payable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "nounId", type: "uint256" }, + { internalType: "uint32", name: "clientId", type: "uint32" }, + ], + name: "createBid", + outputs: [], + stateMutability: "payable", + type: "function", + }, + { + inputs: [], + name: "duration", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "auctionCount", type: "uint256" }, + ], + name: "getPrices", + outputs: [{ internalType: "uint256[]", name: "prices", type: "uint256[]" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "auctionCount", type: "uint256" }, + { internalType: "bool", name: "skipEmptyValues", type: "bool" }, + ], + name: "getSettlements", + outputs: [ + { + components: [ + { internalType: "uint32", name: "blockTimestamp", type: "uint32" }, + { internalType: "uint256", name: "amount", type: "uint256" }, + { internalType: "address", name: "winner", type: "address" }, + { internalType: "uint256", name: "nounId", type: "uint256" }, + { internalType: "uint32", name: "clientId", type: "uint32" }, + ], + internalType: "struct INounsAuctionHouseV3.Settlement[]", + name: "settlements", + type: "tuple[]", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "startId", type: "uint256" }, + { internalType: "uint256", name: "endId", type: "uint256" }, + { internalType: "bool", name: "skipEmptyValues", type: "bool" }, + ], + name: "getSettlements", + outputs: [ + { + components: [ + { internalType: "uint32", name: "blockTimestamp", type: "uint32" }, + { internalType: "uint256", name: "amount", type: "uint256" }, + { internalType: "address", name: "winner", type: "address" }, + { internalType: "uint256", name: "nounId", type: "uint256" }, + { internalType: "uint32", name: "clientId", type: "uint32" }, + ], + internalType: "struct INounsAuctionHouseV3.Settlement[]", + name: "settlements", + type: "tuple[]", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "startId", type: "uint256" }, + { internalType: "uint256", name: "endTimestamp", type: "uint256" }, + { internalType: "bool", name: "skipEmptyValues", type: "bool" }, + ], + name: "getSettlementsFromIdtoTimestamp", + outputs: [ + { + components: [ + { internalType: "uint32", name: "blockTimestamp", type: "uint32" }, + { internalType: "uint256", name: "amount", type: "uint256" }, + { internalType: "address", name: "winner", type: "address" }, + { internalType: "uint256", name: "nounId", type: "uint256" }, + { internalType: "uint32", name: "clientId", type: "uint32" }, + ], + internalType: "struct INounsAuctionHouseV3.Settlement[]", + name: "settlements", + type: "tuple[]", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "uint192", name: "_reservePrice", type: "uint192" }, + { internalType: "uint56", name: "_timeBuffer", type: "uint56" }, + { + internalType: "uint8", + name: "_minBidIncrementPercentage", + type: "uint8", + }, + { + internalType: "contract IChainalysisSanctionsList", + name: "_sanctionsOracle", + type: "address", + }, + ], + name: "initialize", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "minBidIncrementPercentage", + outputs: [{ internalType: "uint8", name: "", type: "uint8" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "nouns", + outputs: [ + { internalType: "contract INounsToken", name: "", type: "address" }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "owner", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "pause", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "paused", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "renounceOwnership", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "reservePrice", + outputs: [{ internalType: "uint192", name: "", type: "uint192" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "sanctionsOracle", + outputs: [ + { + internalType: "contract IChainalysisSanctionsList", + name: "", + type: "address", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "uint8", + name: "_minBidIncrementPercentage", + type: "uint8", + }, + ], + name: "setMinBidIncrementPercentage", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + components: [ + { internalType: "uint32", name: "blockTimestamp", type: "uint32" }, + { internalType: "uint256", name: "amount", type: "uint256" }, + { internalType: "address", name: "winner", type: "address" }, + { internalType: "uint256", name: "nounId", type: "uint256" }, + ], + internalType: "struct INounsAuctionHouseV3.SettlementNoClientId[]", + name: "settlements", + type: "tuple[]", + }, + ], + name: "setPrices", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint192", name: "_reservePrice", type: "uint192" }, + ], + name: "setReservePrice", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "newSanctionsOracle", + type: "address", + }, + ], + name: "setSanctionsOracle", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "uint56", name: "_timeBuffer", type: "uint56" }], + name: "setTimeBuffer", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "settleAuction", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "settleCurrentAndCreateNewAuction", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "timeBuffer", + outputs: [{ internalType: "uint56", name: "", type: "uint56" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "newOwner", type: "address" }], + name: "transferOwnership", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "unpause", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "startId", type: "uint256" }, + { internalType: "uint256", name: "endId", type: "uint256" }, + ], + name: "warmUpSettlementState", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "weth", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, +] as const; diff --git a/apps/api/src/clients/nouns/abi/governor.ts b/apps/api/src/clients/nouns/abi/governor.ts new file mode 100644 index 000000000..933ae3775 --- /dev/null +++ b/apps/api/src/clients/nouns/abi/governor.ts @@ -0,0 +1,1936 @@ +export const GovernorAbi = [ + { inputs: [], name: "AdminOnly", type: "error" }, + { inputs: [], name: "CanOnlyInitializeOnce", type: "error" }, + { inputs: [], name: "InvalidNounsAddress", type: "error" }, + { inputs: [], name: "InvalidTimelockAddress", type: "error" }, + { inputs: [], name: "MustProvideActions", type: "error" }, + { inputs: [], name: "ProposalInfoArityMismatch", type: "error" }, + { inputs: [], name: "ProposerAlreadyHasALiveProposal", type: "error" }, + { inputs: [], name: "TooManyActions", type: "error" }, + { inputs: [], name: "UnsafeUint16Cast", type: "error" }, + { inputs: [], name: "VotesBelowProposalThreshold", type: "error" }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "numTokens", + type: "uint256", + }, + { indexed: false, internalType: "address", name: "to", type: "address" }, + ], + name: "DAONounsSupplyIncreasedFromEscrow", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256[]", + name: "tokenIds", + type: "uint256[]", + }, + { indexed: false, internalType: "address", name: "to", type: "address" }, + ], + name: "DAOWithdrawNounsFromEscrow", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address[]", + name: "oldErc20Tokens", + type: "address[]", + }, + { + indexed: false, + internalType: "address[]", + name: "newErc20tokens", + type: "address[]", + }, + ], + name: "ERC20TokensToIncludeInForkSet", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "uint32", name: "forkId", type: "uint32" }, + { + indexed: true, + internalType: "address", + name: "owner", + type: "address", + }, + { + indexed: false, + internalType: "uint256[]", + name: "tokenIds", + type: "uint256[]", + }, + { + indexed: false, + internalType: "uint256[]", + name: "proposalIds", + type: "uint256[]", + }, + { + indexed: false, + internalType: "string", + name: "reason", + type: "string", + }, + ], + name: "EscrowedToFork", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "uint32", name: "forkId", type: "uint32" }, + { + indexed: false, + internalType: "address", + name: "forkTreasury", + type: "address", + }, + { + indexed: false, + internalType: "address", + name: "forkToken", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "forkEndTimestamp", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "tokensInEscrow", + type: "uint256", + }, + ], + name: "ExecuteFork", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "oldForkDAODeployer", + type: "address", + }, + { + indexed: false, + internalType: "address", + name: "newForkDAODeployer", + type: "address", + }, + ], + name: "ForkDAODeployerSet", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "oldForkPeriod", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "newForkPeriod", + type: "uint256", + }, + ], + name: "ForkPeriodSet", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "oldForkThreshold", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "newForkThreshold", + type: "uint256", + }, + ], + name: "ForkThresholdSet", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "uint32", name: "forkId", type: "uint32" }, + { + indexed: true, + internalType: "address", + name: "owner", + type: "address", + }, + { + indexed: false, + internalType: "uint256[]", + name: "tokenIds", + type: "uint256[]", + }, + { + indexed: false, + internalType: "uint256[]", + name: "proposalIds", + type: "uint256[]", + }, + { + indexed: false, + internalType: "string", + name: "reason", + type: "string", + }, + ], + name: "JoinFork", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint32", + name: "oldLastMinuteWindowInBlocks", + type: "uint32", + }, + { + indexed: false, + internalType: "uint32", + name: "newLastMinuteWindowInBlocks", + type: "uint32", + }, + ], + name: "LastMinuteWindowSet", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint16", + name: "oldMaxQuorumVotesBPS", + type: "uint16", + }, + { + indexed: false, + internalType: "uint16", + name: "newMaxQuorumVotesBPS", + type: "uint16", + }, + ], + name: "MaxQuorumVotesBPSSet", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint16", + name: "oldMinQuorumVotesBPS", + type: "uint16", + }, + { + indexed: false, + internalType: "uint16", + name: "newMinQuorumVotesBPS", + type: "uint16", + }, + ], + name: "MinQuorumVotesBPSSet", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "oldAdmin", + type: "address", + }, + { + indexed: false, + internalType: "address", + name: "newAdmin", + type: "address", + }, + ], + name: "NewAdmin", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "oldPendingAdmin", + type: "address", + }, + { + indexed: false, + internalType: "address", + name: "newPendingAdmin", + type: "address", + }, + ], + name: "NewPendingAdmin", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "oldPendingVetoer", + type: "address", + }, + { + indexed: false, + internalType: "address", + name: "newPendingVetoer", + type: "address", + }, + ], + name: "NewPendingVetoer", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "oldVetoer", + type: "address", + }, + { + indexed: false, + internalType: "address", + name: "newVetoer", + type: "address", + }, + ], + name: "NewVetoer", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint32", + name: "oldObjectionPeriodDurationInBlocks", + type: "uint32", + }, + { + indexed: false, + internalType: "uint32", + name: "newObjectionPeriodDurationInBlocks", + type: "uint32", + }, + ], + name: "ObjectionPeriodDurationSet", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: false, internalType: "uint256", name: "id", type: "uint256" }, + ], + name: "ProposalCanceled", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: false, internalType: "uint256", name: "id", type: "uint256" }, + { + indexed: false, + internalType: "address", + name: "proposer", + type: "address", + }, + { + indexed: false, + internalType: "address[]", + name: "targets", + type: "address[]", + }, + { + indexed: false, + internalType: "uint256[]", + name: "values", + type: "uint256[]", + }, + { + indexed: false, + internalType: "string[]", + name: "signatures", + type: "string[]", + }, + { + indexed: false, + internalType: "bytes[]", + name: "calldatas", + type: "bytes[]", + }, + { + indexed: false, + internalType: "uint256", + name: "startBlock", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "endBlock", + type: "uint256", + }, + { + indexed: false, + internalType: "string", + name: "description", + type: "string", + }, + ], + name: "ProposalCreated", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: false, internalType: "uint256", name: "id", type: "uint256" }, + ], + name: "ProposalCreatedOnTimelockV1", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: false, internalType: "uint256", name: "id", type: "uint256" }, + { + indexed: false, + internalType: "address", + name: "proposer", + type: "address", + }, + { + indexed: false, + internalType: "address[]", + name: "targets", + type: "address[]", + }, + { + indexed: false, + internalType: "uint256[]", + name: "values", + type: "uint256[]", + }, + { + indexed: false, + internalType: "string[]", + name: "signatures", + type: "string[]", + }, + { + indexed: false, + internalType: "bytes[]", + name: "calldatas", + type: "bytes[]", + }, + { + indexed: false, + internalType: "uint256", + name: "startBlock", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "endBlock", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "proposalThreshold", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "quorumVotes", + type: "uint256", + }, + { + indexed: false, + internalType: "string", + name: "description", + type: "string", + }, + ], + name: "ProposalCreatedWithRequirements", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: false, internalType: "uint256", name: "id", type: "uint256" }, + { + indexed: false, + internalType: "address[]", + name: "signers", + type: "address[]", + }, + { + indexed: false, + internalType: "uint256", + name: "updatePeriodEndBlock", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "proposalThreshold", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "quorumVotes", + type: "uint256", + }, + { + indexed: true, + internalType: "uint32", + name: "clientId", + type: "uint32", + }, + ], + name: "ProposalCreatedWithRequirements", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "uint256", name: "id", type: "uint256" }, + { + indexed: true, + internalType: "address", + name: "proposer", + type: "address", + }, + { + indexed: false, + internalType: "string", + name: "description", + type: "string", + }, + { + indexed: false, + internalType: "string", + name: "updateMessage", + type: "string", + }, + ], + name: "ProposalDescriptionUpdated", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: false, internalType: "uint256", name: "id", type: "uint256" }, + ], + name: "ProposalExecuted", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "uint256", name: "id", type: "uint256" }, + { + indexed: false, + internalType: "uint256", + name: "objectionPeriodEndBlock", + type: "uint256", + }, + ], + name: "ProposalObjectionPeriodSet", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: false, internalType: "uint256", name: "id", type: "uint256" }, + { indexed: false, internalType: "uint256", name: "eta", type: "uint256" }, + ], + name: "ProposalQueued", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "oldProposalThresholdBPS", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "newProposalThresholdBPS", + type: "uint256", + }, + ], + name: "ProposalThresholdBPSSet", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "uint256", name: "id", type: "uint256" }, + { + indexed: true, + internalType: "address", + name: "proposer", + type: "address", + }, + { + indexed: false, + internalType: "address[]", + name: "targets", + type: "address[]", + }, + { + indexed: false, + internalType: "uint256[]", + name: "values", + type: "uint256[]", + }, + { + indexed: false, + internalType: "string[]", + name: "signatures", + type: "string[]", + }, + { + indexed: false, + internalType: "bytes[]", + name: "calldatas", + type: "bytes[]", + }, + { + indexed: false, + internalType: "string", + name: "updateMessage", + type: "string", + }, + ], + name: "ProposalTransactionsUpdated", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint32", + name: "oldProposalUpdatablePeriodInBlocks", + type: "uint32", + }, + { + indexed: false, + internalType: "uint32", + name: "newProposalUpdatablePeriodInBlocks", + type: "uint32", + }, + ], + name: "ProposalUpdatablePeriodSet", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "uint256", name: "id", type: "uint256" }, + { + indexed: true, + internalType: "address", + name: "proposer", + type: "address", + }, + { + indexed: false, + internalType: "address[]", + name: "targets", + type: "address[]", + }, + { + indexed: false, + internalType: "uint256[]", + name: "values", + type: "uint256[]", + }, + { + indexed: false, + internalType: "string[]", + name: "signatures", + type: "string[]", + }, + { + indexed: false, + internalType: "bytes[]", + name: "calldatas", + type: "bytes[]", + }, + { + indexed: false, + internalType: "string", + name: "description", + type: "string", + }, + { + indexed: false, + internalType: "string", + name: "updateMessage", + type: "string", + }, + ], + name: "ProposalUpdated", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: false, internalType: "uint256", name: "id", type: "uint256" }, + ], + name: "ProposalVetoed", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint32", + name: "oldQuorumCoefficient", + type: "uint32", + }, + { + indexed: false, + internalType: "uint32", + name: "newQuorumCoefficient", + type: "uint32", + }, + ], + name: "QuorumCoefficientSet", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "oldQuorumVotesBPS", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "newQuorumVotesBPS", + type: "uint256", + }, + ], + name: "QuorumVotesBPSSet", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "voter", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "refundAmount", + type: "uint256", + }, + { + indexed: false, + internalType: "bool", + name: "refundSent", + type: "bool", + }, + ], + name: "RefundableVote", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "signer", + type: "address", + }, + { indexed: false, internalType: "bytes", name: "sig", type: "bytes" }, + ], + name: "SignatureCancelled", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "timelock", + type: "address", + }, + { + indexed: false, + internalType: "address", + name: "timelockV1", + type: "address", + }, + { + indexed: false, + internalType: "address", + name: "admin", + type: "address", + }, + ], + name: "TimelocksAndAdminSet", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "voter", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "proposalId", + type: "uint256", + }, + { indexed: false, internalType: "uint8", name: "support", type: "uint8" }, + { + indexed: false, + internalType: "uint256", + name: "votes", + type: "uint256", + }, + { + indexed: false, + internalType: "string", + name: "reason", + type: "string", + }, + ], + name: "VoteCast", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "voter", + type: "address", + }, + { + indexed: true, + internalType: "uint256", + name: "proposalId", + type: "uint256", + }, + { + indexed: true, + internalType: "uint32", + name: "clientId", + type: "uint32", + }, + ], + name: "VoteCastWithClientId", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "oldVotingDelay", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "newVotingDelay", + type: "uint256", + }, + ], + name: "VotingDelaySet", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "oldVotingPeriod", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "newVotingPeriod", + type: "uint256", + }, + ], + name: "VotingPeriodSet", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "amount", + type: "uint256", + }, + { indexed: false, internalType: "bool", name: "sent", type: "bool" }, + ], + name: "Withdraw", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "uint32", name: "forkId", type: "uint32" }, + { + indexed: true, + internalType: "address", + name: "owner", + type: "address", + }, + { + indexed: false, + internalType: "uint256[]", + name: "tokenIds", + type: "uint256[]", + }, + ], + name: "WithdrawFromForkEscrow", + type: "event", + }, + { stateMutability: "payable", type: "fallback" }, + { + inputs: [], + name: "MAX_PROPOSAL_THRESHOLD_BPS", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "pure", + type: "function", + }, + { + inputs: [], + name: "MAX_VOTING_DELAY", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "pure", + type: "function", + }, + { + inputs: [], + name: "MAX_VOTING_PERIOD", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "pure", + type: "function", + }, + { + inputs: [], + name: "MIN_PROPOSAL_THRESHOLD_BPS", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "pure", + type: "function", + }, + { + inputs: [], + name: "MIN_VOTING_DELAY", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "pure", + type: "function", + }, + { + inputs: [], + name: "MIN_VOTING_PERIOD", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "pure", + type: "function", + }, + { + inputs: [], + name: "adjustedTotalSupply", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "admin", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + name: "cancel", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "bytes", name: "sig", type: "bytes" }], + name: "cancelSig", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "uint8", name: "support", type: "uint8" }, + ], + name: "castRefundableVote", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "uint8", name: "support", type: "uint8" }, + { internalType: "uint32", name: "clientId", type: "uint32" }, + ], + name: "castRefundableVote", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "uint8", name: "support", type: "uint8" }, + { internalType: "string", name: "reason", type: "string" }, + ], + name: "castRefundableVoteWithReason", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "uint8", name: "support", type: "uint8" }, + { internalType: "string", name: "reason", type: "string" }, + { internalType: "uint32", name: "clientId", type: "uint32" }, + ], + name: "castRefundableVoteWithReason", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "uint8", name: "support", type: "uint8" }, + ], + name: "castVote", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "uint8", name: "support", type: "uint8" }, + { internalType: "uint8", name: "v", type: "uint8" }, + { internalType: "bytes32", name: "r", type: "bytes32" }, + { internalType: "bytes32", name: "s", type: "bytes32" }, + ], + name: "castVoteBySig", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "uint8", name: "support", type: "uint8" }, + { internalType: "string", name: "reason", type: "string" }, + ], + name: "castVoteWithReason", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "againstVotes", type: "uint256" }, + { + internalType: "uint256", + name: "adjustedTotalSupply_", + type: "uint256", + }, + { + components: [ + { internalType: "uint16", name: "minQuorumVotesBPS", type: "uint16" }, + { internalType: "uint16", name: "maxQuorumVotesBPS", type: "uint16" }, + { internalType: "uint32", name: "quorumCoefficient", type: "uint32" }, + ], + internalType: "struct NounsDAOTypes.DynamicQuorumParams", + name: "params", + type: "tuple", + }, + ], + name: "dynamicQuorumVotes", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "pure", + type: "function", + }, + { + inputs: [], + name: "erc20TokensToIncludeInFork", + outputs: [{ internalType: "address[]", name: "", type: "address[]" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "uint256[]", name: "tokenIds", type: "uint256[]" }, + { internalType: "uint256[]", name: "proposalIds", type: "uint256[]" }, + { internalType: "string", name: "reason", type: "string" }, + ], + name: "escrowToFork", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + name: "execute", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "executeFork", + outputs: [ + { internalType: "address", name: "forkTreasury", type: "address" }, + { internalType: "address", name: "forkToken", type: "address" }, + ], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "forkDAODeployer", + outputs: [ + { internalType: "contract IForkDAODeployer", name: "", type: "address" }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "forkEndTimestamp", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "forkEscrow", + outputs: [ + { + internalType: "contract INounsDAOForkEscrow", + name: "", + type: "address", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "forkPeriod", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "forkThreshold", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "forkThresholdBPS", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + name: "getActions", + outputs: [ + { internalType: "address[]", name: "targets", type: "address[]" }, + { internalType: "uint256[]", name: "values", type: "uint256[]" }, + { internalType: "string[]", name: "signatures", type: "string[]" }, + { internalType: "bytes[]", name: "calldatas", type: "bytes[]" }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "blockNumber_", type: "uint256" }, + ], + name: "getDynamicQuorumParamsAt", + outputs: [ + { + components: [ + { internalType: "uint16", name: "minQuorumVotesBPS", type: "uint16" }, + { internalType: "uint16", name: "maxQuorumVotesBPS", type: "uint16" }, + { internalType: "uint32", name: "quorumCoefficient", type: "uint32" }, + ], + internalType: "struct NounsDAOTypes.DynamicQuorumParams", + name: "", + type: "tuple", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "address", name: "voter", type: "address" }, + ], + name: "getReceipt", + outputs: [ + { + components: [ + { internalType: "bool", name: "hasVoted", type: "bool" }, + { internalType: "uint8", name: "support", type: "uint8" }, + { internalType: "uint96", name: "votes", type: "uint96" }, + ], + internalType: "struct NounsDAOTypes.Receipt", + name: "", + type: "tuple", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "timelock_", type: "address" }, + { internalType: "address", name: "nouns_", type: "address" }, + { internalType: "address", name: "forkEscrow_", type: "address" }, + { internalType: "address", name: "forkDAODeployer_", type: "address" }, + { internalType: "address", name: "vetoer_", type: "address" }, + { + components: [ + { internalType: "uint256", name: "votingPeriod", type: "uint256" }, + { internalType: "uint256", name: "votingDelay", type: "uint256" }, + { + internalType: "uint256", + name: "proposalThresholdBPS", + type: "uint256", + }, + { + internalType: "uint32", + name: "lastMinuteWindowInBlocks", + type: "uint32", + }, + { + internalType: "uint32", + name: "objectionPeriodDurationInBlocks", + type: "uint32", + }, + { + internalType: "uint32", + name: "proposalUpdatablePeriodInBlocks", + type: "uint32", + }, + ], + internalType: "struct NounsDAOTypes.NounsDAOParams", + name: "daoParams_", + type: "tuple", + }, + { + components: [ + { internalType: "uint16", name: "minQuorumVotesBPS", type: "uint16" }, + { internalType: "uint16", name: "maxQuorumVotesBPS", type: "uint16" }, + { internalType: "uint32", name: "quorumCoefficient", type: "uint32" }, + ], + internalType: "struct NounsDAOTypes.DynamicQuorumParams", + name: "dynamicQuorumParams_", + type: "tuple", + }, + ], + name: "initialize", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256[]", name: "tokenIds", type: "uint256[]" }, + { internalType: "uint256[]", name: "proposalIds", type: "uint256[]" }, + { internalType: "string", name: "reason", type: "string" }, + ], + name: "joinFork", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "lastMinuteWindowInBlocks", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "account", type: "address" }], + name: "latestProposalIds", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "maxQuorumVotes", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "minQuorumVotes", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "nouns", + outputs: [ + { internalType: "contract NounsTokenLike", name: "", type: "address" }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "numTokensInForkEscrow", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "objectionPeriodDurationInBlocks", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "pendingVetoer", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "proposalCount", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "firstProposalId", type: "uint256" }, + { internalType: "uint256", name: "lastProposalId", type: "uint256" }, + { + internalType: "uint16", + name: "proposalEligibilityQuorumBps", + type: "uint16", + }, + { internalType: "bool", name: "excludeCanceled", type: "bool" }, + { internalType: "bool", name: "requireVotingEnded", type: "bool" }, + { internalType: "uint32[]", name: "votingClientIds", type: "uint32[]" }, + ], + name: "proposalDataForRewards", + outputs: [ + { + components: [ + { internalType: "uint256", name: "endBlock", type: "uint256" }, + { + internalType: "uint256", + name: "objectionPeriodEndBlock", + type: "uint256", + }, + { internalType: "uint256", name: "forVotes", type: "uint256" }, + { internalType: "uint256", name: "againstVotes", type: "uint256" }, + { internalType: "uint256", name: "abstainVotes", type: "uint256" }, + { internalType: "uint256", name: "totalSupply", type: "uint256" }, + { + internalType: "uint256", + name: "creationTimestamp", + type: "uint256", + }, + { internalType: "uint32", name: "clientId", type: "uint32" }, + { + components: [ + { internalType: "uint32", name: "votes", type: "uint32" }, + { internalType: "uint32", name: "txs", type: "uint32" }, + ], + internalType: "struct NounsDAOTypes.ClientVoteData[]", + name: "voteData", + type: "tuple[]", + }, + ], + internalType: "struct NounsDAOTypes.ProposalForRewards[]", + name: "", + type: "tuple[]", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "proposalMaxOperations", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "pure", + type: "function", + }, + { + inputs: [], + name: "proposalThreshold", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "proposalThresholdBPS", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "proposalUpdatablePeriodInBlocks", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + name: "proposals", + outputs: [ + { + components: [ + { internalType: "uint256", name: "id", type: "uint256" }, + { internalType: "address", name: "proposer", type: "address" }, + { + internalType: "uint256", + name: "proposalThreshold", + type: "uint256", + }, + { internalType: "uint256", name: "quorumVotes", type: "uint256" }, + { internalType: "uint256", name: "eta", type: "uint256" }, + { internalType: "uint256", name: "startBlock", type: "uint256" }, + { internalType: "uint256", name: "endBlock", type: "uint256" }, + { internalType: "uint256", name: "forVotes", type: "uint256" }, + { internalType: "uint256", name: "againstVotes", type: "uint256" }, + { internalType: "uint256", name: "abstainVotes", type: "uint256" }, + { internalType: "bool", name: "canceled", type: "bool" }, + { internalType: "bool", name: "vetoed", type: "bool" }, + { internalType: "bool", name: "executed", type: "bool" }, + { internalType: "uint256", name: "totalSupply", type: "uint256" }, + { internalType: "uint256", name: "creationBlock", type: "uint256" }, + ], + internalType: "struct NounsDAOTypes.ProposalCondensedV2", + name: "", + type: "tuple", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + name: "proposalsV3", + outputs: [ + { + components: [ + { internalType: "uint256", name: "id", type: "uint256" }, + { internalType: "address", name: "proposer", type: "address" }, + { + internalType: "uint256", + name: "proposalThreshold", + type: "uint256", + }, + { internalType: "uint256", name: "quorumVotes", type: "uint256" }, + { internalType: "uint256", name: "eta", type: "uint256" }, + { internalType: "uint256", name: "startBlock", type: "uint256" }, + { internalType: "uint256", name: "endBlock", type: "uint256" }, + { internalType: "uint256", name: "forVotes", type: "uint256" }, + { internalType: "uint256", name: "againstVotes", type: "uint256" }, + { internalType: "uint256", name: "abstainVotes", type: "uint256" }, + { internalType: "bool", name: "canceled", type: "bool" }, + { internalType: "bool", name: "vetoed", type: "bool" }, + { internalType: "bool", name: "executed", type: "bool" }, + { internalType: "uint256", name: "totalSupply", type: "uint256" }, + { internalType: "uint256", name: "creationBlock", type: "uint256" }, + { internalType: "address[]", name: "signers", type: "address[]" }, + { + internalType: "uint256", + name: "updatePeriodEndBlock", + type: "uint256", + }, + { + internalType: "uint256", + name: "objectionPeriodEndBlock", + type: "uint256", + }, + { internalType: "bool", name: "executeOnTimelockV1", type: "bool" }, + ], + internalType: "struct NounsDAOTypes.ProposalCondensedV3", + name: "", + type: "tuple", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address[]", name: "targets", type: "address[]" }, + { internalType: "uint256[]", name: "values", type: "uint256[]" }, + { internalType: "string[]", name: "signatures", type: "string[]" }, + { internalType: "bytes[]", name: "calldatas", type: "bytes[]" }, + { internalType: "string", name: "description", type: "string" }, + { internalType: "uint32", name: "clientId", type: "uint32" }, + ], + name: "propose", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address[]", name: "targets", type: "address[]" }, + { internalType: "uint256[]", name: "values", type: "uint256[]" }, + { internalType: "string[]", name: "signatures", type: "string[]" }, + { internalType: "bytes[]", name: "calldatas", type: "bytes[]" }, + { internalType: "string", name: "description", type: "string" }, + ], + name: "propose", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + components: [ + { internalType: "bytes", name: "sig", type: "bytes" }, + { internalType: "address", name: "signer", type: "address" }, + { + internalType: "uint256", + name: "expirationTimestamp", + type: "uint256", + }, + ], + internalType: "struct NounsDAOTypes.ProposerSignature[]", + name: "proposerSignatures", + type: "tuple[]", + }, + { internalType: "address[]", name: "targets", type: "address[]" }, + { internalType: "uint256[]", name: "values", type: "uint256[]" }, + { internalType: "string[]", name: "signatures", type: "string[]" }, + { internalType: "bytes[]", name: "calldatas", type: "bytes[]" }, + { internalType: "string", name: "description", type: "string" }, + ], + name: "proposeBySigs", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + components: [ + { internalType: "bytes", name: "sig", type: "bytes" }, + { internalType: "address", name: "signer", type: "address" }, + { + internalType: "uint256", + name: "expirationTimestamp", + type: "uint256", + }, + ], + internalType: "struct NounsDAOTypes.ProposerSignature[]", + name: "proposerSignatures", + type: "tuple[]", + }, + { internalType: "address[]", name: "targets", type: "address[]" }, + { internalType: "uint256[]", name: "values", type: "uint256[]" }, + { internalType: "string[]", name: "signatures", type: "string[]" }, + { internalType: "bytes[]", name: "calldatas", type: "bytes[]" }, + { internalType: "string", name: "description", type: "string" }, + { internalType: "uint32", name: "clientId", type: "uint32" }, + ], + name: "proposeBySigs", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address[]", name: "targets", type: "address[]" }, + { internalType: "uint256[]", name: "values", type: "uint256[]" }, + { internalType: "string[]", name: "signatures", type: "string[]" }, + { internalType: "bytes[]", name: "calldatas", type: "bytes[]" }, + { internalType: "string", name: "description", type: "string" }, + ], + name: "proposeOnTimelockV1", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address[]", name: "targets", type: "address[]" }, + { internalType: "uint256[]", name: "values", type: "uint256[]" }, + { internalType: "string[]", name: "signatures", type: "string[]" }, + { internalType: "bytes[]", name: "calldatas", type: "bytes[]" }, + { internalType: "string", name: "description", type: "string" }, + { internalType: "uint32", name: "clientId", type: "uint32" }, + ], + name: "proposeOnTimelockV1", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + name: "queue", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "quorumParamsCheckpoints", + outputs: [ + { + components: [ + { internalType: "uint32", name: "fromBlock", type: "uint32" }, + { + components: [ + { + internalType: "uint16", + name: "minQuorumVotesBPS", + type: "uint16", + }, + { + internalType: "uint16", + name: "maxQuorumVotesBPS", + type: "uint16", + }, + { + internalType: "uint32", + name: "quorumCoefficient", + type: "uint32", + }, + ], + internalType: "struct NounsDAOTypes.DynamicQuorumParams", + name: "params", + type: "tuple", + }, + ], + internalType: "struct NounsDAOTypes.DynamicQuorumParamsCheckpoint[]", + name: "", + type: "tuple[]", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "index", type: "uint256" }], + name: "quorumParamsCheckpoints", + outputs: [ + { + components: [ + { internalType: "uint32", name: "fromBlock", type: "uint32" }, + { + components: [ + { + internalType: "uint16", + name: "minQuorumVotesBPS", + type: "uint16", + }, + { + internalType: "uint16", + name: "maxQuorumVotesBPS", + type: "uint16", + }, + { + internalType: "uint32", + name: "quorumCoefficient", + type: "uint32", + }, + ], + internalType: "struct NounsDAOTypes.DynamicQuorumParams", + name: "params", + type: "tuple", + }, + ], + internalType: "struct NounsDAOTypes.DynamicQuorumParamsCheckpoint", + name: "", + type: "tuple", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + name: "quorumVotes", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "quorumVotesBPS", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + name: "state", + outputs: [ + { + internalType: "enum NounsDAOTypes.ProposalState", + name: "", + type: "uint8", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "timelock", + outputs: [ + { internalType: "contract INounsDAOExecutor", name: "", type: "address" }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "timelockV1", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "address[]", name: "targets", type: "address[]" }, + { internalType: "uint256[]", name: "values", type: "uint256[]" }, + { internalType: "string[]", name: "signatures", type: "string[]" }, + { internalType: "bytes[]", name: "calldatas", type: "bytes[]" }, + { internalType: "string", name: "description", type: "string" }, + { internalType: "string", name: "updateMessage", type: "string" }, + ], + name: "updateProposal", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { + components: [ + { internalType: "bytes", name: "sig", type: "bytes" }, + { internalType: "address", name: "signer", type: "address" }, + { + internalType: "uint256", + name: "expirationTimestamp", + type: "uint256", + }, + ], + internalType: "struct NounsDAOTypes.ProposerSignature[]", + name: "proposerSignatures", + type: "tuple[]", + }, + { internalType: "address[]", name: "targets", type: "address[]" }, + { internalType: "uint256[]", name: "values", type: "uint256[]" }, + { internalType: "string[]", name: "signatures", type: "string[]" }, + { internalType: "bytes[]", name: "calldatas", type: "bytes[]" }, + { internalType: "string", name: "description", type: "string" }, + { internalType: "string", name: "updateMessage", type: "string" }, + ], + name: "updateProposalBySigs", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "string", name: "description", type: "string" }, + { internalType: "string", name: "updateMessage", type: "string" }, + ], + name: "updateProposalDescription", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "address[]", name: "targets", type: "address[]" }, + { internalType: "uint256[]", name: "values", type: "uint256[]" }, + { internalType: "string[]", name: "signatures", type: "string[]" }, + { internalType: "bytes[]", name: "calldatas", type: "bytes[]" }, + { internalType: "string", name: "updateMessage", type: "string" }, + ], + name: "updateProposalTransactions", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + name: "veto", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "vetoer", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "voteSnapshotBlockSwitchProposalId", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "votingDelay", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "votingPeriod", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "uint256[]", name: "tokenIds", type: "uint256[]" }, + { internalType: "address", name: "to", type: "address" }, + ], + name: "withdrawDAONounsFromEscrowIncreasingTotalSupply", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256[]", name: "tokenIds", type: "uint256[]" }, + ], + name: "withdrawDAONounsFromEscrowToTreasury", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256[]", name: "tokenIds", type: "uint256[]" }, + ], + name: "withdrawFromForkEscrow", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { stateMutability: "payable", type: "receive" }, +] as const; diff --git a/apps/api/src/clients/nouns/abi/index.ts b/apps/api/src/clients/nouns/abi/index.ts new file mode 100644 index 000000000..439f9418c --- /dev/null +++ b/apps/api/src/clients/nouns/abi/index.ts @@ -0,0 +1,4 @@ +export { GovernorAbi } from "./governor"; +export { LegacyGovernorABI } from "./legacyGovernor"; +export { TokenAbi } from "./token"; +export { AuctionAbi } from "./auction"; diff --git a/apps/api/src/clients/nouns/abi/legacyGovernor.ts b/apps/api/src/clients/nouns/abi/legacyGovernor.ts new file mode 100644 index 000000000..21349e3d8 --- /dev/null +++ b/apps/api/src/clients/nouns/abi/legacyGovernor.ts @@ -0,0 +1,2098 @@ +export const LegacyGovernorABI = [ + { inputs: [], name: "AdminOnly", type: "error" }, + { inputs: [], name: "CanOnlyInitializeOnce", type: "error" }, + { inputs: [], name: "InvalidNounsAddress", type: "error" }, + { inputs: [], name: "InvalidTimelockAddress", type: "error" }, + { inputs: [], name: "MustProvideActions", type: "error" }, + { inputs: [], name: "ProposalInfoArityMismatch", type: "error" }, + { inputs: [], name: "ProposerAlreadyHasALiveProposal", type: "error" }, + { inputs: [], name: "TooManyActions", type: "error" }, + { inputs: [], name: "UnsafeUint16Cast", type: "error" }, + { inputs: [], name: "VotesBelowProposalThreshold", type: "error" }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "numTokens", + type: "uint256", + }, + { indexed: false, internalType: "address", name: "to", type: "address" }, + ], + name: "DAONounsSupplyIncreasedFromEscrow", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256[]", + name: "tokenIds", + type: "uint256[]", + }, + { indexed: false, internalType: "address", name: "to", type: "address" }, + ], + name: "DAOWithdrawNounsFromEscrow", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address[]", + name: "oldErc20Tokens", + type: "address[]", + }, + { + indexed: false, + internalType: "address[]", + name: "newErc20tokens", + type: "address[]", + }, + ], + name: "ERC20TokensToIncludeInForkSet", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "uint32", name: "forkId", type: "uint32" }, + { + indexed: true, + internalType: "address", + name: "owner", + type: "address", + }, + { + indexed: false, + internalType: "uint256[]", + name: "tokenIds", + type: "uint256[]", + }, + { + indexed: false, + internalType: "uint256[]", + name: "proposalIds", + type: "uint256[]", + }, + { + indexed: false, + internalType: "string", + name: "reason", + type: "string", + }, + ], + name: "EscrowedToFork", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "uint32", name: "forkId", type: "uint32" }, + { + indexed: false, + internalType: "address", + name: "forkTreasury", + type: "address", + }, + { + indexed: false, + internalType: "address", + name: "forkToken", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "forkEndTimestamp", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "tokensInEscrow", + type: "uint256", + }, + ], + name: "ExecuteFork", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "oldForkDAODeployer", + type: "address", + }, + { + indexed: false, + internalType: "address", + name: "newForkDAODeployer", + type: "address", + }, + ], + name: "ForkDAODeployerSet", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "oldForkPeriod", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "newForkPeriod", + type: "uint256", + }, + ], + name: "ForkPeriodSet", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "oldForkThreshold", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "newForkThreshold", + type: "uint256", + }, + ], + name: "ForkThresholdSet", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "uint32", name: "forkId", type: "uint32" }, + { + indexed: true, + internalType: "address", + name: "owner", + type: "address", + }, + { + indexed: false, + internalType: "uint256[]", + name: "tokenIds", + type: "uint256[]", + }, + { + indexed: false, + internalType: "uint256[]", + name: "proposalIds", + type: "uint256[]", + }, + { + indexed: false, + internalType: "string", + name: "reason", + type: "string", + }, + ], + name: "JoinFork", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint32", + name: "oldLastMinuteWindowInBlocks", + type: "uint32", + }, + { + indexed: false, + internalType: "uint32", + name: "newLastMinuteWindowInBlocks", + type: "uint32", + }, + ], + name: "LastMinuteWindowSet", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint16", + name: "oldMaxQuorumVotesBPS", + type: "uint16", + }, + { + indexed: false, + internalType: "uint16", + name: "newMaxQuorumVotesBPS", + type: "uint16", + }, + ], + name: "MaxQuorumVotesBPSSet", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint16", + name: "oldMinQuorumVotesBPS", + type: "uint16", + }, + { + indexed: false, + internalType: "uint16", + name: "newMinQuorumVotesBPS", + type: "uint16", + }, + ], + name: "MinQuorumVotesBPSSet", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "oldAdmin", + type: "address", + }, + { + indexed: false, + internalType: "address", + name: "newAdmin", + type: "address", + }, + ], + name: "NewAdmin", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "oldImplementation", + type: "address", + }, + { + indexed: false, + internalType: "address", + name: "newImplementation", + type: "address", + }, + ], + name: "NewImplementation", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "oldPendingAdmin", + type: "address", + }, + { + indexed: false, + internalType: "address", + name: "newPendingAdmin", + type: "address", + }, + ], + name: "NewPendingAdmin", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "oldPendingVetoer", + type: "address", + }, + { + indexed: false, + internalType: "address", + name: "newPendingVetoer", + type: "address", + }, + ], + name: "NewPendingVetoer", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "oldVetoer", + type: "address", + }, + { + indexed: false, + internalType: "address", + name: "newVetoer", + type: "address", + }, + ], + name: "NewVetoer", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint32", + name: "oldObjectionPeriodDurationInBlocks", + type: "uint32", + }, + { + indexed: false, + internalType: "uint32", + name: "newObjectionPeriodDurationInBlocks", + type: "uint32", + }, + ], + name: "ObjectionPeriodDurationSet", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: false, internalType: "uint256", name: "id", type: "uint256" }, + ], + name: "ProposalCanceled", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: false, internalType: "uint256", name: "id", type: "uint256" }, + { + indexed: false, + internalType: "address", + name: "proposer", + type: "address", + }, + { + indexed: false, + internalType: "address[]", + name: "targets", + type: "address[]", + }, + { + indexed: false, + internalType: "uint256[]", + name: "values", + type: "uint256[]", + }, + { + indexed: false, + internalType: "string[]", + name: "signatures", + type: "string[]", + }, + { + indexed: false, + internalType: "bytes[]", + name: "calldatas", + type: "bytes[]", + }, + { + indexed: false, + internalType: "uint256", + name: "startBlock", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "endBlock", + type: "uint256", + }, + { + indexed: false, + internalType: "string", + name: "description", + type: "string", + }, + ], + name: "ProposalCreated", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: false, internalType: "uint256", name: "id", type: "uint256" }, + ], + name: "ProposalCreatedOnTimelockV1", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: false, internalType: "uint256", name: "id", type: "uint256" }, + { + indexed: false, + internalType: "address", + name: "proposer", + type: "address", + }, + { + indexed: false, + internalType: "address[]", + name: "signers", + type: "address[]", + }, + { + indexed: false, + internalType: "address[]", + name: "targets", + type: "address[]", + }, + { + indexed: false, + internalType: "uint256[]", + name: "values", + type: "uint256[]", + }, + { + indexed: false, + internalType: "string[]", + name: "signatures", + type: "string[]", + }, + { + indexed: false, + internalType: "bytes[]", + name: "calldatas", + type: "bytes[]", + }, + { + indexed: false, + internalType: "uint256", + name: "startBlock", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "endBlock", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "updatePeriodEndBlock", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "proposalThreshold", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "quorumVotes", + type: "uint256", + }, + { + indexed: false, + internalType: "string", + name: "description", + type: "string", + }, + ], + name: "ProposalCreatedWithRequirements", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: false, internalType: "uint256", name: "id", type: "uint256" }, + { + indexed: false, + internalType: "address", + name: "proposer", + type: "address", + }, + { + indexed: false, + internalType: "address[]", + name: "targets", + type: "address[]", + }, + { + indexed: false, + internalType: "uint256[]", + name: "values", + type: "uint256[]", + }, + { + indexed: false, + internalType: "string[]", + name: "signatures", + type: "string[]", + }, + { + indexed: false, + internalType: "bytes[]", + name: "calldatas", + type: "bytes[]", + }, + { + indexed: false, + internalType: "uint256", + name: "startBlock", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "endBlock", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "proposalThreshold", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "quorumVotes", + type: "uint256", + }, + { + indexed: false, + internalType: "string", + name: "description", + type: "string", + }, + ], + name: "ProposalCreatedWithRequirements", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "uint256", name: "id", type: "uint256" }, + { + indexed: true, + internalType: "address", + name: "proposer", + type: "address", + }, + { + indexed: false, + internalType: "string", + name: "description", + type: "string", + }, + { + indexed: false, + internalType: "string", + name: "updateMessage", + type: "string", + }, + ], + name: "ProposalDescriptionUpdated", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: false, internalType: "uint256", name: "id", type: "uint256" }, + ], + name: "ProposalExecuted", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "uint256", name: "id", type: "uint256" }, + { + indexed: false, + internalType: "uint256", + name: "objectionPeriodEndBlock", + type: "uint256", + }, + ], + name: "ProposalObjectionPeriodSet", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: false, internalType: "uint256", name: "id", type: "uint256" }, + { indexed: false, internalType: "uint256", name: "eta", type: "uint256" }, + ], + name: "ProposalQueued", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "oldProposalThresholdBPS", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "newProposalThresholdBPS", + type: "uint256", + }, + ], + name: "ProposalThresholdBPSSet", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "uint256", name: "id", type: "uint256" }, + { + indexed: true, + internalType: "address", + name: "proposer", + type: "address", + }, + { + indexed: false, + internalType: "address[]", + name: "targets", + type: "address[]", + }, + { + indexed: false, + internalType: "uint256[]", + name: "values", + type: "uint256[]", + }, + { + indexed: false, + internalType: "string[]", + name: "signatures", + type: "string[]", + }, + { + indexed: false, + internalType: "bytes[]", + name: "calldatas", + type: "bytes[]", + }, + { + indexed: false, + internalType: "string", + name: "updateMessage", + type: "string", + }, + ], + name: "ProposalTransactionsUpdated", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint32", + name: "oldProposalUpdatablePeriodInBlocks", + type: "uint32", + }, + { + indexed: false, + internalType: "uint32", + name: "newProposalUpdatablePeriodInBlocks", + type: "uint32", + }, + ], + name: "ProposalUpdatablePeriodSet", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "uint256", name: "id", type: "uint256" }, + { + indexed: true, + internalType: "address", + name: "proposer", + type: "address", + }, + { + indexed: false, + internalType: "address[]", + name: "targets", + type: "address[]", + }, + { + indexed: false, + internalType: "uint256[]", + name: "values", + type: "uint256[]", + }, + { + indexed: false, + internalType: "string[]", + name: "signatures", + type: "string[]", + }, + { + indexed: false, + internalType: "bytes[]", + name: "calldatas", + type: "bytes[]", + }, + { + indexed: false, + internalType: "string", + name: "description", + type: "string", + }, + { + indexed: false, + internalType: "string", + name: "updateMessage", + type: "string", + }, + ], + name: "ProposalUpdated", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: false, internalType: "uint256", name: "id", type: "uint256" }, + ], + name: "ProposalVetoed", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint32", + name: "oldQuorumCoefficient", + type: "uint32", + }, + { + indexed: false, + internalType: "uint32", + name: "newQuorumCoefficient", + type: "uint32", + }, + ], + name: "QuorumCoefficientSet", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "oldQuorumVotesBPS", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "newQuorumVotesBPS", + type: "uint256", + }, + ], + name: "QuorumVotesBPSSet", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "voter", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "refundAmount", + type: "uint256", + }, + { + indexed: false, + internalType: "bool", + name: "refundSent", + type: "bool", + }, + ], + name: "RefundableVote", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "signer", + type: "address", + }, + { indexed: false, internalType: "bytes", name: "sig", type: "bytes" }, + ], + name: "SignatureCancelled", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "timelock", + type: "address", + }, + { + indexed: false, + internalType: "address", + name: "timelockV1", + type: "address", + }, + { + indexed: false, + internalType: "address", + name: "admin", + type: "address", + }, + ], + name: "TimelocksAndAdminSet", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "voter", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "proposalId", + type: "uint256", + }, + { indexed: false, internalType: "uint8", name: "support", type: "uint8" }, + { + indexed: false, + internalType: "uint256", + name: "votes", + type: "uint256", + }, + { + indexed: false, + internalType: "string", + name: "reason", + type: "string", + }, + ], + name: "VoteCast", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "oldVoteSnapshotBlockSwitchProposalId", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "newVoteSnapshotBlockSwitchProposalId", + type: "uint256", + }, + ], + name: "VoteSnapshotBlockSwitchProposalIdSet", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "oldVotingDelay", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "newVotingDelay", + type: "uint256", + }, + ], + name: "VotingDelaySet", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "oldVotingPeriod", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "newVotingPeriod", + type: "uint256", + }, + ], + name: "VotingPeriodSet", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "amount", + type: "uint256", + }, + { indexed: false, internalType: "bool", name: "sent", type: "bool" }, + ], + name: "Withdraw", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "uint32", name: "forkId", type: "uint32" }, + { + indexed: true, + internalType: "address", + name: "owner", + type: "address", + }, + { + indexed: false, + internalType: "uint256[]", + name: "tokenIds", + type: "uint256[]", + }, + ], + name: "WithdrawFromForkEscrow", + type: "event", + }, + { + inputs: [], + name: "MAX_PROPOSAL_THRESHOLD_BPS", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "pure", + type: "function", + }, + { + inputs: [], + name: "MAX_VOTING_DELAY", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "pure", + type: "function", + }, + { + inputs: [], + name: "MAX_VOTING_PERIOD", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "pure", + type: "function", + }, + { + inputs: [], + name: "MIN_PROPOSAL_THRESHOLD_BPS", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "pure", + type: "function", + }, + { + inputs: [], + name: "MIN_VOTING_DELAY", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "pure", + type: "function", + }, + { + inputs: [], + name: "MIN_VOTING_PERIOD", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "pure", + type: "function", + }, + { + inputs: [], + name: "_acceptAdmin", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "_acceptVetoer", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "_burnVetoPower", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint16", name: "newMinQuorumVotesBPS", type: "uint16" }, + { internalType: "uint16", name: "newMaxQuorumVotesBPS", type: "uint16" }, + { internalType: "uint32", name: "newQuorumCoefficient", type: "uint32" }, + ], + name: "_setDynamicQuorumParams", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address[]", name: "erc20tokens", type: "address[]" }, + ], + name: "_setErc20TokensToIncludeInFork", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "newForkDAODeployer", type: "address" }, + ], + name: "_setForkDAODeployer", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "newForkEscrow", type: "address" }, + ], + name: "_setForkEscrow", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "forkEscrow_", type: "address" }, + { internalType: "address", name: "forkDAODeployer_", type: "address" }, + { + internalType: "address[]", + name: "erc20TokensToIncludeInFork_", + type: "address[]", + }, + { internalType: "uint256", name: "forkPeriod_", type: "uint256" }, + { internalType: "uint256", name: "forkThresholdBPS_", type: "uint256" }, + ], + name: "_setForkParams", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "newForkPeriod", type: "uint256" }, + ], + name: "_setForkPeriod", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "newForkThresholdBPS", type: "uint256" }, + ], + name: "_setForkThresholdBPS", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "uint32", + name: "newLastMinuteWindowInBlocks", + type: "uint32", + }, + ], + name: "_setLastMinuteWindowInBlocks", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint16", name: "newMaxQuorumVotesBPS", type: "uint16" }, + ], + name: "_setMaxQuorumVotesBPS", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint16", name: "newMinQuorumVotesBPS", type: "uint16" }, + ], + name: "_setMinQuorumVotesBPS", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "uint32", + name: "newObjectionPeriodDurationInBlocks", + type: "uint32", + }, + ], + name: "_setObjectionPeriodDurationInBlocks", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "newPendingAdmin", type: "address" }, + ], + name: "_setPendingAdmin", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "newPendingVetoer", type: "address" }, + ], + name: "_setPendingVetoer", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "uint256", + name: "newProposalThresholdBPS", + type: "uint256", + }, + ], + name: "_setProposalThresholdBPS", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "uint32", + name: "newProposalUpdatablePeriodInBlocks", + type: "uint32", + }, + ], + name: "_setProposalUpdatablePeriodInBlocks", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint32", name: "newQuorumCoefficient", type: "uint32" }, + ], + name: "_setQuorumCoefficient", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "newTimelock", type: "address" }, + { internalType: "address", name: "newTimelockV1", type: "address" }, + { internalType: "address", name: "newAdmin", type: "address" }, + ], + name: "_setTimelocksAndAdmin", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "_setVoteSnapshotBlockSwitchProposalId", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "newVotingDelay", type: "uint256" }, + ], + name: "_setVotingDelay", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "newVotingPeriod", type: "uint256" }, + ], + name: "_setVotingPeriod", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "_withdraw", + outputs: [ + { internalType: "uint256", name: "", type: "uint256" }, + { internalType: "bool", name: "", type: "bool" }, + ], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "adjustedTotalSupply", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + name: "cancel", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "bytes", name: "sig", type: "bytes" }], + name: "cancelSig", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "uint8", name: "support", type: "uint8" }, + ], + name: "castRefundableVote", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "uint8", name: "support", type: "uint8" }, + { internalType: "string", name: "reason", type: "string" }, + ], + name: "castRefundableVoteWithReason", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "uint8", name: "support", type: "uint8" }, + ], + name: "castVote", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "uint8", name: "support", type: "uint8" }, + { internalType: "uint8", name: "v", type: "uint8" }, + { internalType: "bytes32", name: "r", type: "bytes32" }, + { internalType: "bytes32", name: "s", type: "bytes32" }, + ], + name: "castVoteBySig", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "uint8", name: "support", type: "uint8" }, + { internalType: "string", name: "reason", type: "string" }, + ], + name: "castVoteWithReason", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "againstVotes", type: "uint256" }, + { + internalType: "uint256", + name: "adjustedTotalSupply_", + type: "uint256", + }, + { + components: [ + { internalType: "uint16", name: "minQuorumVotesBPS", type: "uint16" }, + { internalType: "uint16", name: "maxQuorumVotesBPS", type: "uint16" }, + { internalType: "uint32", name: "quorumCoefficient", type: "uint32" }, + ], + internalType: "struct NounsDAOStorageV3.DynamicQuorumParams", + name: "params", + type: "tuple", + }, + ], + name: "dynamicQuorumVotes", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "pure", + type: "function", + }, + { + inputs: [], + name: "erc20TokensToIncludeInFork", + outputs: [{ internalType: "address[]", name: "", type: "address[]" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "uint256[]", name: "tokenIds", type: "uint256[]" }, + { internalType: "uint256[]", name: "proposalIds", type: "uint256[]" }, + { internalType: "string", name: "reason", type: "string" }, + ], + name: "escrowToFork", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + name: "execute", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "executeFork", + outputs: [ + { internalType: "address", name: "forkTreasury", type: "address" }, + { internalType: "address", name: "forkToken", type: "address" }, + ], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + name: "executeOnTimelockV1", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "forkDAODeployer", + outputs: [ + { internalType: "contract IForkDAODeployer", name: "", type: "address" }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "forkEndTimestamp", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "forkEscrow", + outputs: [ + { + internalType: "contract INounsDAOForkEscrow", + name: "", + type: "address", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "forkPeriod", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "forkThreshold", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "forkThresholdBPS", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + name: "getActions", + outputs: [ + { internalType: "address[]", name: "targets", type: "address[]" }, + { internalType: "uint256[]", name: "values", type: "uint256[]" }, + { internalType: "string[]", name: "signatures", type: "string[]" }, + { internalType: "bytes[]", name: "calldatas", type: "bytes[]" }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "blockNumber_", type: "uint256" }, + ], + name: "getDynamicQuorumParamsAt", + outputs: [ + { + components: [ + { internalType: "uint16", name: "minQuorumVotesBPS", type: "uint16" }, + { internalType: "uint16", name: "maxQuorumVotesBPS", type: "uint16" }, + { internalType: "uint32", name: "quorumCoefficient", type: "uint32" }, + ], + internalType: "struct NounsDAOStorageV3.DynamicQuorumParams", + name: "", + type: "tuple", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "address", name: "voter", type: "address" }, + ], + name: "getReceipt", + outputs: [ + { + components: [ + { internalType: "bool", name: "hasVoted", type: "bool" }, + { internalType: "uint8", name: "support", type: "uint8" }, + { internalType: "uint96", name: "votes", type: "uint96" }, + ], + internalType: "struct NounsDAOStorageV3.Receipt", + name: "", + type: "tuple", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "timelock_", type: "address" }, + { internalType: "address", name: "nouns_", type: "address" }, + { internalType: "address", name: "forkEscrow_", type: "address" }, + { internalType: "address", name: "forkDAODeployer_", type: "address" }, + { internalType: "address", name: "vetoer_", type: "address" }, + { + components: [ + { internalType: "uint256", name: "votingPeriod", type: "uint256" }, + { internalType: "uint256", name: "votingDelay", type: "uint256" }, + { + internalType: "uint256", + name: "proposalThresholdBPS", + type: "uint256", + }, + { + internalType: "uint32", + name: "lastMinuteWindowInBlocks", + type: "uint32", + }, + { + internalType: "uint32", + name: "objectionPeriodDurationInBlocks", + type: "uint32", + }, + { + internalType: "uint32", + name: "proposalUpdatablePeriodInBlocks", + type: "uint32", + }, + ], + internalType: "struct NounsDAOStorageV3.NounsDAOParams", + name: "daoParams_", + type: "tuple", + }, + { + components: [ + { internalType: "uint16", name: "minQuorumVotesBPS", type: "uint16" }, + { internalType: "uint16", name: "maxQuorumVotesBPS", type: "uint16" }, + { internalType: "uint32", name: "quorumCoefficient", type: "uint32" }, + ], + internalType: "struct NounsDAOStorageV3.DynamicQuorumParams", + name: "dynamicQuorumParams_", + type: "tuple", + }, + ], + name: "initialize", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256[]", name: "tokenIds", type: "uint256[]" }, + { internalType: "uint256[]", name: "proposalIds", type: "uint256[]" }, + { internalType: "string", name: "reason", type: "string" }, + ], + name: "joinFork", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "lastMinuteWindowInBlocks", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "account", type: "address" }], + name: "latestProposalIds", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "maxQuorumVotes", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "minQuorumVotes", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "nouns", + outputs: [ + { internalType: "contract NounsTokenLike", name: "", type: "address" }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "numTokensInForkEscrow", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "objectionPeriodDurationInBlocks", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "pendingVetoer", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "proposalCount", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "proposalMaxOperations", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "pure", + type: "function", + }, + { + inputs: [], + name: "proposalThreshold", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "proposalThresholdBPS", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "proposalUpdatablePeriodInBlocks", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + name: "proposals", + outputs: [ + { + components: [ + { internalType: "uint256", name: "id", type: "uint256" }, + { internalType: "address", name: "proposer", type: "address" }, + { + internalType: "uint256", + name: "proposalThreshold", + type: "uint256", + }, + { internalType: "uint256", name: "quorumVotes", type: "uint256" }, + { internalType: "uint256", name: "eta", type: "uint256" }, + { internalType: "uint256", name: "startBlock", type: "uint256" }, + { internalType: "uint256", name: "endBlock", type: "uint256" }, + { internalType: "uint256", name: "forVotes", type: "uint256" }, + { internalType: "uint256", name: "againstVotes", type: "uint256" }, + { internalType: "uint256", name: "abstainVotes", type: "uint256" }, + { internalType: "bool", name: "canceled", type: "bool" }, + { internalType: "bool", name: "vetoed", type: "bool" }, + { internalType: "bool", name: "executed", type: "bool" }, + { internalType: "uint256", name: "totalSupply", type: "uint256" }, + { internalType: "uint256", name: "creationBlock", type: "uint256" }, + ], + internalType: "struct NounsDAOStorageV2.ProposalCondensed", + name: "", + type: "tuple", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + name: "proposalsV3", + outputs: [ + { + components: [ + { internalType: "uint256", name: "id", type: "uint256" }, + { internalType: "address", name: "proposer", type: "address" }, + { + internalType: "uint256", + name: "proposalThreshold", + type: "uint256", + }, + { internalType: "uint256", name: "quorumVotes", type: "uint256" }, + { internalType: "uint256", name: "eta", type: "uint256" }, + { internalType: "uint256", name: "startBlock", type: "uint256" }, + { internalType: "uint256", name: "endBlock", type: "uint256" }, + { internalType: "uint256", name: "forVotes", type: "uint256" }, + { internalType: "uint256", name: "againstVotes", type: "uint256" }, + { internalType: "uint256", name: "abstainVotes", type: "uint256" }, + { internalType: "bool", name: "canceled", type: "bool" }, + { internalType: "bool", name: "vetoed", type: "bool" }, + { internalType: "bool", name: "executed", type: "bool" }, + { internalType: "uint256", name: "totalSupply", type: "uint256" }, + { internalType: "uint256", name: "creationBlock", type: "uint256" }, + { internalType: "address[]", name: "signers", type: "address[]" }, + { + internalType: "uint256", + name: "updatePeriodEndBlock", + type: "uint256", + }, + { + internalType: "uint256", + name: "objectionPeriodEndBlock", + type: "uint256", + }, + { internalType: "bool", name: "executeOnTimelockV1", type: "bool" }, + ], + internalType: "struct NounsDAOStorageV3.ProposalCondensed", + name: "", + type: "tuple", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address[]", name: "targets", type: "address[]" }, + { internalType: "uint256[]", name: "values", type: "uint256[]" }, + { internalType: "string[]", name: "signatures", type: "string[]" }, + { internalType: "bytes[]", name: "calldatas", type: "bytes[]" }, + { internalType: "string", name: "description", type: "string" }, + ], + name: "propose", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + components: [ + { internalType: "bytes", name: "sig", type: "bytes" }, + { internalType: "address", name: "signer", type: "address" }, + { + internalType: "uint256", + name: "expirationTimestamp", + type: "uint256", + }, + ], + internalType: "struct NounsDAOStorageV3.ProposerSignature[]", + name: "proposerSignatures", + type: "tuple[]", + }, + { internalType: "address[]", name: "targets", type: "address[]" }, + { internalType: "uint256[]", name: "values", type: "uint256[]" }, + { internalType: "string[]", name: "signatures", type: "string[]" }, + { internalType: "bytes[]", name: "calldatas", type: "bytes[]" }, + { internalType: "string", name: "description", type: "string" }, + ], + name: "proposeBySigs", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address[]", name: "targets", type: "address[]" }, + { internalType: "uint256[]", name: "values", type: "uint256[]" }, + { internalType: "string[]", name: "signatures", type: "string[]" }, + { internalType: "bytes[]", name: "calldatas", type: "bytes[]" }, + { internalType: "string", name: "description", type: "string" }, + ], + name: "proposeOnTimelockV1", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + name: "queue", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "quorumParamsCheckpoints", + outputs: [ + { + components: [ + { internalType: "uint32", name: "fromBlock", type: "uint32" }, + { + components: [ + { + internalType: "uint16", + name: "minQuorumVotesBPS", + type: "uint16", + }, + { + internalType: "uint16", + name: "maxQuorumVotesBPS", + type: "uint16", + }, + { + internalType: "uint32", + name: "quorumCoefficient", + type: "uint32", + }, + ], + internalType: "struct NounsDAOStorageV3.DynamicQuorumParams", + name: "params", + type: "tuple", + }, + ], + internalType: + "struct NounsDAOStorageV3.DynamicQuorumParamsCheckpoint[]", + name: "", + type: "tuple[]", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "index", type: "uint256" }], + name: "quorumParamsCheckpoints", + outputs: [ + { + components: [ + { internalType: "uint32", name: "fromBlock", type: "uint32" }, + { + components: [ + { + internalType: "uint16", + name: "minQuorumVotesBPS", + type: "uint16", + }, + { + internalType: "uint16", + name: "maxQuorumVotesBPS", + type: "uint16", + }, + { + internalType: "uint32", + name: "quorumCoefficient", + type: "uint32", + }, + ], + internalType: "struct NounsDAOStorageV3.DynamicQuorumParams", + name: "params", + type: "tuple", + }, + ], + internalType: "struct NounsDAOStorageV3.DynamicQuorumParamsCheckpoint", + name: "", + type: "tuple", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + name: "quorumVotes", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "quorumVotesBPS", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + name: "state", + outputs: [ + { + internalType: "enum NounsDAOStorageV3.ProposalState", + name: "", + type: "uint8", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "timelock", + outputs: [ + { internalType: "contract INounsDAOExecutor", name: "", type: "address" }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "timelockV1", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "address[]", name: "targets", type: "address[]" }, + { internalType: "uint256[]", name: "values", type: "uint256[]" }, + { internalType: "string[]", name: "signatures", type: "string[]" }, + { internalType: "bytes[]", name: "calldatas", type: "bytes[]" }, + { internalType: "string", name: "description", type: "string" }, + { internalType: "string", name: "updateMessage", type: "string" }, + ], + name: "updateProposal", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { + components: [ + { internalType: "bytes", name: "sig", type: "bytes" }, + { internalType: "address", name: "signer", type: "address" }, + { + internalType: "uint256", + name: "expirationTimestamp", + type: "uint256", + }, + ], + internalType: "struct NounsDAOStorageV3.ProposerSignature[]", + name: "proposerSignatures", + type: "tuple[]", + }, + { internalType: "address[]", name: "targets", type: "address[]" }, + { internalType: "uint256[]", name: "values", type: "uint256[]" }, + { internalType: "string[]", name: "signatures", type: "string[]" }, + { internalType: "bytes[]", name: "calldatas", type: "bytes[]" }, + { internalType: "string", name: "description", type: "string" }, + { internalType: "string", name: "updateMessage", type: "string" }, + ], + name: "updateProposalBySigs", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "string", name: "description", type: "string" }, + { internalType: "string", name: "updateMessage", type: "string" }, + ], + name: "updateProposalDescription", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "address[]", name: "targets", type: "address[]" }, + { internalType: "uint256[]", name: "values", type: "uint256[]" }, + { internalType: "string[]", name: "signatures", type: "string[]" }, + { internalType: "bytes[]", name: "calldatas", type: "bytes[]" }, + { internalType: "string", name: "updateMessage", type: "string" }, + ], + name: "updateProposalTransactions", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + name: "veto", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "vetoer", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "voteSnapshotBlockSwitchProposalId", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "votingDelay", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "votingPeriod", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "uint256[]", name: "tokenIds", type: "uint256[]" }, + { internalType: "address", name: "to", type: "address" }, + ], + name: "withdrawDAONounsFromEscrowIncreasingTotalSupply", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256[]", name: "tokenIds", type: "uint256[]" }, + ], + name: "withdrawDAONounsFromEscrowToTreasury", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256[]", name: "tokenIds", type: "uint256[]" }, + ], + name: "withdrawFromForkEscrow", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { stateMutability: "payable", type: "receive" }, +] as const; diff --git a/apps/api/src/clients/nouns/abi/token.ts b/apps/api/src/clients/nouns/abi/token.ts new file mode 100644 index 000000000..c1945fe04 --- /dev/null +++ b/apps/api/src/clients/nouns/abi/token.ts @@ -0,0 +1,681 @@ +export const TokenAbi = [ + { + inputs: [ + { internalType: "address", name: "_noundersDAO", type: "address" }, + { internalType: "address", name: "_minter", type: "address" }, + { + internalType: "contract INounsDescriptor", + name: "_descriptor", + type: "address", + }, + { + internalType: "contract INounsSeeder", + name: "_seeder", + type: "address", + }, + { + internalType: "contract IProxyRegistry", + name: "_proxyRegistry", + type: "address", + }, + ], + stateMutability: "nonpayable", + type: "constructor", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "owner", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "approved", + type: "address", + }, + { + indexed: true, + internalType: "uint256", + name: "tokenId", + type: "uint256", + }, + ], + name: "Approval", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "owner", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "operator", + type: "address", + }, + { indexed: false, internalType: "bool", name: "approved", type: "bool" }, + ], + name: "ApprovalForAll", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "delegator", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "fromDelegate", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "toDelegate", + type: "address", + }, + ], + name: "DelegateChanged", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "delegate", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "previousBalance", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "newBalance", + type: "uint256", + }, + ], + name: "DelegateVotesChanged", + type: "event", + }, + { anonymous: false, inputs: [], name: "DescriptorLocked", type: "event" }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "contract INounsDescriptor", + name: "descriptor", + type: "address", + }, + ], + name: "DescriptorUpdated", + type: "event", + }, + { anonymous: false, inputs: [], name: "MinterLocked", type: "event" }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "minter", + type: "address", + }, + ], + name: "MinterUpdated", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "uint256", + name: "tokenId", + type: "uint256", + }, + ], + name: "NounBurned", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "uint256", + name: "tokenId", + type: "uint256", + }, + { + components: [ + { internalType: "uint48", name: "background", type: "uint48" }, + { internalType: "uint48", name: "body", type: "uint48" }, + { internalType: "uint48", name: "accessory", type: "uint48" }, + { internalType: "uint48", name: "head", type: "uint48" }, + { internalType: "uint48", name: "glasses", type: "uint48" }, + ], + indexed: false, + internalType: "struct INounsSeeder.Seed", + name: "seed", + type: "tuple", + }, + ], + name: "NounCreated", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "noundersDAO", + type: "address", + }, + ], + name: "NoundersDAOUpdated", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "previousOwner", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "newOwner", + type: "address", + }, + ], + name: "OwnershipTransferred", + type: "event", + }, + { anonymous: false, inputs: [], name: "SeederLocked", type: "event" }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "contract INounsSeeder", + name: "seeder", + type: "address", + }, + ], + name: "SeederUpdated", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "address", name: "from", type: "address" }, + { indexed: true, internalType: "address", name: "to", type: "address" }, + { + indexed: true, + internalType: "uint256", + name: "tokenId", + type: "uint256", + }, + ], + name: "Transfer", + type: "event", + }, + { + inputs: [], + name: "DELEGATION_TYPEHASH", + outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "DOMAIN_TYPEHASH", + outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "to", type: "address" }, + { internalType: "uint256", name: "tokenId", type: "uint256" }, + ], + name: "approve", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "owner", type: "address" }], + name: "balanceOf", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "nounId", type: "uint256" }], + name: "burn", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "", type: "address" }, + { internalType: "uint32", name: "", type: "uint32" }, + ], + name: "checkpoints", + outputs: [ + { internalType: "uint32", name: "fromBlock", type: "uint32" }, + { internalType: "uint96", name: "votes", type: "uint96" }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "contractURI", + outputs: [{ internalType: "string", name: "", type: "string" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "tokenId", type: "uint256" }], + name: "dataURI", + outputs: [{ internalType: "string", name: "", type: "string" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "decimals", + outputs: [{ internalType: "uint8", name: "", type: "uint8" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "delegatee", type: "address" }], + name: "delegate", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "delegatee", type: "address" }, + { internalType: "uint256", name: "nonce", type: "uint256" }, + { internalType: "uint256", name: "expiry", type: "uint256" }, + { internalType: "uint8", name: "v", type: "uint8" }, + { internalType: "bytes32", name: "r", type: "bytes32" }, + { internalType: "bytes32", name: "s", type: "bytes32" }, + ], + name: "delegateBySig", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "delegator", type: "address" }], + name: "delegates", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "descriptor", + outputs: [ + { internalType: "contract INounsDescriptor", name: "", type: "address" }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "tokenId", type: "uint256" }], + name: "getApproved", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "account", type: "address" }], + name: "getCurrentVotes", + outputs: [{ internalType: "uint96", name: "", type: "uint96" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "account", type: "address" }, + { internalType: "uint256", name: "blockNumber", type: "uint256" }, + ], + name: "getPriorVotes", + outputs: [{ internalType: "uint96", name: "", type: "uint96" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "owner", type: "address" }, + { internalType: "address", name: "operator", type: "address" }, + ], + name: "isApprovedForAll", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "isDescriptorLocked", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "isMinterLocked", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "isSeederLocked", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "lockDescriptor", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "lockMinter", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "lockSeeder", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "mint", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "minter", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "name", + outputs: [{ internalType: "string", name: "", type: "string" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "", type: "address" }], + name: "nonces", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "noundersDAO", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "", type: "address" }], + name: "numCheckpoints", + outputs: [{ internalType: "uint32", name: "", type: "uint32" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "owner", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "tokenId", type: "uint256" }], + name: "ownerOf", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "proxyRegistry", + outputs: [ + { internalType: "contract IProxyRegistry", name: "", type: "address" }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "renounceOwnership", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "from", type: "address" }, + { internalType: "address", name: "to", type: "address" }, + { internalType: "uint256", name: "tokenId", type: "uint256" }, + ], + name: "safeTransferFrom", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "from", type: "address" }, + { internalType: "address", name: "to", type: "address" }, + { internalType: "uint256", name: "tokenId", type: "uint256" }, + { internalType: "bytes", name: "_data", type: "bytes" }, + ], + name: "safeTransferFrom", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "seeder", + outputs: [ + { internalType: "contract INounsSeeder", name: "", type: "address" }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "", type: "uint256" }], + name: "seeds", + outputs: [ + { internalType: "uint48", name: "background", type: "uint48" }, + { internalType: "uint48", name: "body", type: "uint48" }, + { internalType: "uint48", name: "accessory", type: "uint48" }, + { internalType: "uint48", name: "head", type: "uint48" }, + { internalType: "uint48", name: "glasses", type: "uint48" }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "operator", type: "address" }, + { internalType: "bool", name: "approved", type: "bool" }, + ], + name: "setApprovalForAll", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "string", name: "newContractURIHash", type: "string" }, + ], + name: "setContractURIHash", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "contract INounsDescriptor", + name: "_descriptor", + type: "address", + }, + ], + name: "setDescriptor", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "_minter", type: "address" }], + name: "setMinter", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "_noundersDAO", type: "address" }, + ], + name: "setNoundersDAO", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "contract INounsSeeder", + name: "_seeder", + type: "address", + }, + ], + name: "setSeeder", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "bytes4", name: "interfaceId", type: "bytes4" }], + name: "supportsInterface", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "symbol", + outputs: [{ internalType: "string", name: "", type: "string" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "index", type: "uint256" }], + name: "tokenByIndex", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "owner", type: "address" }, + { internalType: "uint256", name: "index", type: "uint256" }, + ], + name: "tokenOfOwnerByIndex", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "tokenId", type: "uint256" }], + name: "tokenURI", + outputs: [{ internalType: "string", name: "", type: "string" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "totalSupply", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "from", type: "address" }, + { internalType: "address", name: "to", type: "address" }, + { internalType: "uint256", name: "tokenId", type: "uint256" }, + ], + name: "transferFrom", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "newOwner", type: "address" }], + name: "transferOwnership", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "delegator", type: "address" }], + name: "votesToDelegate", + outputs: [{ internalType: "uint96", name: "", type: "uint96" }], + stateMutability: "view", + type: "function", + }, +] as const; diff --git a/apps/api/src/clients/nouns/index.ts b/apps/api/src/clients/nouns/index.ts new file mode 100644 index 000000000..847eed160 --- /dev/null +++ b/apps/api/src/clients/nouns/index.ts @@ -0,0 +1,125 @@ +import { + Account, + Address, + Chain, + Client as vClient, + fromHex, + toHex, + Transport, +} from "viem"; +import { readContract } from "viem/actions"; + +import { DAOClient } from "@/interfaces/client"; +import { GovernorAbi } from "./abi/governor"; +import { GovernorBase } from "../governor.base"; + +export class Client< + TTransport extends Transport = Transport, + TChain extends Chain = Chain, + TAccount extends Account | undefined = Account | undefined, + > + extends GovernorBase + implements DAOClient +{ + private abi: typeof GovernorAbi; + private address: Address; + + constructor(client: vClient, address: Address) { + super(client); + this.address = address; + this.abi = GovernorAbi; + } + + getDaoId(): string { + return "NOUNS"; + } + + async getQuorum(): Promise { + const lastProposalId = await readContract(this.client, { + abi: this.abi, + address: this.address, + functionName: "proposalCount", + }); + + return await readContract(this.client, { + abi: this.abi, + address: this.address, + functionName: "quorumVotes", + args: [lastProposalId], + }); + } + + async getProposalThreshold(): Promise { + return readContract(this.client, { + abi: this.abi, + address: this.address, + functionName: "proposalThreshold", + }); + } + + async getVotingDelay(): Promise { + return readContract(this.client, { + abi: this.abi, + address: this.address, + functionName: "votingDelay", + }); + } + + async getVotingPeriod(): Promise { + return readContract(this.client, { + abi: this.abi, + address: this.address, + functionName: "votingPeriod", + }); + } + + async getTimelockDelay(): Promise { + const timelockAddress = await readContract(this.client, { + abi: this.abi, + address: this.address, + functionName: "timelock", + }); + return readContract(this.client, { + abi: [ + { + inputs: [], + name: "delay", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, + ], + address: timelockAddress, + functionName: "delay", + }); + } + + async getCurrentBlockNumber(): Promise { + const result = await this.client.request({ + method: "eth_blockNumber", + }); + return fromHex(result, "number"); + } + + async getBlockTime(blockNumber: number): Promise { + const block = await this.client.request({ + method: "eth_getBlockByNumber", + params: [toHex(blockNumber), false], + }); + return block?.timestamp ? fromHex(block.timestamp, "number") : null; + } + + calculateQuorum(votes: { + forVotes: bigint; + againstVotes: bigint; + abstainVotes: bigint; + }): bigint { + return votes.forVotes + votes.abstainVotes; + } +} diff --git a/apps/api/src/clients/obol/abi/governor.ts b/apps/api/src/clients/obol/abi/governor.ts new file mode 100644 index 000000000..ebc242421 --- /dev/null +++ b/apps/api/src/clients/obol/abi/governor.ts @@ -0,0 +1,882 @@ +export const GovernorAbi = [ + { + inputs: [ + { internalType: "contract IVotes", name: "_token", type: "address" }, + { + internalType: "uint256", + name: "_initialQuorumNumerator", + type: "uint256", + }, + { internalType: "uint48", name: "_initialVotingDelay", type: "uint48" }, + { internalType: "uint32", name: "_initialVotingPeriod", type: "uint32" }, + { + internalType: "uint256", + name: "_initialProposalThreshold", + type: "uint256", + }, + { + internalType: "contract TimelockController", + name: "_timelock", + type: "address", + }, + ], + stateMutability: "nonpayable", + type: "constructor", + }, + { inputs: [], name: "CheckpointUnorderedInsertion", type: "error" }, + { inputs: [], name: "FailedInnerCall", type: "error" }, + { + inputs: [{ internalType: "address", name: "voter", type: "address" }], + name: "GovernorAlreadyCastVote", + type: "error", + }, + { + inputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + name: "GovernorAlreadyQueuedProposal", + type: "error", + }, + { + inputs: [], + name: "GovernorCountingFractional_NoVoteWeight", + type: "error", + }, + { + inputs: [], + name: "GovernorCountingFractional__InvalidVoteData", + type: "error", + }, + { + inputs: [], + name: "GovernorCountingFractional__VoteWeightExceeded", + type: "error", + }, + { inputs: [], name: "GovernorDisabledDeposit", type: "error" }, + { + inputs: [ + { internalType: "address", name: "proposer", type: "address" }, + { internalType: "uint256", name: "votes", type: "uint256" }, + { internalType: "uint256", name: "threshold", type: "uint256" }, + ], + name: "GovernorInsufficientProposerVotes", + type: "error", + }, + { + inputs: [ + { internalType: "uint256", name: "targets", type: "uint256" }, + { internalType: "uint256", name: "calldatas", type: "uint256" }, + { internalType: "uint256", name: "values", type: "uint256" }, + ], + name: "GovernorInvalidProposalLength", + type: "error", + }, + { + inputs: [ + { internalType: "uint256", name: "quorumNumerator", type: "uint256" }, + { internalType: "uint256", name: "quorumDenominator", type: "uint256" }, + ], + name: "GovernorInvalidQuorumFraction", + type: "error", + }, + { + inputs: [{ internalType: "address", name: "voter", type: "address" }], + name: "GovernorInvalidSignature", + type: "error", + }, + { inputs: [], name: "GovernorInvalidVoteType", type: "error" }, + { + inputs: [ + { internalType: "uint256", name: "votingPeriod", type: "uint256" }, + ], + name: "GovernorInvalidVotingPeriod", + type: "error", + }, + { + inputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + name: "GovernorNonexistentProposal", + type: "error", + }, + { + inputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + name: "GovernorNotQueuedProposal", + type: "error", + }, + { + inputs: [{ internalType: "address", name: "account", type: "address" }], + name: "GovernorOnlyExecutor", + type: "error", + }, + { + inputs: [{ internalType: "address", name: "account", type: "address" }], + name: "GovernorOnlyProposer", + type: "error", + }, + { inputs: [], name: "GovernorQueueNotImplemented", type: "error" }, + { + inputs: [{ internalType: "address", name: "proposer", type: "address" }], + name: "GovernorRestrictedProposer", + type: "error", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { + internalType: "enum IGovernor.ProposalState", + name: "current", + type: "uint8", + }, + { internalType: "bytes32", name: "expectedStates", type: "bytes32" }, + ], + name: "GovernorUnexpectedProposalState", + type: "error", + }, + { + inputs: [ + { internalType: "address", name: "account", type: "address" }, + { internalType: "uint256", name: "currentNonce", type: "uint256" }, + ], + name: "InvalidAccountNonce", + type: "error", + }, + { inputs: [], name: "InvalidShortString", type: "error" }, + { inputs: [], name: "QueueEmpty", type: "error" }, + { inputs: [], name: "QueueFull", type: "error" }, + { + inputs: [ + { internalType: "uint8", name: "bits", type: "uint8" }, + { internalType: "uint256", name: "value", type: "uint256" }, + ], + name: "SafeCastOverflowedUintDowncast", + type: "error", + }, + { + inputs: [{ internalType: "string", name: "str", type: "string" }], + name: "StringTooLong", + type: "error", + }, + { anonymous: false, inputs: [], name: "EIP712DomainChanged", type: "event" }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "proposalId", + type: "uint256", + }, + ], + name: "ProposalCanceled", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "proposalId", + type: "uint256", + }, + { + indexed: false, + internalType: "address", + name: "proposer", + type: "address", + }, + { + indexed: false, + internalType: "address[]", + name: "targets", + type: "address[]", + }, + { + indexed: false, + internalType: "uint256[]", + name: "values", + type: "uint256[]", + }, + { + indexed: false, + internalType: "string[]", + name: "signatures", + type: "string[]", + }, + { + indexed: false, + internalType: "bytes[]", + name: "calldatas", + type: "bytes[]", + }, + { + indexed: false, + internalType: "uint256", + name: "voteStart", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "voteEnd", + type: "uint256", + }, + { + indexed: false, + internalType: "string", + name: "description", + type: "string", + }, + ], + name: "ProposalCreated", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "proposalId", + type: "uint256", + }, + ], + name: "ProposalExecuted", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "proposalId", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "etaSeconds", + type: "uint256", + }, + ], + name: "ProposalQueued", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "oldProposalThreshold", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "newProposalThreshold", + type: "uint256", + }, + ], + name: "ProposalThresholdSet", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "oldQuorumNumerator", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "newQuorumNumerator", + type: "uint256", + }, + ], + name: "QuorumNumeratorUpdated", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "oldTimelock", + type: "address", + }, + { + indexed: false, + internalType: "address", + name: "newTimelock", + type: "address", + }, + ], + name: "TimelockChange", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "voter", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "proposalId", + type: "uint256", + }, + { indexed: false, internalType: "uint8", name: "support", type: "uint8" }, + { + indexed: false, + internalType: "uint256", + name: "weight", + type: "uint256", + }, + { + indexed: false, + internalType: "string", + name: "reason", + type: "string", + }, + ], + name: "VoteCast", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "voter", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "proposalId", + type: "uint256", + }, + { indexed: false, internalType: "uint8", name: "support", type: "uint8" }, + { + indexed: false, + internalType: "uint256", + name: "weight", + type: "uint256", + }, + { + indexed: false, + internalType: "string", + name: "reason", + type: "string", + }, + { indexed: false, internalType: "bytes", name: "params", type: "bytes" }, + ], + name: "VoteCastWithParams", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "oldVotingDelay", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "newVotingDelay", + type: "uint256", + }, + ], + name: "VotingDelaySet", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "oldVotingPeriod", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "newVotingPeriod", + type: "uint256", + }, + ], + name: "VotingPeriodSet", + type: "event", + }, + { + inputs: [], + name: "BALLOT_TYPEHASH", + outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "CLOCK_MODE", + outputs: [{ internalType: "string", name: "", type: "string" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "COUNTING_MODE", + outputs: [{ internalType: "string", name: "", type: "string" }], + stateMutability: "pure", + type: "function", + }, + { + inputs: [], + name: "EXTENDED_BALLOT_TYPEHASH", + outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address[]", name: "targets", type: "address[]" }, + { internalType: "uint256[]", name: "values", type: "uint256[]" }, + { internalType: "bytes[]", name: "calldatas", type: "bytes[]" }, + { internalType: "bytes32", name: "descriptionHash", type: "bytes32" }, + ], + name: "cancel", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "uint8", name: "support", type: "uint8" }, + ], + name: "castVote", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "uint8", name: "support", type: "uint8" }, + { internalType: "address", name: "voter", type: "address" }, + { internalType: "bytes", name: "signature", type: "bytes" }, + ], + name: "castVoteBySig", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "uint8", name: "support", type: "uint8" }, + { internalType: "string", name: "reason", type: "string" }, + ], + name: "castVoteWithReason", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "uint8", name: "support", type: "uint8" }, + { internalType: "string", name: "reason", type: "string" }, + { internalType: "bytes", name: "params", type: "bytes" }, + ], + name: "castVoteWithReasonAndParams", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "uint8", name: "support", type: "uint8" }, + { internalType: "address", name: "voter", type: "address" }, + { internalType: "string", name: "reason", type: "string" }, + { internalType: "bytes", name: "params", type: "bytes" }, + { internalType: "bytes", name: "signature", type: "bytes" }, + ], + name: "castVoteWithReasonAndParamsBySig", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "clock", + outputs: [{ internalType: "uint48", name: "", type: "uint48" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "eip712Domain", + outputs: [ + { internalType: "bytes1", name: "fields", type: "bytes1" }, + { internalType: "string", name: "name", type: "string" }, + { internalType: "string", name: "version", type: "string" }, + { internalType: "uint256", name: "chainId", type: "uint256" }, + { internalType: "address", name: "verifyingContract", type: "address" }, + { internalType: "bytes32", name: "salt", type: "bytes32" }, + { internalType: "uint256[]", name: "extensions", type: "uint256[]" }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address[]", name: "targets", type: "address[]" }, + { internalType: "uint256[]", name: "values", type: "uint256[]" }, + { internalType: "bytes[]", name: "calldatas", type: "bytes[]" }, + { internalType: "bytes32", name: "descriptionHash", type: "bytes32" }, + ], + name: "execute", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "payable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "account", type: "address" }, + { internalType: "uint256", name: "timepoint", type: "uint256" }, + ], + name: "getVotes", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "account", type: "address" }, + { internalType: "uint256", name: "timepoint", type: "uint256" }, + { internalType: "bytes", name: "params", type: "bytes" }, + ], + name: "getVotesWithParams", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "address", name: "account", type: "address" }, + ], + name: "hasVoted", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address[]", name: "targets", type: "address[]" }, + { internalType: "uint256[]", name: "values", type: "uint256[]" }, + { internalType: "bytes[]", name: "calldatas", type: "bytes[]" }, + { internalType: "bytes32", name: "descriptionHash", type: "bytes32" }, + ], + name: "hashProposal", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "pure", + type: "function", + }, + { + inputs: [], + name: "name", + outputs: [{ internalType: "string", name: "", type: "string" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "owner", type: "address" }], + name: "nonces", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "", type: "address" }, + { internalType: "address", name: "", type: "address" }, + { internalType: "uint256[]", name: "", type: "uint256[]" }, + { internalType: "uint256[]", name: "", type: "uint256[]" }, + { internalType: "bytes", name: "", type: "bytes" }, + ], + name: "onERC1155BatchReceived", + outputs: [{ internalType: "bytes4", name: "", type: "bytes4" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "", type: "address" }, + { internalType: "address", name: "", type: "address" }, + { internalType: "uint256", name: "", type: "uint256" }, + { internalType: "uint256", name: "", type: "uint256" }, + { internalType: "bytes", name: "", type: "bytes" }, + ], + name: "onERC1155Received", + outputs: [{ internalType: "bytes4", name: "", type: "bytes4" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "", type: "address" }, + { internalType: "address", name: "", type: "address" }, + { internalType: "uint256", name: "", type: "uint256" }, + { internalType: "bytes", name: "", type: "bytes" }, + ], + name: "onERC721Received", + outputs: [{ internalType: "bytes4", name: "", type: "bytes4" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + name: "proposalDeadline", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + name: "proposalEta", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + name: "proposalNeedsQueuing", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + name: "proposalProposer", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + name: "proposalSnapshot", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "proposalThreshold", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + name: "proposalVotes", + outputs: [ + { internalType: "uint256", name: "againstVotes", type: "uint256" }, + { internalType: "uint256", name: "forVotes", type: "uint256" }, + { internalType: "uint256", name: "abstainVotes", type: "uint256" }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address[]", name: "targets", type: "address[]" }, + { internalType: "uint256[]", name: "values", type: "uint256[]" }, + { internalType: "bytes[]", name: "calldatas", type: "bytes[]" }, + { internalType: "string", name: "description", type: "string" }, + ], + name: "propose", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address[]", name: "targets", type: "address[]" }, + { internalType: "uint256[]", name: "values", type: "uint256[]" }, + { internalType: "bytes[]", name: "calldatas", type: "bytes[]" }, + { internalType: "bytes32", name: "descriptionHash", type: "bytes32" }, + ], + name: "queue", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "timepoint", type: "uint256" }], + name: "quorum", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "quorumDenominator", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "timepoint", type: "uint256" }], + name: "quorumNumerator", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "quorumNumerator", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "target", type: "address" }, + { internalType: "uint256", name: "value", type: "uint256" }, + { internalType: "bytes", name: "data", type: "bytes" }, + ], + name: "relay", + outputs: [], + stateMutability: "payable", + type: "function", + }, + { + inputs: [ + { + internalType: "uint256", + name: "newProposalThreshold", + type: "uint256", + }, + ], + name: "setProposalThreshold", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint48", name: "newVotingDelay", type: "uint48" }, + ], + name: "setVotingDelay", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint32", name: "newVotingPeriod", type: "uint32" }, + ], + name: "setVotingPeriod", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + name: "state", + outputs: [ + { internalType: "enum IGovernor.ProposalState", name: "", type: "uint8" }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "bytes4", name: "interfaceId", type: "bytes4" }], + name: "supportsInterface", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "timelock", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "token", + outputs: [{ internalType: "contract IERC5805", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "newQuorumNumerator", type: "uint256" }, + ], + name: "updateQuorumNumerator", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "contract TimelockController", + name: "newTimelock", + type: "address", + }, + ], + name: "updateTimelock", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "version", + outputs: [{ internalType: "string", name: "", type: "string" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "address", name: "account", type: "address" }, + ], + name: "voteWeightCast", + outputs: [{ internalType: "uint128", name: "", type: "uint128" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "votingDelay", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "votingPeriod", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { stateMutability: "payable", type: "receive" }, +] as const; diff --git a/apps/api/src/clients/obol/abi/index.ts b/apps/api/src/clients/obol/abi/index.ts new file mode 100644 index 000000000..b039c42a8 --- /dev/null +++ b/apps/api/src/clients/obol/abi/index.ts @@ -0,0 +1,2 @@ +export { GovernorAbi as ObolGovernorAbi } from "./governor"; +export { TokenAbi as ObolTokenAbi } from "./token"; diff --git a/apps/api/src/clients/obol/abi/token.ts b/apps/api/src/clients/obol/abi/token.ts new file mode 100644 index 000000000..c8a319f0d --- /dev/null +++ b/apps/api/src/clients/obol/abi/token.ts @@ -0,0 +1,465 @@ +export const TokenAbi = [ + { + inputs: [ + { internalType: "address", name: "_admin", type: "address" }, + { internalType: "address", name: "_minter", type: "address" }, + { + internalType: "address", + name: "_ensReverseRegistrar", + type: "address", + }, + { internalType: "address", name: "_ensOwner", type: "address" }, + ], + stateMutability: "nonpayable", + type: "constructor", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "owner", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "spender", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "value", + type: "uint256", + }, + ], + name: "Approval", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "delegator", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "fromDelegate", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "toDelegate", + type: "address", + }, + ], + name: "DelegateChanged", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "delegate", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "previousBalance", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "newBalance", + type: "uint256", + }, + ], + name: "DelegateVotesChanged", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "bytes32", name: "role", type: "bytes32" }, + { + indexed: true, + internalType: "bytes32", + name: "previousAdminRole", + type: "bytes32", + }, + { + indexed: true, + internalType: "bytes32", + name: "newAdminRole", + type: "bytes32", + }, + ], + name: "RoleAdminChanged", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "bytes32", name: "role", type: "bytes32" }, + { + indexed: true, + internalType: "address", + name: "account", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "sender", + type: "address", + }, + ], + name: "RoleGranted", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "bytes32", name: "role", type: "bytes32" }, + { + indexed: true, + internalType: "address", + name: "account", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "sender", + type: "address", + }, + ], + name: "RoleRevoked", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "address", name: "from", type: "address" }, + { indexed: true, internalType: "address", name: "to", type: "address" }, + { + indexed: false, + internalType: "uint256", + name: "value", + type: "uint256", + }, + ], + name: "Transfer", + type: "event", + }, + { + inputs: [], + name: "DEFAULT_ADMIN_ROLE", + outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "DOMAIN_SEPARATOR", + outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "MINTER_ROLE", + outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "owner", type: "address" }, + { internalType: "address", name: "spender", type: "address" }, + ], + name: "allowance", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "spender", type: "address" }, + { internalType: "uint256", name: "amount", type: "uint256" }, + ], + name: "approve", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "account", type: "address" }], + name: "balanceOf", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "_amount", type: "uint256" }], + name: "burn", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "_owner", type: "address" }, + { internalType: "uint256", name: "_amount", type: "uint256" }, + ], + name: "burnFrom", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "account", type: "address" }, + { internalType: "uint32", name: "pos", type: "uint32" }, + ], + name: "checkpoints", + outputs: [ + { + components: [ + { internalType: "uint32", name: "fromBlock", type: "uint32" }, + { internalType: "uint224", name: "votes", type: "uint224" }, + ], + internalType: "struct ERC20Votes.Checkpoint", + name: "", + type: "tuple", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "decimals", + outputs: [{ internalType: "uint8", name: "", type: "uint8" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "spender", type: "address" }, + { internalType: "uint256", name: "subtractedValue", type: "uint256" }, + ], + name: "decreaseAllowance", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "delegatee", type: "address" }], + name: "delegate", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "delegatee", type: "address" }, + { internalType: "uint256", name: "nonce", type: "uint256" }, + { internalType: "uint256", name: "expiry", type: "uint256" }, + { internalType: "uint8", name: "v", type: "uint8" }, + { internalType: "bytes32", name: "r", type: "bytes32" }, + { internalType: "bytes32", name: "s", type: "bytes32" }, + ], + name: "delegateBySig", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "account", type: "address" }], + name: "delegates", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "blockNumber", type: "uint256" }], + name: "getPastTotalSupply", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "account", type: "address" }, + { internalType: "uint256", name: "blockNumber", type: "uint256" }, + ], + name: "getPastVotes", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "bytes32", name: "role", type: "bytes32" }], + name: "getRoleAdmin", + outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "account", type: "address" }], + name: "getVotes", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "bytes32", name: "role", type: "bytes32" }, + { internalType: "address", name: "account", type: "address" }, + ], + name: "grantRole", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "bytes32", name: "role", type: "bytes32" }, + { internalType: "address", name: "account", type: "address" }, + ], + name: "hasRole", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "spender", type: "address" }, + { internalType: "uint256", name: "addedValue", type: "uint256" }, + ], + name: "increaseAllowance", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "_to", type: "address" }, + { internalType: "uint256", name: "_amount", type: "uint256" }, + ], + name: "mint", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "name", + outputs: [{ internalType: "string", name: "", type: "string" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "owner", type: "address" }], + name: "nonces", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "account", type: "address" }], + name: "numCheckpoints", + outputs: [{ internalType: "uint32", name: "", type: "uint32" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "owner", type: "address" }, + { internalType: "address", name: "spender", type: "address" }, + { internalType: "uint256", name: "value", type: "uint256" }, + { internalType: "uint256", name: "deadline", type: "uint256" }, + { internalType: "uint8", name: "v", type: "uint8" }, + { internalType: "bytes32", name: "r", type: "bytes32" }, + { internalType: "bytes32", name: "s", type: "bytes32" }, + ], + name: "permit", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "bytes32", name: "role", type: "bytes32" }, + { internalType: "address", name: "account", type: "address" }, + ], + name: "renounceRole", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "bytes32", name: "role", type: "bytes32" }, + { internalType: "address", name: "account", type: "address" }, + ], + name: "revokeRole", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "bytes4", name: "interfaceId", type: "bytes4" }], + name: "supportsInterface", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "symbol", + outputs: [{ internalType: "string", name: "", type: "string" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "totalSupply", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "to", type: "address" }, + { internalType: "uint256", name: "amount", type: "uint256" }, + ], + name: "transfer", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "from", type: "address" }, + { internalType: "address", name: "to", type: "address" }, + { internalType: "uint256", name: "amount", type: "uint256" }, + ], + name: "transferFrom", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "nonpayable", + type: "function", + }, +] as const; diff --git a/apps/api/src/clients/obol/index.ts b/apps/api/src/clients/obol/index.ts new file mode 100644 index 000000000..4e54c803e --- /dev/null +++ b/apps/api/src/clients/obol/index.ts @@ -0,0 +1,117 @@ +import { + Account, + Address, + Chain, + Client, + fromHex, + toHex, + Transport, +} from "viem"; +import { getBlockNumber, readContract } from "viem/actions"; + +import { DAOClient } from "@/interfaces/client"; +import { ObolGovernorAbi } from "./abi"; +import { GovernorBase } from "../governor.base"; + +export class ObolClient< + TTransport extends Transport = Transport, + TChain extends Chain = Chain, + TAccount extends Account | undefined = Account | undefined, + > + extends GovernorBase + implements DAOClient +{ + private abi: typeof ObolGovernorAbi; + private address: Address; + + constructor(client: Client, address: Address) { + super(client); + this.address = address; + this.abi = ObolGovernorAbi; + } + + getDaoId(): string { + return "OBOL"; + } + + async getQuorum(): Promise { + const blockNumber = await getBlockNumber(this.client); + const targetBlock = blockNumber - 10n; + return readContract(this.client, { + abi: this.abi, + address: this.address, + functionName: "quorum", + args: [targetBlock < 0n ? 0n : targetBlock], + }); + } + + async getProposalThreshold(): Promise { + return readContract(this.client, { + abi: this.abi, + address: this.address, + functionName: "proposalThreshold", + }); + } + + async getVotingDelay(): Promise { + return readContract(this.client, { + abi: this.abi, + address: this.address, + functionName: "votingDelay", + }); + } + + async getVotingPeriod(): Promise { + return readContract(this.client, { + abi: this.abi, + address: this.address, + functionName: "votingPeriod", + }); + } + + async getTimelockDelay(): Promise { + const timelockAddress = await readContract(this.client, { + abi: this.abi, + address: this.address, + functionName: "timelock", + }); + return readContract(this.client, { + abi: [ + { + constant: true, + inputs: [], + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + payable: false, + stateMutability: "view", + type: "function", + name: "getMinDelay", + }, + ], + address: timelockAddress, + functionName: "getMinDelay", + }); + } + + async getCurrentBlockNumber(): Promise { + const result = await this.client.request({ + method: "eth_blockNumber", + }); + return fromHex(result, "number"); + } + + async getBlockTime(blockNumber: number): Promise { + const block = await this.client.request({ + method: "eth_getBlockByNumber", + params: [toHex(blockNumber), false], + }); + return block?.timestamp ? fromHex(block.timestamp, "number") : null; + } + + calculateQuorum(votes: { + forVotes: bigint; + againstVotes: bigint; + abstainVotes: bigint; + }): bigint { + return votes.forVotes + votes.abstainVotes; + } +} diff --git a/apps/api/src/clients/op/abi/governor.ts b/apps/api/src/clients/op/abi/governor.ts new file mode 100644 index 000000000..04dac0163 --- /dev/null +++ b/apps/api/src/clients/op/abi/governor.ts @@ -0,0 +1,1134 @@ +export const GovernorAbi = [ + { inputs: [], stateMutability: "nonpayable", type: "constructor" }, + { inputs: [], name: "Empty", type: "error" }, + { inputs: [], name: "InvalidEmptyProposal", type: "error" }, + { inputs: [], name: "InvalidProposalExists", type: "error" }, + { inputs: [], name: "InvalidProposalId", type: "error" }, + { inputs: [], name: "InvalidProposalLength", type: "error" }, + { + inputs: [{ internalType: "uint8", name: "proposalType", type: "uint8" }], + name: "InvalidProposalType", + type: "error", + }, + { + inputs: [{ internalType: "address", name: "target", type: "address" }], + name: "InvalidRelayTarget", + type: "error", + }, + { inputs: [], name: "InvalidVoteType", type: "error" }, + { inputs: [], name: "InvalidVotesBelowThreshold", type: "error" }, + { inputs: [], name: "NotAlligator", type: "error" }, + { inputs: [], name: "NotManagerOrTimelock", type: "error" }, + { + anonymous: false, + inputs: [ + { indexed: false, internalType: "uint8", name: "version", type: "uint8" }, + ], + name: "Initialized", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "oldManager", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "newManager", + type: "address", + }, + ], + name: "ManagerSet", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "proposalId", + type: "uint256", + }, + ], + name: "ProposalCanceled", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "proposalId", + type: "uint256", + }, + { + indexed: false, + internalType: "address", + name: "proposer", + type: "address", + }, + { + indexed: false, + internalType: "address[]", + name: "targets", + type: "address[]", + }, + { + indexed: false, + internalType: "uint256[]", + name: "values", + type: "uint256[]", + }, + { + indexed: false, + internalType: "string[]", + name: "signatures", + type: "string[]", + }, + { + indexed: false, + internalType: "bytes[]", + name: "calldatas", + type: "bytes[]", + }, + { + indexed: false, + internalType: "uint256", + name: "startBlock", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "endBlock", + type: "uint256", + }, + { + indexed: false, + internalType: "string", + name: "description", + type: "string", + }, + ], + name: "ProposalCreated", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "uint256", + name: "proposalId", + type: "uint256", + }, + { + indexed: true, + internalType: "address", + name: "proposer", + type: "address", + }, + { + indexed: false, + internalType: "address[]", + name: "targets", + type: "address[]", + }, + { + indexed: false, + internalType: "uint256[]", + name: "values", + type: "uint256[]", + }, + { + indexed: false, + internalType: "string[]", + name: "signatures", + type: "string[]", + }, + { + indexed: false, + internalType: "bytes[]", + name: "calldatas", + type: "bytes[]", + }, + { + indexed: false, + internalType: "uint256", + name: "startBlock", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "endBlock", + type: "uint256", + }, + { + indexed: false, + internalType: "string", + name: "description", + type: "string", + }, + { + indexed: false, + internalType: "uint8", + name: "proposalType", + type: "uint8", + }, + ], + name: "ProposalCreated", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "uint256", + name: "proposalId", + type: "uint256", + }, + { + indexed: true, + internalType: "address", + name: "proposer", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "votingModule", + type: "address", + }, + { + indexed: false, + internalType: "bytes", + name: "proposalData", + type: "bytes", + }, + { + indexed: false, + internalType: "uint256", + name: "startBlock", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "endBlock", + type: "uint256", + }, + { + indexed: false, + internalType: "string", + name: "description", + type: "string", + }, + { + indexed: false, + internalType: "uint8", + name: "proposalType", + type: "uint8", + }, + ], + name: "ProposalCreated", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "proposalId", + type: "uint256", + }, + { + indexed: false, + internalType: "uint64", + name: "deadline", + type: "uint64", + }, + ], + name: "ProposalDeadlineUpdated", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "proposalId", + type: "uint256", + }, + ], + name: "ProposalExecuted", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "proposalId", + type: "uint256", + }, + { indexed: false, internalType: "uint256", name: "eta", type: "uint256" }, + ], + name: "ProposalQueued", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "oldProposalThreshold", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "newProposalThreshold", + type: "uint256", + }, + ], + name: "ProposalThresholdSet", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "uint256", + name: "proposalId", + type: "uint256", + }, + { + indexed: false, + internalType: "uint8", + name: "proposalType", + type: "uint8", + }, + ], + name: "ProposalTypeUpdated", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "oldTimelock", + type: "address", + }, + { + indexed: false, + internalType: "address", + name: "newTimelock", + type: "address", + }, + ], + name: "TimelockChange", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "voter", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "proposalId", + type: "uint256", + }, + { indexed: false, internalType: "uint8", name: "support", type: "uint8" }, + { + indexed: false, + internalType: "uint256", + name: "weight", + type: "uint256", + }, + { + indexed: false, + internalType: "string", + name: "reason", + type: "string", + }, + ], + name: "VoteCast", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "voter", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "proposalId", + type: "uint256", + }, + { indexed: false, internalType: "uint8", name: "support", type: "uint8" }, + { + indexed: false, + internalType: "uint256", + name: "weight", + type: "uint256", + }, + { + indexed: false, + internalType: "string", + name: "reason", + type: "string", + }, + { indexed: false, internalType: "bytes", name: "params", type: "bytes" }, + ], + name: "VoteCastWithParams", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "oldVotingDelay", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "newVotingDelay", + type: "uint256", + }, + ], + name: "VotingDelaySet", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "oldVotingPeriod", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "newVotingPeriod", + type: "uint256", + }, + ], + name: "VotingPeriodSet", + type: "event", + }, + { + inputs: [], + name: "BALLOT_TYPEHASH", + outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "COUNTING_MODE", + outputs: [{ internalType: "string", name: "", type: "string" }], + stateMutability: "pure", + type: "function", + }, + { + inputs: [], + name: "EXTENDED_BALLOT_TYPEHASH", + outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "PERCENT_DIVISOR", + outputs: [{ internalType: "uint16", name: "", type: "uint16" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "PROPOSAL_TYPES_CONFIGURATOR", + outputs: [ + { + internalType: "contract IProposalTypesConfigurator", + name: "", + type: "address", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "VERSION", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "pure", + type: "function", + }, + { + inputs: [], + name: "VOTABLE_SUPPLY_ORACLE", + outputs: [ + { + internalType: "contract IVotableSupplyOracle", + name: "", + type: "address", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "alligator", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "module", type: "address" }], + name: "approvedModules", + outputs: [{ internalType: "bool", name: "approved", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address[]", name: "targets", type: "address[]" }, + { internalType: "uint256[]", name: "values", type: "uint256[]" }, + { internalType: "bytes[]", name: "calldatas", type: "bytes[]" }, + { internalType: "bytes32", name: "descriptionHash", type: "bytes32" }, + ], + name: "cancel", + outputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "contract VotingModule", + name: "module", + type: "address", + }, + { internalType: "bytes", name: "proposalData", type: "bytes" }, + { internalType: "bytes32", name: "descriptionHash", type: "bytes32" }, + ], + name: "cancelWithModule", + outputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "uint8", name: "support", type: "uint8" }, + ], + name: "castVote", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "uint8", name: "support", type: "uint8" }, + { internalType: "uint8", name: "v", type: "uint8" }, + { internalType: "bytes32", name: "r", type: "bytes32" }, + { internalType: "bytes32", name: "s", type: "bytes32" }, + ], + name: "castVoteBySig", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "address", name: "voter", type: "address" }, + { internalType: "uint8", name: "support", type: "uint8" }, + { internalType: "string", name: "reason", type: "string" }, + { internalType: "uint256", name: "votes", type: "uint256" }, + { internalType: "bytes", name: "params", type: "bytes" }, + ], + name: "castVoteFromAlligator", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "uint8", name: "support", type: "uint8" }, + { internalType: "string", name: "reason", type: "string" }, + ], + name: "castVoteWithReason", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "uint8", name: "support", type: "uint8" }, + { internalType: "string", name: "reason", type: "string" }, + { internalType: "bytes", name: "params", type: "bytes" }, + ], + name: "castVoteWithReasonAndParams", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "uint8", name: "support", type: "uint8" }, + { internalType: "string", name: "reason", type: "string" }, + { internalType: "bytes", name: "params", type: "bytes" }, + { internalType: "uint8", name: "v", type: "uint8" }, + { internalType: "bytes32", name: "r", type: "bytes32" }, + { internalType: "bytes32", name: "s", type: "bytes32" }, + ], + name: "castVoteWithReasonAndParamsBySig", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "uint8", name: "proposalType", type: "uint8" }, + ], + name: "editProposalType", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address[]", name: "targets", type: "address[]" }, + { internalType: "uint256[]", name: "values", type: "uint256[]" }, + { internalType: "bytes[]", name: "calldatas", type: "bytes[]" }, + { internalType: "bytes32", name: "descriptionHash", type: "bytes32" }, + ], + name: "execute", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "payable", + type: "function", + }, + { + inputs: [ + { + internalType: "contract VotingModule", + name: "module", + type: "address", + }, + { internalType: "bytes", name: "proposalData", type: "bytes" }, + { internalType: "bytes32", name: "descriptionHash", type: "bytes32" }, + ], + name: "executeWithModule", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "payable", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + name: "getProposalType", + outputs: [{ internalType: "uint8", name: "", type: "uint8" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "account", type: "address" }, + { internalType: "uint256", name: "blockNumber", type: "uint256" }, + ], + name: "getVotes", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "account", type: "address" }, + { internalType: "uint256", name: "blockNumber", type: "uint256" }, + { internalType: "bytes", name: "params", type: "bytes" }, + ], + name: "getVotesWithParams", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "address", name: "account", type: "address" }, + ], + name: "hasVoted", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address[]", name: "targets", type: "address[]" }, + { internalType: "uint256[]", name: "values", type: "uint256[]" }, + { internalType: "bytes[]", name: "calldatas", type: "bytes[]" }, + { internalType: "bytes32", name: "descriptionHash", type: "bytes32" }, + ], + name: "hashProposal", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "pure", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "module", type: "address" }, + { internalType: "bytes", name: "proposalData", type: "bytes" }, + { internalType: "bytes32", name: "descriptionHash", type: "bytes32" }, + ], + name: "hashProposalWithModule", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "address", name: "account", type: "address" }, + { internalType: "uint256", name: "votes", type: "uint256" }, + { internalType: "uint256", name: "accountVotes", type: "uint256" }, + ], + name: "increaseWeightCast", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "contract IVotingToken", + name: "_votingToken", + type: "address", + }, + { + internalType: "contract IVotableSupplyOracle", + name: "_votableSupplyOracle", + type: "address", + }, + { internalType: "address", name: "_manager", type: "address" }, + { internalType: "address", name: "_alligator", type: "address" }, + { + internalType: "contract TimelockControllerUpgradeable", + name: "_timelockAddress", + type: "address", + }, + { + internalType: "contract IProposalTypesConfigurator", + name: "_proposalTypesConfigurator", + type: "address", + }, + { + components: [ + { internalType: "uint16", name: "quorum", type: "uint16" }, + { internalType: "uint16", name: "approvalThreshold", type: "uint16" }, + { internalType: "string", name: "name", type: "string" }, + { internalType: "string", name: "description", type: "string" }, + { internalType: "address", name: "module", type: "address" }, + ], + internalType: "struct IProposalTypesConfigurator.ProposalType[]", + name: "_proposalTypes", + type: "tuple[]", + }, + ], + name: "initialize", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "manager", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "name", + outputs: [{ internalType: "string", name: "", type: "string" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "", type: "address" }, + { internalType: "address", name: "", type: "address" }, + { internalType: "uint256[]", name: "", type: "uint256[]" }, + { internalType: "uint256[]", name: "", type: "uint256[]" }, + { internalType: "bytes", name: "", type: "bytes" }, + ], + name: "onERC1155BatchReceived", + outputs: [{ internalType: "bytes4", name: "", type: "bytes4" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "", type: "address" }, + { internalType: "address", name: "", type: "address" }, + { internalType: "uint256", name: "", type: "uint256" }, + { internalType: "uint256", name: "", type: "uint256" }, + { internalType: "bytes", name: "", type: "bytes" }, + ], + name: "onERC1155Received", + outputs: [{ internalType: "bytes4", name: "", type: "bytes4" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "", type: "address" }, + { internalType: "address", name: "", type: "address" }, + { internalType: "uint256", name: "", type: "uint256" }, + { internalType: "bytes", name: "", type: "bytes" }, + ], + name: "onERC721Received", + outputs: [{ internalType: "bytes4", name: "", type: "bytes4" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + name: "proposalDeadline", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + name: "proposalEta", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + name: "proposalSnapshot", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "proposalThreshold", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + name: "proposalVotes", + outputs: [ + { internalType: "uint256", name: "againstVotes", type: "uint256" }, + { internalType: "uint256", name: "forVotes", type: "uint256" }, + { internalType: "uint256", name: "abstainVotes", type: "uint256" }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address[]", name: "targets", type: "address[]" }, + { internalType: "uint256[]", name: "values", type: "uint256[]" }, + { internalType: "bytes[]", name: "calldatas", type: "bytes[]" }, + { internalType: "string", name: "description", type: "string" }, + ], + name: "propose", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address[]", name: "targets", type: "address[]" }, + { internalType: "uint256[]", name: "values", type: "uint256[]" }, + { internalType: "bytes[]", name: "calldatas", type: "bytes[]" }, + { internalType: "string", name: "description", type: "string" }, + { internalType: "uint8", name: "proposalType", type: "uint8" }, + ], + name: "propose", + outputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "contract VotingModule", + name: "module", + type: "address", + }, + { internalType: "bytes", name: "proposalData", type: "bytes" }, + { internalType: "string", name: "description", type: "string" }, + { internalType: "uint8", name: "proposalType", type: "uint8" }, + ], + name: "proposeWithModule", + outputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address[]", name: "targets", type: "address[]" }, + { internalType: "uint256[]", name: "values", type: "uint256[]" }, + { internalType: "bytes[]", name: "calldatas", type: "bytes[]" }, + { internalType: "bytes32", name: "descriptionHash", type: "bytes32" }, + ], + name: "queue", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "contract VotingModule", + name: "module", + type: "address", + }, + { internalType: "bytes", name: "proposalData", type: "bytes" }, + { internalType: "bytes32", name: "descriptionHash", type: "bytes32" }, + ], + name: "queueWithModule", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + name: "quorum", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "_alligator", type: "address" }, + { + internalType: "address", + name: "_votableSupplyOracle", + type: "address", + }, + { + internalType: "address", + name: "_proposalTypesConfigurator", + type: "address", + }, + { + internalType: "contract TimelockControllerUpgradeable", + name: "_timelockAddress", + type: "address", + }, + ], + name: "reinitialize", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "target", type: "address" }, + { internalType: "uint256", name: "value", type: "uint256" }, + { internalType: "bytes", name: "data", type: "bytes" }, + ], + name: "relay", + outputs: [], + stateMutability: "payable", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "_newManager", type: "address" }], + name: "setManager", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "module", type: "address" }, + { internalType: "bool", name: "approved", type: "bool" }, + ], + name: "setModuleApproval", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "uint64", name: "deadline", type: "uint64" }, + ], + name: "setProposalDeadline", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "uint256", + name: "newProposalThreshold", + type: "uint256", + }, + ], + name: "setProposalThreshold", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "newVotingDelay", type: "uint256" }, + ], + name: "setVotingDelay", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "newVotingPeriod", type: "uint256" }, + ], + name: "setVotingPeriod", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + name: "state", + outputs: [ + { + internalType: "enum IGovernorUpgradeable.ProposalState", + name: "", + type: "uint8", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "bytes4", name: "interfaceId", type: "bytes4" }], + name: "supportsInterface", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "timelock", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "token", + outputs: [ + { internalType: "contract IVotingToken", name: "", type: "address" }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "contract TimelockControllerUpgradeable", + name: "newTimelock", + type: "address", + }, + ], + name: "updateTimelock", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "version", + outputs: [{ internalType: "string", name: "", type: "string" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "votableSupply", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "blockNumber", type: "uint256" }], + name: "votableSupply", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "votingDelay", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "votingPeriod", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "address", name: "account", type: "address" }, + ], + name: "weightCast", + outputs: [{ internalType: "uint256", name: "votes", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { stateMutability: "payable", type: "receive" }, +] as const; diff --git a/apps/api/src/clients/op/abi/index.ts b/apps/api/src/clients/op/abi/index.ts new file mode 100644 index 000000000..1fe9f7622 --- /dev/null +++ b/apps/api/src/clients/op/abi/index.ts @@ -0,0 +1,3 @@ +export { GovernorAbi } from "./governor"; +export { LegacyGovernorAbi } from "./legacyGovernor"; +export { TokenAbi } from "./token"; diff --git a/apps/api/src/clients/op/abi/legacyGovernor.ts b/apps/api/src/clients/op/abi/legacyGovernor.ts new file mode 100644 index 000000000..f08923241 --- /dev/null +++ b/apps/api/src/clients/op/abi/legacyGovernor.ts @@ -0,0 +1,1064 @@ +export const LegacyGovernorAbi = [ + { inputs: [], name: "Empty", type: "error" }, + { inputs: [], name: "InvalidProposalId", type: "error" }, + { + inputs: [{ internalType: "uint8", name: "proposalType", type: "uint8" }], + name: "InvalidProposalType", + type: "error", + }, + { + anonymous: false, + inputs: [ + { indexed: false, internalType: "uint8", name: "version", type: "uint8" }, + ], + name: "Initialized", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "proposalId", + type: "uint256", + }, + ], + name: "ProposalCanceled", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "uint256", + name: "proposalId", + type: "uint256", + }, + { + indexed: true, + internalType: "address", + name: "proposer", + type: "address", + }, + { + indexed: false, + internalType: "address[]", + name: "targets", + type: "address[]", + }, + { + indexed: false, + internalType: "uint256[]", + name: "values", + type: "uint256[]", + }, + { + indexed: false, + internalType: "string[]", + name: "signatures", + type: "string[]", + }, + { + indexed: false, + internalType: "bytes[]", + name: "calldatas", + type: "bytes[]", + }, + { + indexed: false, + internalType: "uint256", + name: "startBlock", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "endBlock", + type: "uint256", + }, + { + indexed: false, + internalType: "string", + name: "description", + type: "string", + }, + { + indexed: false, + internalType: "uint8", + name: "proposalType", + type: "uint8", + }, + ], + name: "ProposalCreated", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "uint256", + name: "proposalId", + type: "uint256", + }, + { + indexed: true, + internalType: "address", + name: "proposer", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "votingModule", + type: "address", + }, + { + indexed: false, + internalType: "bytes", + name: "proposalData", + type: "bytes", + }, + { + indexed: false, + internalType: "uint256", + name: "startBlock", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "endBlock", + type: "uint256", + }, + { + indexed: false, + internalType: "string", + name: "description", + type: "string", + }, + { + indexed: false, + internalType: "uint8", + name: "proposalType", + type: "uint8", + }, + ], + name: "ProposalCreated", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "proposalId", + type: "uint256", + }, + { + indexed: false, + internalType: "address", + name: "proposer", + type: "address", + }, + { + indexed: false, + internalType: "address", + name: "votingModule", + type: "address", + }, + { + indexed: false, + internalType: "bytes", + name: "proposalData", + type: "bytes", + }, + { + indexed: false, + internalType: "uint256", + name: "startBlock", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "endBlock", + type: "uint256", + }, + { + indexed: false, + internalType: "string", + name: "description", + type: "string", + }, + ], + name: "ProposalCreated", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "proposalId", + type: "uint256", + }, + { + indexed: false, + internalType: "address", + name: "proposer", + type: "address", + }, + { + indexed: false, + internalType: "address[]", + name: "targets", + type: "address[]", + }, + { + indexed: false, + internalType: "uint256[]", + name: "values", + type: "uint256[]", + }, + { + indexed: false, + internalType: "string[]", + name: "signatures", + type: "string[]", + }, + { + indexed: false, + internalType: "bytes[]", + name: "calldatas", + type: "bytes[]", + }, + { + indexed: false, + internalType: "uint256", + name: "startBlock", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "endBlock", + type: "uint256", + }, + { + indexed: false, + internalType: "string", + name: "description", + type: "string", + }, + ], + name: "ProposalCreated", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "proposalId", + type: "uint256", + }, + { + indexed: false, + internalType: "uint64", + name: "deadline", + type: "uint64", + }, + ], + name: "ProposalDeadlineUpdated", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "proposalId", + type: "uint256", + }, + ], + name: "ProposalExecuted", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "oldProposalThreshold", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "newProposalThreshold", + type: "uint256", + }, + ], + name: "ProposalThresholdSet", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "uint256", + name: "proposalId", + type: "uint256", + }, + { + indexed: false, + internalType: "uint8", + name: "proposalType", + type: "uint8", + }, + ], + name: "ProposalTypeUpdated", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "oldQuorumNumerator", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "newQuorumNumerator", + type: "uint256", + }, + ], + name: "QuorumNumeratorUpdated", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "voter", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "proposalId", + type: "uint256", + }, + { indexed: false, internalType: "uint8", name: "support", type: "uint8" }, + { + indexed: false, + internalType: "uint256", + name: "weight", + type: "uint256", + }, + { + indexed: false, + internalType: "string", + name: "reason", + type: "string", + }, + ], + name: "VoteCast", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "voter", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "proposalId", + type: "uint256", + }, + { indexed: false, internalType: "uint8", name: "support", type: "uint8" }, + { + indexed: false, + internalType: "uint256", + name: "weight", + type: "uint256", + }, + { + indexed: false, + internalType: "string", + name: "reason", + type: "string", + }, + { indexed: false, internalType: "bytes", name: "params", type: "bytes" }, + ], + name: "VoteCastWithParams", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "oldVotingDelay", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "newVotingDelay", + type: "uint256", + }, + ], + name: "VotingDelaySet", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "oldVotingPeriod", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "newVotingPeriod", + type: "uint256", + }, + ], + name: "VotingPeriodSet", + type: "event", + }, + { + inputs: [], + name: "ALLIGATOR", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "BALLOT_TYPEHASH", + outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "COUNTING_MODE", + outputs: [{ internalType: "string", name: "", type: "string" }], + stateMutability: "pure", + type: "function", + }, + { + inputs: [], + name: "EXTENDED_BALLOT_TYPEHASH", + outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "PERCENT_DIVISOR", + outputs: [{ internalType: "uint16", name: "", type: "uint16" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "PROPOSAL_TYPES_CONFIGURATOR", + outputs: [ + { + internalType: "contract IProposalTypesConfigurator", + name: "", + type: "address", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "VERSION", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "pure", + type: "function", + }, + { + inputs: [], + name: "VOTABLE_SUPPLY_ORACLE", + outputs: [ + { + internalType: "contract IVotableSupplyOracle", + name: "", + type: "address", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "module", type: "address" }], + name: "approvedModules", + outputs: [{ internalType: "bool", name: "approved", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address[]", name: "targets", type: "address[]" }, + { internalType: "uint256[]", name: "values", type: "uint256[]" }, + { internalType: "bytes[]", name: "calldatas", type: "bytes[]" }, + { internalType: "bytes32", name: "descriptionHash", type: "bytes32" }, + ], + name: "cancel", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "contract VotingModule", + name: "module", + type: "address", + }, + { internalType: "bytes", name: "proposalData", type: "bytes" }, + { internalType: "bytes32", name: "descriptionHash", type: "bytes32" }, + ], + name: "cancelWithModule", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "uint8", name: "support", type: "uint8" }, + ], + name: "castVote", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "uint8", name: "support", type: "uint8" }, + { internalType: "uint8", name: "v", type: "uint8" }, + { internalType: "bytes32", name: "r", type: "bytes32" }, + { internalType: "bytes32", name: "s", type: "bytes32" }, + ], + name: "castVoteBySig", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "address", name: "voter", type: "address" }, + { internalType: "uint8", name: "support", type: "uint8" }, + { internalType: "string", name: "reason", type: "string" }, + { internalType: "uint256", name: "votes", type: "uint256" }, + { internalType: "bytes", name: "params", type: "bytes" }, + ], + name: "castVoteFromAlligator", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "uint8", name: "support", type: "uint8" }, + { internalType: "string", name: "reason", type: "string" }, + ], + name: "castVoteWithReason", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "uint8", name: "support", type: "uint8" }, + { internalType: "string", name: "reason", type: "string" }, + { internalType: "bytes", name: "params", type: "bytes" }, + ], + name: "castVoteWithReasonAndParams", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "uint8", name: "support", type: "uint8" }, + { internalType: "string", name: "reason", type: "string" }, + { internalType: "bytes", name: "params", type: "bytes" }, + { internalType: "uint8", name: "v", type: "uint8" }, + { internalType: "bytes32", name: "r", type: "bytes32" }, + { internalType: "bytes32", name: "s", type: "bytes32" }, + ], + name: "castVoteWithReasonAndParamsBySig", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "uint8", name: "proposalType", type: "uint8" }, + ], + name: "editProposalType", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address[]", name: "targets", type: "address[]" }, + { internalType: "uint256[]", name: "values", type: "uint256[]" }, + { internalType: "bytes[]", name: "calldatas", type: "bytes[]" }, + { internalType: "bytes32", name: "descriptionHash", type: "bytes32" }, + ], + name: "execute", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "payable", + type: "function", + }, + { + inputs: [ + { + internalType: "contract VotingModule", + name: "module", + type: "address", + }, + { internalType: "bytes", name: "proposalData", type: "bytes" }, + { internalType: "bytes32", name: "descriptionHash", type: "bytes32" }, + ], + name: "executeWithModule", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "payable", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + name: "getProposalType", + outputs: [{ internalType: "uint8", name: "", type: "uint8" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "account", type: "address" }, + { internalType: "uint256", name: "blockNumber", type: "uint256" }, + ], + name: "getVotes", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "account", type: "address" }, + { internalType: "uint256", name: "blockNumber", type: "uint256" }, + { internalType: "bytes", name: "params", type: "bytes" }, + ], + name: "getVotesWithParams", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "address", name: "account", type: "address" }, + ], + name: "hasVoted", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address[]", name: "targets", type: "address[]" }, + { internalType: "uint256[]", name: "values", type: "uint256[]" }, + { internalType: "bytes[]", name: "calldatas", type: "bytes[]" }, + { internalType: "bytes32", name: "descriptionHash", type: "bytes32" }, + ], + name: "hashProposal", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "pure", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "module", type: "address" }, + { internalType: "bytes", name: "proposalData", type: "bytes" }, + { internalType: "bytes32", name: "descriptionHash", type: "bytes32" }, + ], + name: "hashProposalWithModule", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "address", name: "account", type: "address" }, + { internalType: "uint256", name: "votes", type: "uint256" }, + { internalType: "uint256", name: "accountVotes", type: "uint256" }, + ], + name: "increaseWeightCast", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "manager", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "name", + outputs: [{ internalType: "string", name: "", type: "string" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "", type: "address" }, + { internalType: "address", name: "", type: "address" }, + { internalType: "uint256[]", name: "", type: "uint256[]" }, + { internalType: "uint256[]", name: "", type: "uint256[]" }, + { internalType: "bytes", name: "", type: "bytes" }, + ], + name: "onERC1155BatchReceived", + outputs: [{ internalType: "bytes4", name: "", type: "bytes4" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "", type: "address" }, + { internalType: "address", name: "", type: "address" }, + { internalType: "uint256", name: "", type: "uint256" }, + { internalType: "uint256", name: "", type: "uint256" }, + { internalType: "bytes", name: "", type: "bytes" }, + ], + name: "onERC1155Received", + outputs: [{ internalType: "bytes4", name: "", type: "bytes4" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "", type: "address" }, + { internalType: "address", name: "", type: "address" }, + { internalType: "uint256", name: "", type: "uint256" }, + { internalType: "bytes", name: "", type: "bytes" }, + ], + name: "onERC721Received", + outputs: [{ internalType: "bytes4", name: "", type: "bytes4" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + name: "proposalDeadline", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + name: "proposalSnapshot", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "proposalThreshold", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + name: "proposalVotes", + outputs: [ + { internalType: "uint256", name: "againstVotes", type: "uint256" }, + { internalType: "uint256", name: "forVotes", type: "uint256" }, + { internalType: "uint256", name: "abstainVotes", type: "uint256" }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address[]", name: "targets", type: "address[]" }, + { internalType: "uint256[]", name: "values", type: "uint256[]" }, + { internalType: "bytes[]", name: "calldatas", type: "bytes[]" }, + { internalType: "string", name: "description", type: "string" }, + ], + name: "propose", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address[]", name: "targets", type: "address[]" }, + { internalType: "uint256[]", name: "values", type: "uint256[]" }, + { internalType: "bytes[]", name: "calldatas", type: "bytes[]" }, + { internalType: "string", name: "description", type: "string" }, + { internalType: "uint8", name: "proposalType", type: "uint8" }, + ], + name: "propose", + outputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "contract VotingModule", + name: "module", + type: "address", + }, + { internalType: "bytes", name: "proposalData", type: "bytes" }, + { internalType: "string", name: "description", type: "string" }, + ], + name: "proposeWithModule", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "contract VotingModule", + name: "module", + type: "address", + }, + { internalType: "bytes", name: "proposalData", type: "bytes" }, + { internalType: "string", name: "description", type: "string" }, + { internalType: "uint8", name: "proposalType", type: "uint8" }, + ], + name: "proposeWithModule", + outputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + name: "quorum", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "quorumDenominator", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "blockNumber", type: "uint256" }], + name: "quorumNumerator", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "quorumNumerator", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "target", type: "address" }, + { internalType: "uint256", name: "value", type: "uint256" }, + { internalType: "bytes", name: "data", type: "bytes" }, + ], + name: "relay", + outputs: [], + stateMutability: "payable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "module", type: "address" }, + { internalType: "bool", name: "approved", type: "bool" }, + ], + name: "setModuleApproval", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "uint64", name: "deadline", type: "uint64" }, + ], + name: "setProposalDeadline", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "uint256", + name: "newProposalThreshold", + type: "uint256", + }, + ], + name: "setProposalThreshold", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "newVotingDelay", type: "uint256" }, + ], + name: "setVotingDelay", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "newVotingPeriod", type: "uint256" }, + ], + name: "setVotingPeriod", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + name: "state", + outputs: [ + { + internalType: "enum IGovernorUpgradeable.ProposalState", + name: "", + type: "uint8", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "bytes4", name: "interfaceId", type: "bytes4" }], + name: "supportsInterface", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "token", + outputs: [ + { internalType: "contract IVotesUpgradeable", name: "", type: "address" }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "token_unused", + outputs: [ + { internalType: "contract IVotesUpgradeable", name: "", type: "address" }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "newQuorumNumerator", type: "uint256" }, + ], + name: "updateQuorumNumerator", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "version", + outputs: [{ internalType: "string", name: "", type: "string" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "votableSupply", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "blockNumber", type: "uint256" }], + name: "votableSupply", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "votingDelay", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "votingPeriod", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "address", name: "account", type: "address" }, + ], + name: "weightCast", + outputs: [{ internalType: "uint256", name: "votes", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { stateMutability: "payable", type: "receive" }, +] as const; diff --git a/apps/api/src/clients/op/abi/token.ts b/apps/api/src/clients/op/abi/token.ts new file mode 100644 index 000000000..d8c679aac --- /dev/null +++ b/apps/api/src/clients/op/abi/token.ts @@ -0,0 +1,364 @@ +export const TokenAbi = [ + { inputs: [], stateMutability: "nonpayable", type: "constructor" }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "owner", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "spender", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "value", + type: "uint256", + }, + ], + name: "Approval", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "delegator", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "fromDelegate", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "toDelegate", + type: "address", + }, + ], + name: "DelegateChanged", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "delegate", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "previousBalance", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "newBalance", + type: "uint256", + }, + ], + name: "DelegateVotesChanged", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "previousOwner", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "newOwner", + type: "address", + }, + ], + name: "OwnershipTransferred", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "address", name: "from", type: "address" }, + { indexed: true, internalType: "address", name: "to", type: "address" }, + { + indexed: false, + internalType: "uint256", + name: "value", + type: "uint256", + }, + ], + name: "Transfer", + type: "event", + }, + { + inputs: [], + name: "DOMAIN_SEPARATOR", + outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "owner", type: "address" }, + { internalType: "address", name: "spender", type: "address" }, + ], + name: "allowance", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "spender", type: "address" }, + { internalType: "uint256", name: "amount", type: "uint256" }, + ], + name: "approve", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "account", type: "address" }], + name: "balanceOf", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "amount", type: "uint256" }], + name: "burn", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "account", type: "address" }, + { internalType: "uint256", name: "amount", type: "uint256" }, + ], + name: "burnFrom", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "account", type: "address" }, + { internalType: "uint32", name: "pos", type: "uint32" }, + ], + name: "checkpoints", + outputs: [ + { + components: [ + { internalType: "uint32", name: "fromBlock", type: "uint32" }, + { internalType: "uint224", name: "votes", type: "uint224" }, + ], + internalType: "struct ERC20Votes.Checkpoint", + name: "", + type: "tuple", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "decimals", + outputs: [{ internalType: "uint8", name: "", type: "uint8" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "spender", type: "address" }, + { internalType: "uint256", name: "subtractedValue", type: "uint256" }, + ], + name: "decreaseAllowance", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "delegatee", type: "address" }], + name: "delegate", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "delegatee", type: "address" }, + { internalType: "uint256", name: "nonce", type: "uint256" }, + { internalType: "uint256", name: "expiry", type: "uint256" }, + { internalType: "uint8", name: "v", type: "uint8" }, + { internalType: "bytes32", name: "r", type: "bytes32" }, + { internalType: "bytes32", name: "s", type: "bytes32" }, + ], + name: "delegateBySig", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "account", type: "address" }], + name: "delegates", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "blockNumber", type: "uint256" }], + name: "getPastTotalSupply", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "account", type: "address" }, + { internalType: "uint256", name: "blockNumber", type: "uint256" }, + ], + name: "getPastVotes", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "account", type: "address" }], + name: "getVotes", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "spender", type: "address" }, + { internalType: "uint256", name: "addedValue", type: "uint256" }, + ], + name: "increaseAllowance", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "_account", type: "address" }, + { internalType: "uint256", name: "_amount", type: "uint256" }, + ], + name: "mint", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "name", + outputs: [{ internalType: "string", name: "", type: "string" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "owner", type: "address" }], + name: "nonces", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "account", type: "address" }], + name: "numCheckpoints", + outputs: [{ internalType: "uint32", name: "", type: "uint32" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "owner", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "owner", type: "address" }, + { internalType: "address", name: "spender", type: "address" }, + { internalType: "uint256", name: "value", type: "uint256" }, + { internalType: "uint256", name: "deadline", type: "uint256" }, + { internalType: "uint8", name: "v", type: "uint8" }, + { internalType: "bytes32", name: "r", type: "bytes32" }, + { internalType: "bytes32", name: "s", type: "bytes32" }, + ], + name: "permit", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "renounceOwnership", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "symbol", + outputs: [{ internalType: "string", name: "", type: "string" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "totalSupply", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "to", type: "address" }, + { internalType: "uint256", name: "amount", type: "uint256" }, + ], + name: "transfer", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "from", type: "address" }, + { internalType: "address", name: "to", type: "address" }, + { internalType: "uint256", name: "amount", type: "uint256" }, + ], + name: "transferFrom", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "newOwner", type: "address" }], + name: "transferOwnership", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, +] as const; diff --git a/apps/api/src/clients/op/index.ts b/apps/api/src/clients/op/index.ts new file mode 100644 index 000000000..bd95930bf --- /dev/null +++ b/apps/api/src/clients/op/index.ts @@ -0,0 +1,97 @@ +import { + Account, + Address, + Chain, + Client, + fromHex, + toHex, + Transport, +} from "viem"; +import { readContract } from "viem/actions"; + +import { DAOClient } from "@/interfaces/client"; +import { GovernorAbi } from "./abi"; +import { GovernorBase } from "../governor.base"; + +export class OPClient< + TTransport extends Transport = Transport, + TChain extends Chain = Chain, + TAccount extends Account | undefined = Account | undefined, + > + extends GovernorBase + implements DAOClient +{ + private abi: typeof GovernorAbi; + private address: Address; + + constructor(client: Client, address: Address) { + super(client); + this.address = address; + this.abi = GovernorAbi; + } + + getDaoId(): string { + return "OP"; + } + + async getQuorum(proposalId: string | null): Promise { + if (!proposalId) return 0n; + return readContract(this.client, { + abi: this.abi, + address: this.address, + functionName: "quorum", + args: [BigInt(proposalId)], + }); + } + + async getProposalThreshold(): Promise { + return readContract(this.client, { + abi: this.abi, + address: this.address, + functionName: "proposalThreshold", + }); + } + + async getVotingDelay(): Promise { + return readContract(this.client, { + abi: this.abi, + address: this.address, + functionName: "votingDelay", + }); + } + + async getVotingPeriod(): Promise { + return readContract(this.client, { + abi: this.abi, + address: this.address, + functionName: "votingPeriod", + }); + } + + async getTimelockDelay(): Promise { + return 0n; + } + + async getCurrentBlockNumber(): Promise { + const result = await this.client.request({ + method: "eth_blockNumber", + }); + return fromHex(result, "number"); + } + + async getBlockTime(blockNumber: number): Promise { + const block = await this.client.request({ + method: "eth_getBlockByNumber", + params: [toHex(blockNumber), false], + }); + return block?.timestamp ? fromHex(block.timestamp, "number") : null; + } + + calculateQuorum(votes: { + forVotes: bigint; + againstVotes: bigint; + abstainVotes: bigint; + }): bigint { + return votes.forVotes + votes.againstVotes + votes.abstainVotes; + } +} diff --git a/apps/api/src/clients/scr/abi/governor.ts b/apps/api/src/clients/scr/abi/governor.ts new file mode 100644 index 000000000..a05fba693 --- /dev/null +++ b/apps/api/src/clients/scr/abi/governor.ts @@ -0,0 +1,1124 @@ +export const GovernorAbi = [ + { inputs: [], stateMutability: "nonpayable", type: "constructor" }, + { inputs: [], name: "Empty", type: "error" }, + { inputs: [], name: "InvalidProposalId", type: "error" }, + { + inputs: [{ internalType: "uint8", name: "proposalType", type: "uint8" }], + name: "InvalidProposalType", + type: "error", + }, + { + inputs: [{ internalType: "address", name: "target", type: "address" }], + name: "InvalidRelayTarget", + type: "error", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "oldAdmin", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "newAdmin", + type: "address", + }, + ], + name: "AdminSet", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: false, internalType: "uint8", name: "version", type: "uint8" }, + ], + name: "Initialized", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "oldManager", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "newManager", + type: "address", + }, + ], + name: "ManagerSet", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "proposalId", + type: "uint256", + }, + ], + name: "ProposalCanceled", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "proposalId", + type: "uint256", + }, + { + indexed: false, + internalType: "address", + name: "proposer", + type: "address", + }, + { + indexed: false, + internalType: "address[]", + name: "targets", + type: "address[]", + }, + { + indexed: false, + internalType: "uint256[]", + name: "values", + type: "uint256[]", + }, + { + indexed: false, + internalType: "string[]", + name: "signatures", + type: "string[]", + }, + { + indexed: false, + internalType: "bytes[]", + name: "calldatas", + type: "bytes[]", + }, + { + indexed: false, + internalType: "uint256", + name: "startBlock", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "endBlock", + type: "uint256", + }, + { + indexed: false, + internalType: "string", + name: "description", + type: "string", + }, + ], + name: "ProposalCreated", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "proposalId", + type: "uint256", + }, + { + indexed: false, + internalType: "address", + name: "proposer", + type: "address", + }, + { + indexed: false, + internalType: "address", + name: "votingModule", + type: "address", + }, + { + indexed: false, + internalType: "bytes", + name: "proposalData", + type: "bytes", + }, + { + indexed: false, + internalType: "uint256", + name: "startBlock", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "endBlock", + type: "uint256", + }, + { + indexed: false, + internalType: "string", + name: "description", + type: "string", + }, + ], + name: "ProposalCreated", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "uint256", + name: "proposalId", + type: "uint256", + }, + { + indexed: true, + internalType: "address", + name: "proposer", + type: "address", + }, + { + indexed: false, + internalType: "address[]", + name: "targets", + type: "address[]", + }, + { + indexed: false, + internalType: "uint256[]", + name: "values", + type: "uint256[]", + }, + { + indexed: false, + internalType: "string[]", + name: "signatures", + type: "string[]", + }, + { + indexed: false, + internalType: "bytes[]", + name: "calldatas", + type: "bytes[]", + }, + { + indexed: false, + internalType: "uint256", + name: "startBlock", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "endBlock", + type: "uint256", + }, + { + indexed: false, + internalType: "string", + name: "description", + type: "string", + }, + { + indexed: false, + internalType: "uint8", + name: "proposalType", + type: "uint8", + }, + ], + name: "ProposalCreated", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "uint256", + name: "proposalId", + type: "uint256", + }, + { + indexed: true, + internalType: "address", + name: "proposer", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "votingModule", + type: "address", + }, + { + indexed: false, + internalType: "bytes", + name: "proposalData", + type: "bytes", + }, + { + indexed: false, + internalType: "uint256", + name: "startBlock", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "endBlock", + type: "uint256", + }, + { + indexed: false, + internalType: "string", + name: "description", + type: "string", + }, + { + indexed: false, + internalType: "uint8", + name: "proposalType", + type: "uint8", + }, + ], + name: "ProposalCreated", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "proposalId", + type: "uint256", + }, + { + indexed: false, + internalType: "uint64", + name: "deadline", + type: "uint64", + }, + ], + name: "ProposalDeadlineUpdated", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "proposalId", + type: "uint256", + }, + ], + name: "ProposalExecuted", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "proposalId", + type: "uint256", + }, + { indexed: false, internalType: "uint256", name: "eta", type: "uint256" }, + ], + name: "ProposalQueued", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "oldProposalThreshold", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "newProposalThreshold", + type: "uint256", + }, + ], + name: "ProposalThresholdSet", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "uint256", + name: "proposalId", + type: "uint256", + }, + { + indexed: false, + internalType: "uint8", + name: "proposalType", + type: "uint8", + }, + ], + name: "ProposalTypeUpdated", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "oldTimelock", + type: "address", + }, + { + indexed: false, + internalType: "address", + name: "newTimelock", + type: "address", + }, + ], + name: "TimelockChange", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "voter", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "proposalId", + type: "uint256", + }, + { indexed: false, internalType: "uint8", name: "support", type: "uint8" }, + { + indexed: false, + internalType: "uint256", + name: "weight", + type: "uint256", + }, + { + indexed: false, + internalType: "string", + name: "reason", + type: "string", + }, + ], + name: "VoteCast", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "voter", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "proposalId", + type: "uint256", + }, + { indexed: false, internalType: "uint8", name: "support", type: "uint8" }, + { + indexed: false, + internalType: "uint256", + name: "weight", + type: "uint256", + }, + { + indexed: false, + internalType: "string", + name: "reason", + type: "string", + }, + { indexed: false, internalType: "bytes", name: "params", type: "bytes" }, + ], + name: "VoteCastWithParams", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "oldVotingDelay", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "newVotingDelay", + type: "uint256", + }, + ], + name: "VotingDelaySet", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "oldVotingPeriod", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "newVotingPeriod", + type: "uint256", + }, + ], + name: "VotingPeriodSet", + type: "event", + }, + { + inputs: [], + name: "BALLOT_TYPEHASH", + outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "COUNTING_MODE", + outputs: [{ internalType: "string", name: "", type: "string" }], + stateMutability: "pure", + type: "function", + }, + { + inputs: [], + name: "EXTENDED_BALLOT_TYPEHASH", + outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "PERCENT_DIVISOR", + outputs: [{ internalType: "uint16", name: "", type: "uint16" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "PROPOSAL_TYPES_CONFIGURATOR", + outputs: [ + { + internalType: "contract IProposalTypesConfigurator", + name: "", + type: "address", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "VERSION", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "pure", + type: "function", + }, + { + inputs: [], + name: "admin", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "module", type: "address" }], + name: "approvedModules", + outputs: [{ internalType: "bool", name: "approved", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address[]", name: "targets", type: "address[]" }, + { internalType: "uint256[]", name: "values", type: "uint256[]" }, + { internalType: "bytes[]", name: "calldatas", type: "bytes[]" }, + { internalType: "bytes32", name: "descriptionHash", type: "bytes32" }, + ], + name: "cancel", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "contract VotingModule", + name: "module", + type: "address", + }, + { internalType: "bytes", name: "proposalData", type: "bytes" }, + { internalType: "bytes32", name: "descriptionHash", type: "bytes32" }, + ], + name: "cancelWithModule", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "uint8", name: "support", type: "uint8" }, + ], + name: "castVote", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "uint8", name: "support", type: "uint8" }, + { internalType: "uint8", name: "v", type: "uint8" }, + { internalType: "bytes32", name: "r", type: "bytes32" }, + { internalType: "bytes32", name: "s", type: "bytes32" }, + ], + name: "castVoteBySig", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "uint8", name: "support", type: "uint8" }, + { internalType: "string", name: "reason", type: "string" }, + ], + name: "castVoteWithReason", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "uint8", name: "support", type: "uint8" }, + { internalType: "string", name: "reason", type: "string" }, + { internalType: "bytes", name: "params", type: "bytes" }, + ], + name: "castVoteWithReasonAndParams", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "uint8", name: "support", type: "uint8" }, + { internalType: "string", name: "reason", type: "string" }, + { internalType: "bytes", name: "params", type: "bytes" }, + { internalType: "uint8", name: "v", type: "uint8" }, + { internalType: "bytes32", name: "r", type: "bytes32" }, + { internalType: "bytes32", name: "s", type: "bytes32" }, + ], + name: "castVoteWithReasonAndParamsBySig", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "uint8", name: "proposalType", type: "uint8" }, + ], + name: "editProposalType", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address[]", name: "targets", type: "address[]" }, + { internalType: "uint256[]", name: "values", type: "uint256[]" }, + { internalType: "bytes[]", name: "calldatas", type: "bytes[]" }, + { internalType: "bytes32", name: "descriptionHash", type: "bytes32" }, + ], + name: "execute", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "payable", + type: "function", + }, + { + inputs: [ + { + internalType: "contract VotingModule", + name: "module", + type: "address", + }, + { internalType: "bytes", name: "proposalData", type: "bytes" }, + { internalType: "bytes32", name: "descriptionHash", type: "bytes32" }, + ], + name: "executeWithModule", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "payable", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + name: "getProposalType", + outputs: [{ internalType: "uint8", name: "", type: "uint8" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "account", type: "address" }, + { internalType: "uint256", name: "blockNumber", type: "uint256" }, + ], + name: "getVotes", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "account", type: "address" }, + { internalType: "uint256", name: "blockNumber", type: "uint256" }, + { internalType: "bytes", name: "params", type: "bytes" }, + ], + name: "getVotesWithParams", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "address", name: "account", type: "address" }, + ], + name: "hasVoted", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address[]", name: "targets", type: "address[]" }, + { internalType: "uint256[]", name: "values", type: "uint256[]" }, + { internalType: "bytes[]", name: "calldatas", type: "bytes[]" }, + { internalType: "bytes32", name: "descriptionHash", type: "bytes32" }, + ], + name: "hashProposal", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "pure", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "module", type: "address" }, + { internalType: "bytes", name: "proposalData", type: "bytes" }, + { internalType: "bytes32", name: "descriptionHash", type: "bytes32" }, + ], + name: "hashProposalWithModule", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "contract IVotesUpgradeable", + name: "_votingToken", + type: "address", + }, + { internalType: "address", name: "_admin", type: "address" }, + { internalType: "address", name: "_manager", type: "address" }, + { + internalType: "contract TimelockControllerUpgradeable", + name: "_timelock", + type: "address", + }, + { + internalType: "contract IProposalTypesConfigurator", + name: "_proposalTypesConfigurator", + type: "address", + }, + { + components: [ + { internalType: "uint16", name: "quorum", type: "uint16" }, + { internalType: "uint16", name: "approvalThreshold", type: "uint16" }, + { internalType: "string", name: "name", type: "string" }, + { internalType: "address", name: "module", type: "address" }, + ], + internalType: "struct IProposalTypesConfigurator.ProposalType[]", + name: "_proposalTypes", + type: "tuple[]", + }, + ], + name: "initialize", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "manager", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "name", + outputs: [{ internalType: "string", name: "", type: "string" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "", type: "address" }, + { internalType: "address", name: "", type: "address" }, + { internalType: "uint256[]", name: "", type: "uint256[]" }, + { internalType: "uint256[]", name: "", type: "uint256[]" }, + { internalType: "bytes", name: "", type: "bytes" }, + ], + name: "onERC1155BatchReceived", + outputs: [{ internalType: "bytes4", name: "", type: "bytes4" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "", type: "address" }, + { internalType: "address", name: "", type: "address" }, + { internalType: "uint256", name: "", type: "uint256" }, + { internalType: "uint256", name: "", type: "uint256" }, + { internalType: "bytes", name: "", type: "bytes" }, + ], + name: "onERC1155Received", + outputs: [{ internalType: "bytes4", name: "", type: "bytes4" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "", type: "address" }, + { internalType: "address", name: "", type: "address" }, + { internalType: "uint256", name: "", type: "uint256" }, + { internalType: "bytes", name: "", type: "bytes" }, + ], + name: "onERC721Received", + outputs: [{ internalType: "bytes4", name: "", type: "bytes4" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + name: "proposalDeadline", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + name: "proposalEta", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + name: "proposalSnapshot", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "proposalThreshold", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + name: "proposalVotes", + outputs: [ + { internalType: "uint256", name: "againstVotes", type: "uint256" }, + { internalType: "uint256", name: "forVotes", type: "uint256" }, + { internalType: "uint256", name: "abstainVotes", type: "uint256" }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address[]", name: "targets", type: "address[]" }, + { internalType: "uint256[]", name: "values", type: "uint256[]" }, + { internalType: "bytes[]", name: "calldatas", type: "bytes[]" }, + { internalType: "string", name: "description", type: "string" }, + ], + name: "propose", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address[]", name: "targets", type: "address[]" }, + { internalType: "uint256[]", name: "values", type: "uint256[]" }, + { internalType: "bytes[]", name: "calldatas", type: "bytes[]" }, + { internalType: "string", name: "description", type: "string" }, + { internalType: "uint8", name: "proposalType", type: "uint8" }, + ], + name: "propose", + outputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "contract VotingModule", + name: "module", + type: "address", + }, + { internalType: "bytes", name: "proposalData", type: "bytes" }, + { internalType: "string", name: "description", type: "string" }, + ], + name: "proposeWithModule", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "contract VotingModule", + name: "module", + type: "address", + }, + { internalType: "bytes", name: "proposalData", type: "bytes" }, + { internalType: "string", name: "description", type: "string" }, + { internalType: "uint8", name: "proposalType", type: "uint8" }, + ], + name: "proposeWithModule", + outputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address[]", name: "targets", type: "address[]" }, + { internalType: "uint256[]", name: "values", type: "uint256[]" }, + { internalType: "bytes[]", name: "calldatas", type: "bytes[]" }, + { internalType: "bytes32", name: "descriptionHash", type: "bytes32" }, + ], + name: "queue", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "contract VotingModule", + name: "module", + type: "address", + }, + { internalType: "bytes", name: "proposalData", type: "bytes" }, + { internalType: "bytes32", name: "descriptionHash", type: "bytes32" }, + ], + name: "queueWithModule", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + name: "quorum", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "target", type: "address" }, + { internalType: "uint256", name: "value", type: "uint256" }, + { internalType: "bytes", name: "data", type: "bytes" }, + ], + name: "relay", + outputs: [], + stateMutability: "payable", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "_newAdmin", type: "address" }], + name: "setAdmin", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "_newManager", type: "address" }], + name: "setManager", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "module", type: "address" }, + { internalType: "bool", name: "approved", type: "bool" }, + ], + name: "setModuleApproval", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "uint64", name: "deadline", type: "uint64" }, + ], + name: "setProposalDeadline", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "uint256", + name: "newProposalThreshold", + type: "uint256", + }, + ], + name: "setProposalThreshold", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "newVotingDelay", type: "uint256" }, + ], + name: "setVotingDelay", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "newVotingPeriod", type: "uint256" }, + ], + name: "setVotingPeriod", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + name: "state", + outputs: [ + { + internalType: "enum IGovernorUpgradeable.ProposalState", + name: "", + type: "uint8", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "bytes4", name: "interfaceId", type: "bytes4" }], + name: "supportsInterface", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "timelock", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "token", + outputs: [ + { internalType: "contract IVotesUpgradeable", name: "", type: "address" }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "contract TimelockControllerUpgradeable", + name: "newTimelock", + type: "address", + }, + ], + name: "updateTimelock", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "version", + outputs: [{ internalType: "string", name: "", type: "string" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "votingDelay", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "votingPeriod", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { stateMutability: "payable", type: "receive" }, +] as const; diff --git a/apps/api/src/clients/scr/abi/index.ts b/apps/api/src/clients/scr/abi/index.ts new file mode 100644 index 000000000..db767f1ac --- /dev/null +++ b/apps/api/src/clients/scr/abi/index.ts @@ -0,0 +1,2 @@ +export { GovernorAbi as SCRGovernorAbi } from "./governor"; +export { TokenAbi as SCRTokenAbi } from "./token"; diff --git a/apps/api/src/clients/scr/abi/token.ts b/apps/api/src/clients/scr/abi/token.ts new file mode 100644 index 000000000..71337f1f9 --- /dev/null +++ b/apps/api/src/clients/scr/abi/token.ts @@ -0,0 +1,720 @@ +export const TokenAbi = [ + { inputs: [], stateMutability: "nonpayable", type: "constructor" }, + { inputs: [], name: "AccessControlBadConfirmation", type: "error" }, + { + inputs: [ + { internalType: "address", name: "account", type: "address" }, + { internalType: "bytes32", name: "neededRole", type: "bytes32" }, + ], + name: "AccessControlUnauthorizedAccount", + type: "error", + }, + { inputs: [], name: "CheckpointUnorderedInsertion", type: "error" }, + { + inputs: [{ internalType: "address", name: "delegatee", type: "address" }], + name: "DuplicateOrUnsortedDelegatees", + type: "error", + }, + { inputs: [], name: "ECDSAInvalidSignature", type: "error" }, + { + inputs: [{ internalType: "uint256", name: "length", type: "uint256" }], + name: "ECDSAInvalidSignatureLength", + type: "error", + }, + { + inputs: [{ internalType: "bytes32", name: "s", type: "bytes32" }], + name: "ECDSAInvalidSignatureS", + type: "error", + }, + { + inputs: [ + { internalType: "uint256", name: "increasedSupply", type: "uint256" }, + { internalType: "uint256", name: "cap", type: "uint256" }, + ], + name: "ERC20ExceededSafeSupply", + type: "error", + }, + { + inputs: [ + { internalType: "address", name: "spender", type: "address" }, + { internalType: "uint256", name: "allowance", type: "uint256" }, + { internalType: "uint256", name: "needed", type: "uint256" }, + ], + name: "ERC20InsufficientAllowance", + type: "error", + }, + { + inputs: [ + { internalType: "address", name: "sender", type: "address" }, + { internalType: "uint256", name: "balance", type: "uint256" }, + { internalType: "uint256", name: "needed", type: "uint256" }, + ], + name: "ERC20InsufficientBalance", + type: "error", + }, + { + inputs: [{ internalType: "address", name: "approver", type: "address" }], + name: "ERC20InvalidApprover", + type: "error", + }, + { + inputs: [{ internalType: "address", name: "receiver", type: "address" }], + name: "ERC20InvalidReceiver", + type: "error", + }, + { + inputs: [{ internalType: "address", name: "sender", type: "address" }], + name: "ERC20InvalidSender", + type: "error", + }, + { + inputs: [{ internalType: "address", name: "spender", type: "address" }], + name: "ERC20InvalidSpender", + type: "error", + }, + { + inputs: [{ internalType: "uint256", name: "deadline", type: "uint256" }], + name: "ERC2612ExpiredSignature", + type: "error", + }, + { + inputs: [ + { internalType: "address", name: "signer", type: "address" }, + { internalType: "address", name: "owner", type: "address" }, + ], + name: "ERC2612InvalidSigner", + type: "error", + }, + { + inputs: [ + { internalType: "uint256", name: "timepoint", type: "uint256" }, + { internalType: "uint48", name: "clock", type: "uint48" }, + ], + name: "ERC5805FutureLookup", + type: "error", + }, + { inputs: [], name: "ERC6372InconsistentClock", type: "error" }, + { + inputs: [ + { internalType: "address", name: "account", type: "address" }, + { internalType: "uint256", name: "currentNonce", type: "uint256" }, + ], + name: "InvalidAccountNonce", + type: "error", + }, + { inputs: [], name: "InvalidAddressZero", type: "error" }, + { inputs: [], name: "InvalidInitialization", type: "error" }, + { inputs: [], name: "InvalidNumeratorZero", type: "error" }, + { inputs: [], name: "InvalidSignature", type: "error" }, + { inputs: [], name: "NotInitializing", type: "error" }, + { + inputs: [ + { internalType: "uint256", name: "numerator", type: "uint256" }, + { internalType: "uint96", name: "denominator", type: "uint96" }, + ], + name: "NumeratorSumExceedsDenominator", + type: "error", + }, + { + inputs: [ + { internalType: "uint256", name: "length", type: "uint256" }, + { internalType: "uint256", name: "max", type: "uint256" }, + ], + name: "PartialDelegationLimitExceeded", + type: "error", + }, + { + inputs: [ + { internalType: "uint8", name: "bits", type: "uint8" }, + { internalType: "uint256", name: "value", type: "uint256" }, + ], + name: "SafeCastOverflowedUintDowncast", + type: "error", + }, + { + inputs: [{ internalType: "uint256", name: "expiry", type: "uint256" }], + name: "VotesExpiredSignature", + type: "error", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "owner", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "spender", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "value", + type: "uint256", + }, + ], + name: "Approval", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "delegator", + type: "address", + }, + { + components: [ + { internalType: "address", name: "_delegatee", type: "address" }, + { internalType: "uint96", name: "_numerator", type: "uint96" }, + ], + indexed: false, + internalType: "struct PartialDelegation[]", + name: "oldDelegatees", + type: "tuple[]", + }, + { + components: [ + { internalType: "address", name: "_delegatee", type: "address" }, + { internalType: "uint96", name: "_numerator", type: "uint96" }, + ], + indexed: false, + internalType: "struct PartialDelegation[]", + name: "newDelegatees", + type: "tuple[]", + }, + ], + name: "DelegateChanged", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "delegate", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "previousVotes", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "newVotes", + type: "uint256", + }, + ], + name: "DelegateVotesChanged", + type: "event", + }, + { anonymous: false, inputs: [], name: "EIP712DomainChanged", type: "event" }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint64", + name: "version", + type: "uint64", + }, + ], + name: "Initialized", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "bytes32", name: "role", type: "bytes32" }, + { + indexed: true, + internalType: "bytes32", + name: "previousAdminRole", + type: "bytes32", + }, + { + indexed: true, + internalType: "bytes32", + name: "newAdminRole", + type: "bytes32", + }, + ], + name: "RoleAdminChanged", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "bytes32", name: "role", type: "bytes32" }, + { + indexed: true, + internalType: "address", + name: "account", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "sender", + type: "address", + }, + ], + name: "RoleGranted", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "bytes32", name: "role", type: "bytes32" }, + { + indexed: true, + internalType: "address", + name: "account", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "sender", + type: "address", + }, + ], + name: "RoleRevoked", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "address", name: "from", type: "address" }, + { indexed: true, internalType: "address", name: "to", type: "address" }, + { + indexed: false, + internalType: "uint256", + name: "value", + type: "uint256", + }, + ], + name: "Transfer", + type: "event", + }, + { + inputs: [], + name: "BURNER_ROLE", + outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "CLOCK_MODE", + outputs: [{ internalType: "string", name: "", type: "string" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "DEFAULT_ADMIN_ROLE", + outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "DELEGATION_TYPEHASH", + outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "DENOMINATOR", + outputs: [{ internalType: "uint96", name: "", type: "uint96" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "DOMAIN_SEPARATOR", + outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "MAX_PARTIAL_DELEGATIONS", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "MINTER_ROLE", + outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "PARTIAL_DELEGATION_ON_BEHALF_TYPEHASH", + outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "PARTIAL_DELEGATION_TYPEHASH", + outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "owner", type: "address" }, + { internalType: "address", name: "spender", type: "address" }, + ], + name: "allowance", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "spender", type: "address" }, + { internalType: "uint256", name: "value", type: "uint256" }, + ], + name: "approve", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "account", type: "address" }], + name: "balanceOf", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "_account", type: "address" }, + { internalType: "uint256", name: "_value", type: "uint256" }, + ], + name: "burn", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "account", type: "address" }, + { internalType: "uint32", name: "pos", type: "uint32" }, + ], + name: "checkpoints", + outputs: [ + { + components: [ + { internalType: "uint48", name: "_key", type: "uint48" }, + { internalType: "uint208", name: "_value", type: "uint208" }, + ], + internalType: "struct Checkpoints.Checkpoint208", + name: "", + type: "tuple", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "clock", + outputs: [{ internalType: "uint48", name: "", type: "uint48" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "decimals", + outputs: [{ internalType: "uint8", name: "", type: "uint8" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "delegatee", type: "address" }], + name: "delegate", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + components: [ + { internalType: "address", name: "_delegatee", type: "address" }, + { internalType: "uint96", name: "_numerator", type: "uint96" }, + ], + internalType: "struct PartialDelegation[]", + name: "_partialDelegations", + type: "tuple[]", + }, + ], + name: "delegate", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "delegatee", type: "address" }, + { internalType: "uint256", name: "nonce", type: "uint256" }, + { internalType: "uint256", name: "expiry", type: "uint256" }, + { internalType: "uint8", name: "v", type: "uint8" }, + { internalType: "bytes32", name: "r", type: "bytes32" }, + { internalType: "bytes32", name: "s", type: "bytes32" }, + ], + name: "delegateBySig", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "_delegator", type: "address" }, + { + components: [ + { internalType: "address", name: "_delegatee", type: "address" }, + { internalType: "uint96", name: "_numerator", type: "uint96" }, + ], + internalType: "struct PartialDelegation[]", + name: "_partialDelegations", + type: "tuple[]", + }, + { internalType: "uint256", name: "_nonce", type: "uint256" }, + { internalType: "uint256", name: "_expiry", type: "uint256" }, + { internalType: "bytes", name: "_signature", type: "bytes" }, + ], + name: "delegatePartiallyOnBehalf", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "account", type: "address" }], + name: "delegates", + outputs: [ + { + components: [ + { internalType: "address", name: "_delegatee", type: "address" }, + { internalType: "uint96", name: "_numerator", type: "uint96" }, + ], + internalType: "struct PartialDelegation[]", + name: "", + type: "tuple[]", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "eip712Domain", + outputs: [ + { internalType: "bytes1", name: "fields", type: "bytes1" }, + { internalType: "string", name: "name", type: "string" }, + { internalType: "string", name: "version", type: "string" }, + { internalType: "uint256", name: "chainId", type: "uint256" }, + { internalType: "address", name: "verifyingContract", type: "address" }, + { internalType: "bytes32", name: "salt", type: "bytes32" }, + { internalType: "uint256[]", name: "extensions", type: "uint256[]" }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "timepoint", type: "uint256" }], + name: "getPastTotalSupply", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "account", type: "address" }, + { internalType: "uint256", name: "timepoint", type: "uint256" }, + ], + name: "getPastVotes", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "bytes32", name: "role", type: "bytes32" }], + name: "getRoleAdmin", + outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "account", type: "address" }], + name: "getVotes", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "bytes32", name: "role", type: "bytes32" }, + { internalType: "address", name: "account", type: "address" }, + ], + name: "grantRole", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "bytes32", name: "role", type: "bytes32" }, + { internalType: "address", name: "account", type: "address" }, + ], + name: "hasRole", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "_admin", type: "address" }, + { internalType: "string", name: "_name", type: "string" }, + { internalType: "string", name: "_symbol", type: "string" }, + ], + name: "initialize", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "invalidateNonce", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "_account", type: "address" }, + { internalType: "uint256", name: "_amount", type: "uint256" }, + ], + name: "mint", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "name", + outputs: [{ internalType: "string", name: "", type: "string" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "owner", type: "address" }], + name: "nonces", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "account", type: "address" }], + name: "numCheckpoints", + outputs: [{ internalType: "uint32", name: "", type: "uint32" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "owner", type: "address" }, + { internalType: "address", name: "spender", type: "address" }, + { internalType: "uint256", name: "value", type: "uint256" }, + { internalType: "uint256", name: "deadline", type: "uint256" }, + { internalType: "uint8", name: "v", type: "uint8" }, + { internalType: "bytes32", name: "r", type: "bytes32" }, + { internalType: "bytes32", name: "s", type: "bytes32" }, + ], + name: "permit", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "bytes32", name: "role", type: "bytes32" }, + { internalType: "address", name: "callerConfirmation", type: "address" }, + ], + name: "renounceRole", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "bytes32", name: "role", type: "bytes32" }, + { internalType: "address", name: "account", type: "address" }, + ], + name: "revokeRole", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "bytes4", name: "interfaceId", type: "bytes4" }], + name: "supportsInterface", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "symbol", + outputs: [{ internalType: "string", name: "", type: "string" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "totalSupply", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "to", type: "address" }, + { internalType: "uint256", name: "value", type: "uint256" }, + ], + name: "transfer", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "from", type: "address" }, + { internalType: "address", name: "to", type: "address" }, + { internalType: "uint256", name: "value", type: "uint256" }, + ], + name: "transferFrom", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "nonpayable", + type: "function", + }, +] as const; diff --git a/apps/api/src/clients/scr/index.ts b/apps/api/src/clients/scr/index.ts new file mode 100644 index 000000000..aa72d6d5b --- /dev/null +++ b/apps/api/src/clients/scr/index.ts @@ -0,0 +1,115 @@ +import { + Account, + Address, + Chain, + Client, + fromHex, + parseEther, + toHex, + Transport, +} from "viem"; +import { readContract } from "viem/actions"; + +import { DAOClient } from "@/interfaces/client"; +import { GovernorAbi } from "./abi/governor"; +import { GovernorBase } from "../governor.base"; + +export class SCRClient< + TTransport extends Transport = Transport, + TChain extends Chain = Chain, + TAccount extends Account | undefined = Account | undefined, + > + extends GovernorBase + implements DAOClient +{ + private abi: typeof GovernorAbi; + private address: Address; + + constructor(client: Client, address: Address) { + super(client); + this.address = address; + this.abi = GovernorAbi; + } + + getDaoId(): string { + return "SCR"; + } + + async getQuorum(_: string | null): Promise { + return parseEther("2100000"); // 2.1M $SCR (0.21% Total Supply) + } + + async getProposalThreshold(): Promise { + return readContract(this.client, { + abi: this.abi, + address: this.address, + functionName: "proposalThreshold", + }); + } + + async getVotingDelay(): Promise { + return readContract(this.client, { + abi: this.abi, + address: this.address, + functionName: "votingDelay", + }); + } + + async getVotingPeriod(): Promise { + return readContract(this.client, { + abi: this.abi, + address: this.address, + functionName: "votingPeriod", + }); + } + + async getTimelockDelay(): Promise { + const timelockAddress = await readContract(this.client, { + abi: this.abi, + address: this.address, + functionName: "timelock", + }); + return readContract(this.client, { + abi: [ + { + inputs: [], + name: "getMinDelay", + outputs: [ + { + internalType: "uint256", + name: "duration", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, + ], + address: timelockAddress, + functionName: "getMinDelay", + }); + } + + async getCurrentBlockNumber(): Promise { + const result = await this.client.request({ + method: "eth_blockNumber", + }); + return fromHex(result, "number"); + } + + async getBlockTime(blockNumber: number): Promise { + const block = await this.client.request({ + method: "eth_getBlockByNumber", + params: [toHex(blockNumber), false], + }); + return block?.timestamp ? fromHex(block.timestamp, "number") : null; + } + + calculateQuorum(votes: { + forVotes: bigint; + againstVotes: bigint; + abstainVotes: bigint; + }): bigint { + return votes.forVotes + votes.abstainVotes + votes.againstVotes; + } +} diff --git a/apps/api/src/clients/uni/abi/governor.ts b/apps/api/src/clients/uni/abi/governor.ts new file mode 100644 index 000000000..e282b2aa7 --- /dev/null +++ b/apps/api/src/clients/uni/abi/governor.ts @@ -0,0 +1,777 @@ +export const GovernorAbi = [ + ...[ + { + inputs: [ + { internalType: "address", name: "timelock_", type: "address" }, + { internalType: "address", name: "uni_", type: "address" }, + { internalType: "address", name: "admin_", type: "address" }, + { internalType: "address", name: "implementation_", type: "address" }, + { internalType: "uint256", name: "votingPeriod_", type: "uint256" }, + { internalType: "uint256", name: "votingDelay_", type: "uint256" }, + { + internalType: "uint256", + name: "proposalThreshold_", + type: "uint256", + }, + ], + payable: false, + stateMutability: "nonpayable", + type: "constructor", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "oldAdmin", + type: "address", + }, + { + indexed: false, + internalType: "address", + name: "newAdmin", + type: "address", + }, + ], + name: "NewAdmin", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "oldImplementation", + type: "address", + }, + { + indexed: false, + internalType: "address", + name: "newImplementation", + type: "address", + }, + ], + name: "NewImplementation", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "oldPendingAdmin", + type: "address", + }, + { + indexed: false, + internalType: "address", + name: "newPendingAdmin", + type: "address", + }, + ], + name: "NewPendingAdmin", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "id", + type: "uint256", + }, + ], + name: "ProposalCanceled", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "id", + type: "uint256", + }, + { + indexed: false, + internalType: "address", + name: "proposer", + type: "address", + }, + { + indexed: false, + internalType: "address[]", + name: "targets", + type: "address[]", + }, + { + indexed: false, + internalType: "uint256[]", + name: "values", + type: "uint256[]", + }, + { + indexed: false, + internalType: "string[]", + name: "signatures", + type: "string[]", + }, + { + indexed: false, + internalType: "bytes[]", + name: "calldatas", + type: "bytes[]", + }, + { + indexed: false, + internalType: "uint256", + name: "startBlock", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "endBlock", + type: "uint256", + }, + { + indexed: false, + internalType: "string", + name: "description", + type: "string", + }, + ], + name: "ProposalCreated", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "id", + type: "uint256", + }, + ], + name: "ProposalExecuted", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "id", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "eta", + type: "uint256", + }, + ], + name: "ProposalQueued", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "voter", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "proposalId", + type: "uint256", + }, + { + indexed: false, + internalType: "uint8", + name: "support", + type: "uint8", + }, + { + indexed: false, + internalType: "uint256", + name: "votes", + type: "uint256", + }, + { + indexed: false, + internalType: "string", + name: "reason", + type: "string", + }, + ], + name: "VoteCast", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "oldVotingDelay", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "newVotingDelay", + type: "uint256", + }, + ], + name: "VotingDelaySet", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "oldVotingPeriod", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "newVotingPeriod", + type: "uint256", + }, + ], + name: "VotingPeriodSet", + type: "event", + }, + { payable: true, stateMutability: "payable", type: "fallback" }, + { + constant: false, + inputs: [ + { internalType: "address", name: "implementation_", type: "address" }, + ], + name: "_setImplementation", + outputs: [], + payable: false, + stateMutability: "nonpayable", + type: "function", + }, + { + constant: true, + inputs: [], + name: "admin", + outputs: [{ internalType: "address", name: "", type: "address" }], + payable: false, + stateMutability: "view", + type: "function", + }, + { + constant: true, + inputs: [], + name: "implementation", + outputs: [{ internalType: "address", name: "", type: "address" }], + payable: false, + stateMutability: "view", + type: "function", + }, + { + constant: true, + inputs: [], + name: "pendingAdmin", + outputs: [{ internalType: "address", name: "", type: "address" }], + payable: false, + stateMutability: "view", + type: "function", + }, + ], + ...[ + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "oldProposalThreshold", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "newProposalThreshold", + type: "uint256", + }, + ], + name: "ProposalThresholdSet", + type: "event", + }, + { + constant: true, + inputs: [], + name: "BALLOT_TYPEHASH", + outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], + payable: false, + stateMutability: "view", + type: "function", + }, + { + constant: true, + inputs: [], + name: "DOMAIN_TYPEHASH", + outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], + payable: false, + stateMutability: "view", + type: "function", + }, + { + constant: true, + inputs: [], + name: "MAX_PROPOSAL_THRESHOLD", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + payable: false, + stateMutability: "view", + type: "function", + }, + { + constant: true, + inputs: [], + name: "MAX_VOTING_DELAY", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + payable: false, + stateMutability: "view", + type: "function", + }, + { + constant: true, + inputs: [], + name: "MAX_VOTING_PERIOD", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + payable: false, + stateMutability: "view", + type: "function", + }, + { + constant: true, + inputs: [], + name: "MIN_PROPOSAL_THRESHOLD", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + payable: false, + stateMutability: "view", + type: "function", + }, + { + constant: true, + inputs: [], + name: "MIN_VOTING_DELAY", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + payable: false, + stateMutability: "view", + type: "function", + }, + { + constant: true, + inputs: [], + name: "MIN_VOTING_PERIOD", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + payable: false, + stateMutability: "view", + type: "function", + }, + { + constant: false, + inputs: [], + name: "_acceptAdmin", + outputs: [], + payable: false, + stateMutability: "nonpayable", + type: "function", + }, + { + constant: false, + inputs: [ + { internalType: "uint256", name: "proposalCount", type: "uint256" }, + ], + name: "_initiate", + outputs: [], + payable: false, + stateMutability: "nonpayable", + type: "function", + }, + { + constant: false, + inputs: [ + { internalType: "address", name: "newPendingAdmin", type: "address" }, + ], + name: "_setPendingAdmin", + outputs: [], + payable: false, + stateMutability: "nonpayable", + type: "function", + }, + { + constant: false, + inputs: [ + { + internalType: "uint256", + name: "newProposalThreshold", + type: "uint256", + }, + ], + name: "_setProposalThreshold", + outputs: [], + payable: false, + stateMutability: "nonpayable", + type: "function", + }, + { + constant: false, + inputs: [ + { internalType: "uint256", name: "newVotingDelay", type: "uint256" }, + ], + name: "_setVotingDelay", + outputs: [], + payable: false, + stateMutability: "nonpayable", + type: "function", + }, + { + constant: false, + inputs: [ + { internalType: "uint256", name: "newVotingPeriod", type: "uint256" }, + ], + name: "_setVotingPeriod", + outputs: [], + payable: false, + stateMutability: "nonpayable", + type: "function", + }, + { + constant: true, + inputs: [], + name: "admin", + outputs: [{ internalType: "address", name: "", type: "address" }], + payable: false, + stateMutability: "view", + type: "function", + }, + { + constant: false, + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + ], + name: "cancel", + outputs: [], + payable: false, + stateMutability: "nonpayable", + type: "function", + }, + { + constant: false, + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "uint8", name: "support", type: "uint8" }, + ], + name: "castVote", + outputs: [], + payable: false, + stateMutability: "nonpayable", + type: "function", + }, + { + constant: false, + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "uint8", name: "support", type: "uint8" }, + { internalType: "uint8", name: "v", type: "uint8" }, + { internalType: "bytes32", name: "r", type: "bytes32" }, + { internalType: "bytes32", name: "s", type: "bytes32" }, + ], + name: "castVoteBySig", + outputs: [], + payable: false, + stateMutability: "nonpayable", + type: "function", + }, + { + constant: false, + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "uint8", name: "support", type: "uint8" }, + { internalType: "string", name: "reason", type: "string" }, + ], + name: "castVoteWithReason", + outputs: [], + payable: false, + stateMutability: "nonpayable", + type: "function", + }, + { + constant: false, + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + ], + name: "execute", + outputs: [], + payable: true, + stateMutability: "payable", + type: "function", + }, + { + constant: true, + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + ], + name: "getActions", + outputs: [ + { internalType: "address[]", name: "targets", type: "address[]" }, + { internalType: "uint256[]", name: "values", type: "uint256[]" }, + { internalType: "string[]", name: "signatures", type: "string[]" }, + { internalType: "bytes[]", name: "calldatas", type: "bytes[]" }, + ], + payable: false, + stateMutability: "view", + type: "function", + }, + { + constant: true, + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "address", name: "voter", type: "address" }, + ], + name: "getReceipt", + outputs: [ + { + components: [ + { internalType: "bool", name: "hasVoted", type: "bool" }, + { internalType: "uint8", name: "support", type: "uint8" }, + { internalType: "uint96", name: "votes", type: "uint96" }, + ], + internalType: "struct GovernorBravoDelegateStorageV1.Receipt", + name: "", + type: "tuple", + }, + ], + payable: false, + stateMutability: "view", + type: "function", + }, + { + constant: true, + inputs: [], + name: "implementation", + outputs: [{ internalType: "address", name: "", type: "address" }], + payable: false, + stateMutability: "view", + type: "function", + }, + { + constant: true, + inputs: [], + name: "initialProposalId", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + payable: false, + stateMutability: "view", + type: "function", + }, + { + constant: false, + inputs: [ + { internalType: "address", name: "timelock_", type: "address" }, + { internalType: "address", name: "uni_", type: "address" }, + { internalType: "uint256", name: "votingPeriod_", type: "uint256" }, + { internalType: "uint256", name: "votingDelay_", type: "uint256" }, + { + internalType: "uint256", + name: "proposalThreshold_", + type: "uint256", + }, + ], + name: "initialize", + outputs: [], + payable: false, + stateMutability: "nonpayable", + type: "function", + }, + { + constant: true, + inputs: [{ internalType: "address", name: "", type: "address" }], + name: "latestProposalIds", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + payable: false, + stateMutability: "view", + type: "function", + }, + { + constant: true, + inputs: [], + name: "name", + outputs: [{ internalType: "string", name: "", type: "string" }], + payable: false, + stateMutability: "view", + type: "function", + }, + { + constant: true, + inputs: [], + name: "pendingAdmin", + outputs: [{ internalType: "address", name: "", type: "address" }], + payable: false, + stateMutability: "view", + type: "function", + }, + { + constant: true, + inputs: [], + name: "proposalCount", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + payable: false, + stateMutability: "view", + type: "function", + }, + { + constant: true, + inputs: [], + name: "proposalMaxOperations", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + payable: false, + stateMutability: "view", + type: "function", + }, + { + constant: true, + inputs: [], + name: "proposalThreshold", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + payable: false, + stateMutability: "view", + type: "function", + }, + { + constant: true, + inputs: [{ internalType: "uint256", name: "", type: "uint256" }], + name: "proposals", + outputs: [ + { internalType: "uint256", name: "id", type: "uint256" }, + { internalType: "address", name: "proposer", type: "address" }, + { internalType: "uint256", name: "eta", type: "uint256" }, + { internalType: "uint256", name: "startBlock", type: "uint256" }, + { internalType: "uint256", name: "endBlock", type: "uint256" }, + { internalType: "uint256", name: "forVotes", type: "uint256" }, + { internalType: "uint256", name: "againstVotes", type: "uint256" }, + { internalType: "uint256", name: "abstainVotes", type: "uint256" }, + { internalType: "bool", name: "canceled", type: "bool" }, + { internalType: "bool", name: "executed", type: "bool" }, + ], + payable: false, + stateMutability: "view", + type: "function", + }, + { + constant: false, + inputs: [ + { internalType: "address[]", name: "targets", type: "address[]" }, + { internalType: "uint256[]", name: "values", type: "uint256[]" }, + { internalType: "string[]", name: "signatures", type: "string[]" }, + { internalType: "bytes[]", name: "calldatas", type: "bytes[]" }, + { internalType: "string", name: "description", type: "string" }, + ], + name: "propose", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + payable: false, + stateMutability: "nonpayable", + type: "function", + }, + { + constant: false, + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + ], + name: "queue", + outputs: [], + payable: false, + stateMutability: "nonpayable", + type: "function", + }, + { + constant: true, + inputs: [], + name: "quorumVotes", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + payable: false, + stateMutability: "view", + type: "function", + }, + { + constant: true, + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + ], + name: "state", + outputs: [ + { + internalType: "enum GovernorBravoDelegateStorageV1.ProposalState", + name: "", + type: "uint8", + }, + ], + payable: false, + stateMutability: "view", + type: "function", + }, + { + constant: true, + inputs: [], + name: "timelock", + outputs: [ + { + internalType: "contract TimelockInterface", + name: "", + type: "address", + }, + ], + payable: false, + stateMutability: "view", + type: "function", + }, + { + constant: true, + inputs: [], + name: "uni", + outputs: [ + { internalType: "contract UniInterface", name: "", type: "address" }, + ], + payable: false, + stateMutability: "view", + type: "function", + }, + { + constant: true, + inputs: [], + name: "votingDelay", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + payable: false, + stateMutability: "view", + type: "function", + }, + { + constant: true, + inputs: [], + name: "votingPeriod", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + payable: false, + stateMutability: "view", + type: "function", + }, + ], +] as const; diff --git a/apps/api/src/clients/uni/abi/index.ts b/apps/api/src/clients/uni/abi/index.ts new file mode 100644 index 000000000..6876ec5bf --- /dev/null +++ b/apps/api/src/clients/uni/abi/index.ts @@ -0,0 +1,2 @@ +export { TokenAbi } from "./token"; +export { GovernorAbi } from "./governor"; diff --git a/apps/api/src/clients/uni/abi/token.ts b/apps/api/src/clients/uni/abi/token.ts new file mode 100644 index 000000000..b334ccb13 --- /dev/null +++ b/apps/api/src/clients/uni/abi/token.ts @@ -0,0 +1,408 @@ +export const TokenAbi = [ + { + inputs: [ + { internalType: "address", name: "account", type: "address" }, + { internalType: "address", name: "minter_", type: "address" }, + { + internalType: "uint256", + name: "mintingAllowedAfter_", + type: "uint256", + }, + ], + payable: false, + stateMutability: "nonpayable", + type: "constructor", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "owner", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "spender", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "amount", + type: "uint256", + }, + ], + name: "Approval", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "delegator", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "fromDelegate", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "toDelegate", + type: "address", + }, + ], + name: "DelegateChanged", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "delegate", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "previousBalance", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "newBalance", + type: "uint256", + }, + ], + name: "DelegateVotesChanged", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "minter", + type: "address", + }, + { + indexed: false, + internalType: "address", + name: "newMinter", + type: "address", + }, + ], + name: "MinterChanged", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "address", name: "from", type: "address" }, + { indexed: true, internalType: "address", name: "to", type: "address" }, + { + indexed: false, + internalType: "uint256", + name: "amount", + type: "uint256", + }, + ], + name: "Transfer", + type: "event", + }, + { + constant: true, + inputs: [], + name: "DELEGATION_TYPEHASH", + outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], + payable: false, + stateMutability: "view", + type: "function", + }, + { + constant: true, + inputs: [], + name: "DOMAIN_TYPEHASH", + outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], + payable: false, + stateMutability: "view", + type: "function", + }, + { + constant: true, + inputs: [], + name: "PERMIT_TYPEHASH", + outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], + payable: false, + stateMutability: "view", + type: "function", + }, + { + constant: true, + inputs: [ + { internalType: "address", name: "account", type: "address" }, + { internalType: "address", name: "spender", type: "address" }, + ], + name: "allowance", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + payable: false, + stateMutability: "view", + type: "function", + }, + { + constant: false, + inputs: [ + { internalType: "address", name: "spender", type: "address" }, + { internalType: "uint256", name: "rawAmount", type: "uint256" }, + ], + name: "approve", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + payable: false, + stateMutability: "nonpayable", + type: "function", + }, + { + constant: true, + inputs: [{ internalType: "address", name: "account", type: "address" }], + name: "balanceOf", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + payable: false, + stateMutability: "view", + type: "function", + }, + { + constant: true, + inputs: [ + { internalType: "address", name: "", type: "address" }, + { internalType: "uint32", name: "", type: "uint32" }, + ], + name: "checkpoints", + outputs: [ + { internalType: "uint32", name: "fromBlock", type: "uint32" }, + { internalType: "uint96", name: "votes", type: "uint96" }, + ], + payable: false, + stateMutability: "view", + type: "function", + }, + { + constant: true, + inputs: [], + name: "decimals", + outputs: [{ internalType: "uint8", name: "", type: "uint8" }], + payable: false, + stateMutability: "view", + type: "function", + }, + { + constant: false, + inputs: [{ internalType: "address", name: "delegatee", type: "address" }], + name: "delegate", + outputs: [], + payable: false, + stateMutability: "nonpayable", + type: "function", + }, + { + constant: false, + inputs: [ + { internalType: "address", name: "delegatee", type: "address" }, + { internalType: "uint256", name: "nonce", type: "uint256" }, + { internalType: "uint256", name: "expiry", type: "uint256" }, + { internalType: "uint8", name: "v", type: "uint8" }, + { internalType: "bytes32", name: "r", type: "bytes32" }, + { internalType: "bytes32", name: "s", type: "bytes32" }, + ], + name: "delegateBySig", + outputs: [], + payable: false, + stateMutability: "nonpayable", + type: "function", + }, + { + constant: true, + inputs: [{ internalType: "address", name: "", type: "address" }], + name: "delegates", + outputs: [{ internalType: "address", name: "", type: "address" }], + payable: false, + stateMutability: "view", + type: "function", + }, + { + constant: true, + inputs: [{ internalType: "address", name: "account", type: "address" }], + name: "getCurrentVotes", + outputs: [{ internalType: "uint96", name: "", type: "uint96" }], + payable: false, + stateMutability: "view", + type: "function", + }, + { + constant: true, + inputs: [ + { internalType: "address", name: "account", type: "address" }, + { internalType: "uint256", name: "blockNumber", type: "uint256" }, + ], + name: "getPriorVotes", + outputs: [{ internalType: "uint96", name: "", type: "uint96" }], + payable: false, + stateMutability: "view", + type: "function", + }, + { + constant: true, + inputs: [], + name: "minimumTimeBetweenMints", + outputs: [{ internalType: "uint32", name: "", type: "uint32" }], + payable: false, + stateMutability: "view", + type: "function", + }, + { + constant: false, + inputs: [ + { internalType: "address", name: "dst", type: "address" }, + { internalType: "uint256", name: "rawAmount", type: "uint256" }, + ], + name: "mint", + outputs: [], + payable: false, + stateMutability: "nonpayable", + type: "function", + }, + { + constant: true, + inputs: [], + name: "mintCap", + outputs: [{ internalType: "uint8", name: "", type: "uint8" }], + payable: false, + stateMutability: "view", + type: "function", + }, + { + constant: true, + inputs: [], + name: "minter", + outputs: [{ internalType: "address", name: "", type: "address" }], + payable: false, + stateMutability: "view", + type: "function", + }, + { + constant: true, + inputs: [], + name: "mintingAllowedAfter", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + payable: false, + stateMutability: "view", + type: "function", + }, + { + constant: true, + inputs: [], + name: "name", + outputs: [{ internalType: "string", name: "", type: "string" }], + payable: false, + stateMutability: "view", + type: "function", + }, + { + constant: true, + inputs: [{ internalType: "address", name: "", type: "address" }], + name: "nonces", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + payable: false, + stateMutability: "view", + type: "function", + }, + { + constant: true, + inputs: [{ internalType: "address", name: "", type: "address" }], + name: "numCheckpoints", + outputs: [{ internalType: "uint32", name: "", type: "uint32" }], + payable: false, + stateMutability: "view", + type: "function", + }, + { + constant: false, + inputs: [ + { internalType: "address", name: "owner", type: "address" }, + { internalType: "address", name: "spender", type: "address" }, + { internalType: "uint256", name: "rawAmount", type: "uint256" }, + { internalType: "uint256", name: "deadline", type: "uint256" }, + { internalType: "uint8", name: "v", type: "uint8" }, + { internalType: "bytes32", name: "r", type: "bytes32" }, + { internalType: "bytes32", name: "s", type: "bytes32" }, + ], + name: "permit", + outputs: [], + payable: false, + stateMutability: "nonpayable", + type: "function", + }, + { + constant: false, + inputs: [{ internalType: "address", name: "minter_", type: "address" }], + name: "setMinter", + outputs: [], + payable: false, + stateMutability: "nonpayable", + type: "function", + }, + { + constant: true, + inputs: [], + name: "symbol", + outputs: [{ internalType: "string", name: "", type: "string" }], + payable: false, + stateMutability: "view", + type: "function", + }, + { + constant: true, + inputs: [], + name: "totalSupply", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + payable: false, + stateMutability: "view", + type: "function", + }, + { + constant: false, + inputs: [ + { internalType: "address", name: "dst", type: "address" }, + { internalType: "uint256", name: "rawAmount", type: "uint256" }, + ], + name: "transfer", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + payable: false, + stateMutability: "nonpayable", + type: "function", + }, + { + constant: false, + inputs: [ + { internalType: "address", name: "src", type: "address" }, + { internalType: "address", name: "dst", type: "address" }, + { internalType: "uint256", name: "rawAmount", type: "uint256" }, + ], + name: "transferFrom", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + payable: false, + stateMutability: "nonpayable", + type: "function", + }, +] as const; diff --git a/apps/api/src/clients/uni/index.ts b/apps/api/src/clients/uni/index.ts new file mode 100644 index 000000000..f406bdc62 --- /dev/null +++ b/apps/api/src/clients/uni/index.ts @@ -0,0 +1,115 @@ +import { + Account, + Address, + Chain, + Client, + fromHex, + toHex, + Transport, +} from "viem"; +import { readContract } from "viem/actions"; + +import { DAOClient } from "@/interfaces/client"; +import { GovernorAbi } from "./abi"; +import { GovernorBase } from "../governor.base"; + +export class UNIClient< + TTransport extends Transport = Transport, + TChain extends Chain = Chain, + TAccount extends Account | undefined = Account | undefined, + > + extends GovernorBase + implements DAOClient +{ + private abi: typeof GovernorAbi; + private address: Address; + + constructor(client: Client, address: Address) { + super(client); + this.address = address; + this.abi = GovernorAbi; + } + + getDaoId(): string { + return "UNI"; + } + + async getQuorum(): Promise { + return readContract(this.client, { + abi: this.abi, + address: this.address, + functionName: "quorumVotes", + args: [], + }); + } + + async getProposalThreshold(): Promise { + return readContract(this.client, { + abi: this.abi, + address: this.address, + functionName: "proposalThreshold", + }); + } + + async getVotingDelay(): Promise { + return readContract(this.client, { + abi: this.abi, + address: this.address, + functionName: "votingDelay", + }); + } + + async getVotingPeriod(): Promise { + return readContract(this.client, { + abi: this.abi, + address: this.address, + functionName: "votingPeriod", + }); + } + + async getTimelockDelay(): Promise { + const timelockAddress = await readContract(this.client, { + abi: this.abi, + address: this.address, + functionName: "timelock", + }); + return readContract(this.client, { + abi: [ + { + constant: true, + inputs: [], + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + payable: false, + stateMutability: "view", + type: "function", + name: "delay", + }, + ], + address: timelockAddress, + functionName: "delay", + }); + } + + async getCurrentBlockNumber(): Promise { + const result = await this.client.request({ + method: "eth_blockNumber", + }); + return fromHex(result, "number"); + } + + async getBlockTime(blockNumber: number): Promise { + const block = await this.client.request({ + method: "eth_getBlockByNumber", + params: [toHex(blockNumber), false], + }); + return block?.timestamp ? fromHex(block.timestamp, "number") : null; + } + + calculateQuorum(votes: { + forVotes: bigint; + againstVotes: bigint; + abstainVotes: bigint; + }): bigint { + return votes.forVotes; + } +} diff --git a/apps/api/src/clients/zk/abi/governor.ts b/apps/api/src/clients/zk/abi/governor.ts new file mode 100644 index 000000000..a430c0148 --- /dev/null +++ b/apps/api/src/clients/zk/abi/governor.ts @@ -0,0 +1,839 @@ +export const GovernorAbi = [ + { + inputs: [ + { + components: [ + { internalType: "string", name: "name", type: "string" }, + { internalType: "contract IVotes", name: "token", type: "address" }, + { + internalType: "contract TimelockController", + name: "timelock", + type: "address", + }, + { + internalType: "uint48", + name: "initialVotingDelay", + type: "uint48", + }, + { + internalType: "uint32", + name: "initialVotingPeriod", + type: "uint32", + }, + { + internalType: "uint256", + name: "initialProposalThreshold", + type: "uint256", + }, + { internalType: "uint224", name: "initialQuorum", type: "uint224" }, + { + internalType: "uint64", + name: "initialVoteExtension", + type: "uint64", + }, + { internalType: "address", name: "vetoGuardian", type: "address" }, + { internalType: "address", name: "proposeGuardian", type: "address" }, + { internalType: "bool", name: "isProposeGuarded", type: "bool" }, + ], + internalType: "struct ZkTokenGovernor.ConstructorParams", + name: "params", + type: "tuple", + }, + ], + stateMutability: "nonpayable", + type: "constructor", + }, + { inputs: [], name: "Empty", type: "error" }, + { inputs: [], name: "InvalidShortString", type: "error" }, + { + inputs: [{ internalType: "string", name: "str", type: "string" }], + name: "StringTooLong", + type: "error", + }, + { inputs: [], name: "Unauthorized", type: "error" }, + { inputs: [], name: "UncancelableProposalState", type: "error" }, + { anonymous: false, inputs: [], name: "EIP712DomainChanged", type: "event" }, + { + anonymous: false, + inputs: [ + { indexed: false, internalType: "bool", name: "oldState", type: "bool" }, + { indexed: false, internalType: "bool", name: "newState", type: "bool" }, + ], + name: "IsProposeGuardedToggled", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint64", + name: "oldVoteExtension", + type: "uint64", + }, + { + indexed: false, + internalType: "uint64", + name: "newVoteExtension", + type: "uint64", + }, + ], + name: "LateQuorumVoteExtensionSet", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "proposalId", + type: "uint256", + }, + ], + name: "ProposalCanceled", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "proposalId", + type: "uint256", + }, + { + indexed: false, + internalType: "address", + name: "proposer", + type: "address", + }, + { + indexed: false, + internalType: "address[]", + name: "targets", + type: "address[]", + }, + { + indexed: false, + internalType: "uint256[]", + name: "values", + type: "uint256[]", + }, + { + indexed: false, + internalType: "string[]", + name: "signatures", + type: "string[]", + }, + { + indexed: false, + internalType: "bytes[]", + name: "calldatas", + type: "bytes[]", + }, + { + indexed: false, + internalType: "uint256", + name: "voteStart", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "voteEnd", + type: "uint256", + }, + { + indexed: false, + internalType: "string", + name: "description", + type: "string", + }, + ], + name: "ProposalCreated", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "proposalId", + type: "uint256", + }, + ], + name: "ProposalExecuted", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "uint256", + name: "proposalId", + type: "uint256", + }, + { + indexed: false, + internalType: "uint64", + name: "extendedDeadline", + type: "uint64", + }, + ], + name: "ProposalExtended", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "proposalId", + type: "uint256", + }, + { indexed: false, internalType: "uint256", name: "eta", type: "uint256" }, + ], + name: "ProposalQueued", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "oldProposalThreshold", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "newProposalThreshold", + type: "uint256", + }, + ], + name: "ProposalThresholdSet", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "oldQuorum", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "newQuorum", + type: "uint256", + }, + ], + name: "QuorumUpdated", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "oldTimelock", + type: "address", + }, + { + indexed: false, + internalType: "address", + name: "newTimelock", + type: "address", + }, + ], + name: "TimelockChange", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "voter", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "proposalId", + type: "uint256", + }, + { indexed: false, internalType: "uint8", name: "support", type: "uint8" }, + { + indexed: false, + internalType: "uint256", + name: "weight", + type: "uint256", + }, + { + indexed: false, + internalType: "string", + name: "reason", + type: "string", + }, + ], + name: "VoteCast", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "voter", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "proposalId", + type: "uint256", + }, + { indexed: false, internalType: "uint8", name: "support", type: "uint8" }, + { + indexed: false, + internalType: "uint256", + name: "weight", + type: "uint256", + }, + { + indexed: false, + internalType: "string", + name: "reason", + type: "string", + }, + { indexed: false, internalType: "bytes", name: "params", type: "bytes" }, + ], + name: "VoteCastWithParams", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "oldVotingDelay", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "newVotingDelay", + type: "uint256", + }, + ], + name: "VotingDelaySet", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "oldVotingPeriod", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "newVotingPeriod", + type: "uint256", + }, + ], + name: "VotingPeriodSet", + type: "event", + }, + { + inputs: [], + name: "BALLOT_TYPEHASH", + outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "CLOCK_MODE", + outputs: [{ internalType: "string", name: "", type: "string" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "COUNTING_MODE", + outputs: [{ internalType: "string", name: "", type: "string" }], + stateMutability: "pure", + type: "function", + }, + { + inputs: [], + name: "EXTENDED_BALLOT_TYPEHASH", + outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "PROPOSE_GUARDIAN", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "VETO_GUARDIAN", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address[]", name: "_targets", type: "address[]" }, + { internalType: "uint256[]", name: "_values", type: "uint256[]" }, + { internalType: "bytes[]", name: "_calldatas", type: "bytes[]" }, + { internalType: "bytes32", name: "_descriptionHash", type: "bytes32" }, + ], + name: "cancel", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "uint8", name: "support", type: "uint8" }, + ], + name: "castVote", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "uint8", name: "support", type: "uint8" }, + { internalType: "uint8", name: "v", type: "uint8" }, + { internalType: "bytes32", name: "r", type: "bytes32" }, + { internalType: "bytes32", name: "s", type: "bytes32" }, + ], + name: "castVoteBySig", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "uint8", name: "support", type: "uint8" }, + { internalType: "string", name: "reason", type: "string" }, + ], + name: "castVoteWithReason", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "uint8", name: "support", type: "uint8" }, + { internalType: "string", name: "reason", type: "string" }, + { internalType: "bytes", name: "params", type: "bytes" }, + ], + name: "castVoteWithReasonAndParams", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "_proposalId", type: "uint256" }, + { internalType: "uint8", name: "_support", type: "uint8" }, + { internalType: "string", name: "_reason", type: "string" }, + { internalType: "bytes", name: "_params", type: "bytes" }, + { internalType: "uint8", name: "_v", type: "uint8" }, + { internalType: "bytes32", name: "_r", type: "bytes32" }, + { internalType: "bytes32", name: "_s", type: "bytes32" }, + ], + name: "castVoteWithReasonAndParamsBySig", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "clock", + outputs: [{ internalType: "uint48", name: "", type: "uint48" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "eip712Domain", + outputs: [ + { internalType: "bytes1", name: "fields", type: "bytes1" }, + { internalType: "string", name: "name", type: "string" }, + { internalType: "string", name: "version", type: "string" }, + { internalType: "uint256", name: "chainId", type: "uint256" }, + { internalType: "address", name: "verifyingContract", type: "address" }, + { internalType: "bytes32", name: "salt", type: "bytes32" }, + { internalType: "uint256[]", name: "extensions", type: "uint256[]" }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address[]", name: "targets", type: "address[]" }, + { internalType: "uint256[]", name: "values", type: "uint256[]" }, + { internalType: "bytes[]", name: "calldatas", type: "bytes[]" }, + { internalType: "bytes32", name: "descriptionHash", type: "bytes32" }, + ], + name: "execute", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "payable", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "", type: "address" }], + name: "fractionalVoteNonce", + outputs: [{ internalType: "uint128", name: "", type: "uint128" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "account", type: "address" }, + { internalType: "uint256", name: "timepoint", type: "uint256" }, + ], + name: "getVotes", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "account", type: "address" }, + { internalType: "uint256", name: "timepoint", type: "uint256" }, + { internalType: "bytes", name: "params", type: "bytes" }, + ], + name: "getVotesWithParams", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "address", name: "account", type: "address" }, + ], + name: "hasVoted", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address[]", name: "targets", type: "address[]" }, + { internalType: "uint256[]", name: "values", type: "uint256[]" }, + { internalType: "bytes[]", name: "calldatas", type: "bytes[]" }, + { internalType: "bytes32", name: "descriptionHash", type: "bytes32" }, + ], + name: "hashProposal", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "pure", + type: "function", + }, + { + inputs: [], + name: "isProposeGuarded", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "lateQuorumVoteExtension", + outputs: [{ internalType: "uint64", name: "", type: "uint64" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "name", + outputs: [{ internalType: "string", name: "", type: "string" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "", type: "address" }, + { internalType: "address", name: "", type: "address" }, + { internalType: "uint256[]", name: "", type: "uint256[]" }, + { internalType: "uint256[]", name: "", type: "uint256[]" }, + { internalType: "bytes", name: "", type: "bytes" }, + ], + name: "onERC1155BatchReceived", + outputs: [{ internalType: "bytes4", name: "", type: "bytes4" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "", type: "address" }, + { internalType: "address", name: "", type: "address" }, + { internalType: "uint256", name: "", type: "uint256" }, + { internalType: "uint256", name: "", type: "uint256" }, + { internalType: "bytes", name: "", type: "bytes" }, + ], + name: "onERC1155Received", + outputs: [{ internalType: "bytes4", name: "", type: "bytes4" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "", type: "address" }, + { internalType: "address", name: "", type: "address" }, + { internalType: "uint256", name: "", type: "uint256" }, + { internalType: "bytes", name: "", type: "bytes" }, + ], + name: "onERC721Received", + outputs: [{ internalType: "bytes4", name: "", type: "bytes4" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "_proposalId", type: "uint256" }], + name: "proposalDeadline", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + name: "proposalEta", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + name: "proposalProposer", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + name: "proposalSnapshot", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "proposalThreshold", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], + name: "proposalVotes", + outputs: [ + { internalType: "uint256", name: "againstVotes", type: "uint256" }, + { internalType: "uint256", name: "forVotes", type: "uint256" }, + { internalType: "uint256", name: "abstainVotes", type: "uint256" }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address[]", name: "targets", type: "address[]" }, + { internalType: "uint256[]", name: "values", type: "uint256[]" }, + { internalType: "bytes[]", name: "calldatas", type: "bytes[]" }, + { internalType: "string", name: "description", type: "string" }, + ], + name: "propose", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address[]", name: "targets", type: "address[]" }, + { internalType: "uint256[]", name: "values", type: "uint256[]" }, + { internalType: "bytes[]", name: "calldatas", type: "bytes[]" }, + { internalType: "bytes32", name: "descriptionHash", type: "bytes32" }, + ], + name: "queue", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "_voteStart", type: "uint256" }], + name: "quorum", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "target", type: "address" }, + { internalType: "uint256", name: "value", type: "uint256" }, + { internalType: "bytes", name: "data", type: "bytes" }, + ], + name: "relay", + outputs: [], + stateMutability: "payable", + type: "function", + }, + { + inputs: [{ internalType: "bool", name: "_isProposeGuarded", type: "bool" }], + name: "setIsProposeGuarded", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint64", name: "newVoteExtension", type: "uint64" }, + ], + name: "setLateQuorumVoteExtension", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "uint256", + name: "newProposalThreshold", + type: "uint256", + }, + ], + name: "setProposalThreshold", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "uint224", name: "_amount", type: "uint224" }], + name: "setQuorum", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "newVotingDelay", type: "uint256" }, + ], + name: "setVotingDelay", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "newVotingPeriod", type: "uint256" }, + ], + name: "setVotingPeriod", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "_proposalId", type: "uint256" }], + name: "state", + outputs: [ + { internalType: "enum IGovernor.ProposalState", name: "", type: "uint8" }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "bytes4", name: "_interfaceId", type: "bytes4" }], + name: "supportsInterface", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "timelock", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "token", + outputs: [{ internalType: "contract IERC5805", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "contract TimelockController", + name: "newTimelock", + type: "address", + }, + ], + name: "updateTimelock", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "version", + outputs: [{ internalType: "string", name: "", type: "string" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "proposalId", type: "uint256" }, + { internalType: "address", name: "account", type: "address" }, + ], + name: "voteWeightCast", + outputs: [{ internalType: "uint128", name: "", type: "uint128" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "votingDelay", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "votingPeriod", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { stateMutability: "payable", type: "receive" }, +] as const; diff --git a/apps/api/src/clients/zk/abi/index.ts b/apps/api/src/clients/zk/abi/index.ts new file mode 100644 index 000000000..d49549a68 --- /dev/null +++ b/apps/api/src/clients/zk/abi/index.ts @@ -0,0 +1,2 @@ +export * from "./token.ts"; +export * from "./governor.ts"; diff --git a/apps/api/src/clients/zk/abi/token.ts b/apps/api/src/clients/zk/abi/token.ts new file mode 100644 index 000000000..ae8b5ea9c --- /dev/null +++ b/apps/api/src/clients/zk/abi/token.ts @@ -0,0 +1,547 @@ +export const TokenAbi = [ + { + inputs: [{ internalType: "uint256", name: "expiry", type: "uint256" }], + name: "DelegateSignatureExpired", + type: "error", + }, + { inputs: [], name: "DelegateSignatureIsInvalid", type: "error" }, + { inputs: [], name: "ERC6372InconsistentClock", type: "error" }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "owner", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "spender", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "value", + type: "uint256", + }, + ], + name: "Approval", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "delegator", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "fromDelegate", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "toDelegate", + type: "address", + }, + ], + name: "DelegateChanged", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "delegate", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "previousBalance", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "newBalance", + type: "uint256", + }, + ], + name: "DelegateVotesChanged", + type: "event", + }, + { anonymous: false, inputs: [], name: "EIP712DomainChanged", type: "event" }, + { + anonymous: false, + inputs: [ + { indexed: false, internalType: "uint8", name: "version", type: "uint8" }, + ], + name: "Initialized", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "bytes32", name: "role", type: "bytes32" }, + { + indexed: true, + internalType: "bytes32", + name: "previousAdminRole", + type: "bytes32", + }, + { + indexed: true, + internalType: "bytes32", + name: "newAdminRole", + type: "bytes32", + }, + ], + name: "RoleAdminChanged", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "bytes32", name: "role", type: "bytes32" }, + { + indexed: true, + internalType: "address", + name: "account", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "sender", + type: "address", + }, + ], + name: "RoleGranted", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "bytes32", name: "role", type: "bytes32" }, + { + indexed: true, + internalType: "address", + name: "account", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "sender", + type: "address", + }, + ], + name: "RoleRevoked", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "address", name: "from", type: "address" }, + { indexed: true, internalType: "address", name: "to", type: "address" }, + { + indexed: false, + internalType: "uint256", + name: "value", + type: "uint256", + }, + ], + name: "Transfer", + type: "event", + }, + { + inputs: [], + name: "BURNER_ADMIN_ROLE", + outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "BURNER_ROLE", + outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "CLOCK_MODE", + outputs: [{ internalType: "string", name: "", type: "string" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "DEFAULT_ADMIN_ROLE", + outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "DELEGATION_TYPEHASH", + outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "DOMAIN_SEPARATOR", + outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "MINTER_ADMIN_ROLE", + outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "MINTER_ROLE", + outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "owner", type: "address" }, + { internalType: "address", name: "spender", type: "address" }, + ], + name: "allowance", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "spender", type: "address" }, + { internalType: "uint256", name: "amount", type: "uint256" }, + ], + name: "approve", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "account", type: "address" }], + name: "balanceOf", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "_from", type: "address" }, + { internalType: "uint256", name: "_amount", type: "uint256" }, + ], + name: "burn", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "account", type: "address" }, + { internalType: "uint32", name: "pos", type: "uint32" }, + ], + name: "checkpoints", + outputs: [ + { + components: [ + { internalType: "uint32", name: "fromBlock", type: "uint32" }, + { internalType: "uint224", name: "votes", type: "uint224" }, + ], + internalType: "struct ERC20VotesUpgradeable.Checkpoint", + name: "", + type: "tuple", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "clock", + outputs: [{ internalType: "uint48", name: "", type: "uint48" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "decimals", + outputs: [{ internalType: "uint8", name: "", type: "uint8" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "spender", type: "address" }, + { internalType: "uint256", name: "subtractedValue", type: "uint256" }, + ], + name: "decreaseAllowance", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "delegatee", type: "address" }], + name: "delegate", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "delegatee", type: "address" }, + { internalType: "uint256", name: "nonce", type: "uint256" }, + { internalType: "uint256", name: "expiry", type: "uint256" }, + { internalType: "uint8", name: "v", type: "uint8" }, + { internalType: "bytes32", name: "r", type: "bytes32" }, + { internalType: "bytes32", name: "s", type: "bytes32" }, + ], + name: "delegateBySig", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "_signer", type: "address" }, + { internalType: "address", name: "_delegatee", type: "address" }, + { internalType: "uint256", name: "_expiry", type: "uint256" }, + { internalType: "bytes", name: "_signature", type: "bytes" }, + ], + name: "delegateOnBehalf", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "account", type: "address" }], + name: "delegates", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "eip712Domain", + outputs: [ + { internalType: "bytes1", name: "fields", type: "bytes1" }, + { internalType: "string", name: "name", type: "string" }, + { internalType: "string", name: "version", type: "string" }, + { internalType: "uint256", name: "chainId", type: "uint256" }, + { internalType: "address", name: "verifyingContract", type: "address" }, + { internalType: "bytes32", name: "salt", type: "bytes32" }, + { internalType: "uint256[]", name: "extensions", type: "uint256[]" }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "timepoint", type: "uint256" }], + name: "getPastTotalSupply", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "account", type: "address" }, + { internalType: "uint256", name: "timepoint", type: "uint256" }, + ], + name: "getPastVotes", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "bytes32", name: "role", type: "bytes32" }], + name: "getRoleAdmin", + outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "account", type: "address" }], + name: "getVotes", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "bytes32", name: "role", type: "bytes32" }, + { internalType: "address", name: "account", type: "address" }, + ], + name: "grantRole", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "bytes32", name: "role", type: "bytes32" }, + { internalType: "address", name: "account", type: "address" }, + ], + name: "hasRole", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "spender", type: "address" }, + { internalType: "uint256", name: "addedValue", type: "uint256" }, + ], + name: "increaseAllowance", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "_admin", type: "address" }, + { internalType: "address", name: "_mintReceiver", type: "address" }, + { internalType: "uint256", name: "_mintAmount", type: "uint256" }, + ], + name: "initialize", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "initializeV2", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "_to", type: "address" }, + { internalType: "uint256", name: "_amount", type: "uint256" }, + ], + name: "mint", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "name", + outputs: [{ internalType: "string", name: "", type: "string" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "owner", type: "address" }], + name: "nonces", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "account", type: "address" }], + name: "numCheckpoints", + outputs: [{ internalType: "uint32", name: "", type: "uint32" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "owner", type: "address" }, + { internalType: "address", name: "spender", type: "address" }, + { internalType: "uint256", name: "value", type: "uint256" }, + { internalType: "uint256", name: "deadline", type: "uint256" }, + { internalType: "uint8", name: "v", type: "uint8" }, + { internalType: "bytes32", name: "r", type: "bytes32" }, + { internalType: "bytes32", name: "s", type: "bytes32" }, + ], + name: "permit", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "bytes32", name: "role", type: "bytes32" }, + { internalType: "address", name: "account", type: "address" }, + ], + name: "renounceRole", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "bytes32", name: "role", type: "bytes32" }, + { internalType: "address", name: "account", type: "address" }, + ], + name: "revokeRole", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "bytes4", name: "interfaceId", type: "bytes4" }], + name: "supportsInterface", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "symbol", + outputs: [{ internalType: "string", name: "", type: "string" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "totalSupply", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "to", type: "address" }, + { internalType: "uint256", name: "amount", type: "uint256" }, + ], + name: "transfer", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "from", type: "address" }, + { internalType: "address", name: "to", type: "address" }, + { internalType: "uint256", name: "amount", type: "uint256" }, + ], + name: "transferFrom", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "nonpayable", + type: "function", + }, +] as const; diff --git a/apps/api/src/clients/zk/index.ts b/apps/api/src/clients/zk/index.ts new file mode 100644 index 000000000..e836f0664 --- /dev/null +++ b/apps/api/src/clients/zk/index.ts @@ -0,0 +1,119 @@ +import { + Account, + Address, + Chain, + Client, + fromHex, + toHex, + Transport, +} from "viem"; + +import { DAOClient } from "@/interfaces/client"; +import { GovernorBase } from "../governor.base"; +import { GovernorAbi } from "./abi"; +import { readContract } from "viem/actions"; + +export class ZKClient< + TTransport extends Transport = Transport, + TChain extends Chain = Chain, + TAccount extends Account | undefined = Account | undefined, + > + extends GovernorBase + implements DAOClient +{ + private abi: typeof GovernorAbi; + private address: Address; + + constructor(client: Client, address: Address) { + super(client); + this.address = address; + this.abi = GovernorAbi; + } + + getDaoId(): string { + return "ZK"; + } + + async getQuorum(): Promise { + return readContract(this.client, { + abi: this.abi, + address: this.address, + functionName: "quorum", + args: [BigInt(Math.floor(Date.now() / 1000))], + }); + } + + async getProposalThreshold(): Promise { + return readContract(this.client, { + abi: this.abi, + address: this.address, + functionName: "proposalThreshold", + }); + } + + async getVotingDelay(): Promise { + return readContract(this.client, { + abi: this.abi, + address: this.address, + functionName: "votingDelay", + }); + } + + async getVotingPeriod(): Promise { + return readContract(this.client, { + abi: this.abi, + address: this.address, + functionName: "votingPeriod", + }); + } + + async getTimelockDelay(): Promise { + const timelockAddress = await readContract(this.client, { + abi: this.abi, + address: this.address, + functionName: "timelock", + }); + return readContract(this.client, { + abi: [ + { + inputs: [], + name: "getMinDelay", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, + ], + address: timelockAddress, + functionName: "getMinDelay", + }); + } + + async getCurrentBlockNumber(): Promise { + const result = await this.client.request({ + method: "eth_blockNumber", + }); + return fromHex(result, "number"); + } + + async getBlockTime(blockNumber: number): Promise { + const block = await this.client.request({ + method: "eth_getBlockByNumber", + params: [toHex(blockNumber), false], + }); + return block?.timestamp ? fromHex(block.timestamp, "number") : null; + } + + calculateQuorum(votes: { + forVotes: bigint; + againstVotes: bigint; + abstainVotes: bigint; + }): bigint { + return votes.forVotes; + } +} diff --git a/apps/indexer/src/api/controllers/account-balance/historical.ts b/apps/api/src/controllers/account-balance/historical.ts similarity index 94% rename from apps/indexer/src/api/controllers/account-balance/historical.ts rename to apps/api/src/controllers/account-balance/historical.ts index be5ffd09a..f7594221e 100644 --- a/apps/indexer/src/api/controllers/account-balance/historical.ts +++ b/apps/api/src/controllers/account-balance/historical.ts @@ -1,12 +1,12 @@ import { OpenAPIHono as Hono, createRoute } from "@hono/zod-openapi"; -import { HistoricalBalancesService } from "@/api/services"; +import { HistoricalBalancesService } from "@/services"; import { HistoricalBalancesResponseMapper, HistoricalBalanceRequestParamsSchema, HistoricalBalanceRequestQuerySchema, HistoricalBalancesResponseSchema, -} from "@/api/mappers"; +} from "@/mappers"; export function historicalBalances( app: Hono, diff --git a/apps/indexer/src/api/controllers/account-balance/index.ts b/apps/api/src/controllers/account-balance/index.ts similarity index 100% rename from apps/indexer/src/api/controllers/account-balance/index.ts rename to apps/api/src/controllers/account-balance/index.ts diff --git a/apps/indexer/src/api/controllers/account-balance/interactions.ts b/apps/api/src/controllers/account-balance/interactions.ts similarity index 100% rename from apps/indexer/src/api/controllers/account-balance/interactions.ts rename to apps/api/src/controllers/account-balance/interactions.ts diff --git a/apps/indexer/src/api/controllers/account-balance/listing.ts b/apps/api/src/controllers/account-balance/listing.ts similarity index 96% rename from apps/indexer/src/api/controllers/account-balance/listing.ts rename to apps/api/src/controllers/account-balance/listing.ts index 868893f24..18f363adb 100644 --- a/apps/indexer/src/api/controllers/account-balance/listing.ts +++ b/apps/api/src/controllers/account-balance/listing.ts @@ -1,14 +1,14 @@ import { createRoute, OpenAPIHono as Hono, z } from "@hono/zod-openapi"; -import { AccountBalanceService } from "@/api/services"; +import { AccountBalanceService } from "@/services"; import { AccountBalancesRequestSchema, AccountBalancesResponseMapper, AccountBalancesResponseSchema, -} from "@/api/mappers"; +} from "@/mappers"; import { AccountBalanceResponseMapper, AccountBalanceResponseSchema, -} from "@/api/mappers"; +} from "@/mappers"; import { getAddress, isAddress } from "viem"; import { DaoIdEnum } from "@/lib/enums"; diff --git a/apps/indexer/src/api/controllers/account-balance/variations.ts b/apps/api/src/controllers/account-balance/variations.ts similarity index 97% rename from apps/indexer/src/api/controllers/account-balance/variations.ts rename to apps/api/src/controllers/account-balance/variations.ts index 8307bbae8..b64e13f91 100644 --- a/apps/indexer/src/api/controllers/account-balance/variations.ts +++ b/apps/api/src/controllers/account-balance/variations.ts @@ -7,8 +7,8 @@ import { AccountBalanceVariationsResponseSchema, AccountBalanceVariationsByAccountIdResponseMapper, AccountBalanceVariationsByAccountIdResponseSchema, -} from "@/api/mappers"; -import { BalanceVariationsService } from "@/api/services"; +} from "@/mappers"; +import { BalanceVariationsService } from "@/services"; export function accountBalanceVariations( app: Hono, diff --git a/apps/indexer/src/api/controllers/dao/index.ts b/apps/api/src/controllers/dao/index.ts similarity index 88% rename from apps/indexer/src/api/controllers/dao/index.ts rename to apps/api/src/controllers/dao/index.ts index e636b40e5..e71f864bf 100644 --- a/apps/indexer/src/api/controllers/dao/index.ts +++ b/apps/api/src/controllers/dao/index.ts @@ -1,6 +1,6 @@ import { OpenAPIHono as Hono, createRoute } from "@hono/zod-openapi"; -import { DaoService } from "@/api/services"; -import { DaoResponseSchema } from "@/api/mappers"; +import { DaoService } from "@/services"; +import { DaoResponseSchema } from "@/mappers"; export function dao(app: Hono, service: DaoService) { app.openapi( diff --git a/apps/indexer/src/api/controllers/delegation-percentage/index.ts b/apps/api/src/controllers/delegation-percentage/index.ts similarity index 92% rename from apps/indexer/src/api/controllers/delegation-percentage/index.ts rename to apps/api/src/controllers/delegation-percentage/index.ts index d2bd0d5e2..0a6af7d80 100644 --- a/apps/indexer/src/api/controllers/delegation-percentage/index.ts +++ b/apps/api/src/controllers/delegation-percentage/index.ts @@ -1,10 +1,10 @@ import { OpenAPIHono as Hono, createRoute } from "@hono/zod-openapi"; -import { DelegationPercentageService } from "@/api/services"; +import { DelegationPercentageService } from "@/services"; import { DelegationPercentageRequestSchema, DelegationPercentageResponseSchema, toApi, -} from "@/api/mappers/"; +} from "@/mappers/"; export function delegationPercentage( app: Hono, diff --git a/apps/indexer/src/api/controllers/delegations/delegations.ts b/apps/api/src/controllers/delegations/delegations.ts similarity index 90% rename from apps/indexer/src/api/controllers/delegations/delegations.ts rename to apps/api/src/controllers/delegations/delegations.ts index cb9d640ff..fa8512a77 100644 --- a/apps/indexer/src/api/controllers/delegations/delegations.ts +++ b/apps/api/src/controllers/delegations/delegations.ts @@ -4,8 +4,8 @@ import { DelegationsResponseSchema, delegationMapper, DelegationsRequestParamsSchema, -} from "@/api/mappers/delegations"; -import { DelegationsService } from "@/api/services/delegations/current"; +} from "@/mappers/delegations"; +import { DelegationsService } from "@/services/delegations/current"; export function delegations(app: Hono, service: DelegationsService) { app.openapi( diff --git a/apps/indexer/src/api/controllers/delegations/historical.ts b/apps/api/src/controllers/delegations/historical.ts similarity index 93% rename from apps/indexer/src/api/controllers/delegations/historical.ts rename to apps/api/src/controllers/delegations/historical.ts index 1c286d76d..d1c8b2109 100644 --- a/apps/indexer/src/api/controllers/delegations/historical.ts +++ b/apps/api/src/controllers/delegations/historical.ts @@ -5,8 +5,8 @@ import { HistoricalDelegationsRequestParamsSchema, HistoricalDelegationsRequestQuerySchema, DelegationsResponseSchema, -} from "@/api/mappers/delegations"; -import { HistoricalDelegationsService } from "@/api/services/delegations"; +} from "@/mappers/delegations"; +import { HistoricalDelegationsService } from "@/services/delegations"; export function historicalDelegations( app: Hono, diff --git a/apps/indexer/src/api/controllers/delegations/index.ts b/apps/api/src/controllers/delegations/index.ts similarity index 100% rename from apps/indexer/src/api/controllers/delegations/index.ts rename to apps/api/src/controllers/delegations/index.ts diff --git a/apps/indexer/src/api/controllers/governance-activity/controller.ts b/apps/api/src/controllers/governance-activity/controller.ts similarity index 99% rename from apps/indexer/src/api/controllers/governance-activity/controller.ts rename to apps/api/src/controllers/governance-activity/controller.ts index 4d8c94efe..8961d58ce 100644 --- a/apps/indexer/src/api/controllers/governance-activity/controller.ts +++ b/apps/api/src/controllers/governance-activity/controller.ts @@ -10,6 +10,9 @@ import { import { formatEther } from "viem"; interface GovernanceActivityRepository { + +constructor(private readonly db: Drizzle) {} + getActiveSupply(days: DaysEnum): Promise; getProposalsCompare( days: DaysEnum, diff --git a/apps/indexer/src/api/controllers/governance-activity/index.ts b/apps/api/src/controllers/governance-activity/index.ts similarity index 100% rename from apps/indexer/src/api/controllers/governance-activity/index.ts rename to apps/api/src/controllers/governance-activity/index.ts diff --git a/apps/indexer/src/api/controllers/governance-activity/types.ts b/apps/api/src/controllers/governance-activity/types.ts similarity index 100% rename from apps/indexer/src/api/controllers/governance-activity/types.ts rename to apps/api/src/controllers/governance-activity/types.ts diff --git a/apps/indexer/src/api/controllers/index.ts b/apps/api/src/controllers/index.ts similarity index 100% rename from apps/indexer/src/api/controllers/index.ts rename to apps/api/src/controllers/index.ts diff --git a/apps/indexer/src/api/controllers/last-update/index.ts b/apps/api/src/controllers/last-update/index.ts similarity index 85% rename from apps/indexer/src/api/controllers/last-update/index.ts rename to apps/api/src/controllers/last-update/index.ts index 283657f2b..d8bb0a69d 100644 --- a/apps/indexer/src/api/controllers/last-update/index.ts +++ b/apps/api/src/controllers/last-update/index.ts @@ -1,7 +1,7 @@ import { OpenAPIHono as Hono, createRoute, z } from "@hono/zod-openapi"; -import { ChartType } from "@/api/mappers/"; -import { LastUpdateService } from "@/api/services"; -import { LastUpdateRepositoryImpl } from "@/api/repositories"; +import { ChartType } from "@/mappers/"; +import { LastUpdateService } from "@/services"; +import { LastUpdateRepositoryImpl } from "@/repositories"; export function lastUpdate(app: Hono) { const repository = new LastUpdateRepositoryImpl(); diff --git a/apps/indexer/src/api/controllers/proposals/index.ts b/apps/api/src/controllers/proposals/index.ts similarity index 100% rename from apps/indexer/src/api/controllers/proposals/index.ts rename to apps/api/src/controllers/proposals/index.ts diff --git a/apps/indexer/src/api/controllers/proposals/proposals-activity.ts b/apps/api/src/controllers/proposals/proposals-activity.ts similarity index 93% rename from apps/indexer/src/api/controllers/proposals/proposals-activity.ts rename to apps/api/src/controllers/proposals/proposals-activity.ts index 2c8dd5474..03ce53f04 100644 --- a/apps/indexer/src/api/controllers/proposals/proposals-activity.ts +++ b/apps/api/src/controllers/proposals/proposals-activity.ts @@ -2,11 +2,11 @@ import { OpenAPIHono as Hono, createRoute, z } from "@hono/zod-openapi"; import { getAddress, isAddress } from "viem"; import { DaoIdEnum } from "@/lib/enums"; -import { ProposalsActivityService } from "@/api/services"; -import { ProposalsActivityRepository, VoteFilter } from "@/api/repositories/"; +import { ProposalsActivityService } from "@/services"; +import { ProposalsActivityRepository, VoteFilter } from "@/repositories/"; import { CONTRACT_ADDRESSES } from "@/lib/constants"; import { DAOClient } from "@/interfaces/client"; -import { ProposalActivityResponseSchema } from "@/api/mappers"; +import { ProposalActivityResponseSchema } from "@/mappers"; export function proposalsActivity( app: Hono, diff --git a/apps/indexer/src/api/controllers/proposals/proposals.ts b/apps/api/src/controllers/proposals/proposals.ts similarity index 98% rename from apps/indexer/src/api/controllers/proposals/proposals.ts rename to apps/api/src/controllers/proposals/proposals.ts index db54730a0..77e35e455 100644 --- a/apps/indexer/src/api/controllers/proposals/proposals.ts +++ b/apps/api/src/controllers/proposals/proposals.ts @@ -1,6 +1,6 @@ import { OpenAPIHono as Hono, createRoute, z } from "@hono/zod-openapi"; -import { ProposalsService } from "@/api/services"; +import { ProposalsService } from "@/services"; import { ProposalsResponseSchema, ProposalsRequestSchema, @@ -11,7 +11,7 @@ import { VotersResponseSchema, VotesRequestSchema, VotesResponseSchema, -} from "@/api/mappers"; +} from "@/mappers"; import { DAOClient } from "@/interfaces"; export function proposals( diff --git a/apps/indexer/src/api/controllers/token-metrics/index.ts b/apps/api/src/controllers/token-metrics/index.ts similarity index 91% rename from apps/indexer/src/api/controllers/token-metrics/index.ts rename to apps/api/src/controllers/token-metrics/index.ts index 3c550d60a..6ccdb2e20 100644 --- a/apps/indexer/src/api/controllers/token-metrics/index.ts +++ b/apps/api/src/controllers/token-metrics/index.ts @@ -1,10 +1,10 @@ import { OpenAPIHono as Hono, createRoute } from "@hono/zod-openapi"; -import { TokenMetricsService } from "@/api/services/token-metrics"; +import { TokenMetricsService } from "@/services/token-metrics"; import { TokenMetricsRequestSchema, TokenMetricsResponseSchema, toTokenMetricsApi, -} from "@/api/mappers/token-metrics"; +} from "@/mappers/token-metrics"; import { metricTypeArray } from "@/lib/constants"; export function tokenMetrics(app: Hono, service: TokenMetricsService) { diff --git a/apps/indexer/src/api/controllers/token/index.ts b/apps/api/src/controllers/token/index.ts similarity index 100% rename from apps/indexer/src/api/controllers/token/index.ts rename to apps/api/src/controllers/token/index.ts diff --git a/apps/indexer/src/api/controllers/token/token-distribution.ts b/apps/api/src/controllers/token/token-distribution.ts similarity index 98% rename from apps/indexer/src/api/controllers/token/token-distribution.ts rename to apps/api/src/controllers/token/token-distribution.ts index 1b76beb5b..d4ab0a90d 100644 --- a/apps/indexer/src/api/controllers/token/token-distribution.ts +++ b/apps/api/src/controllers/token/token-distribution.ts @@ -5,6 +5,9 @@ import { DaysEnum, DaysOpts } from "@/lib/enums"; import { MetricTypesEnum } from "@/lib/constants"; interface TokenDistributionRepository { + +constructor(private readonly db: Drizzle) {} + getSupplyComparison( metricType: string, days: DaysEnum, diff --git a/apps/indexer/src/api/controllers/token/token-historical-data.ts b/apps/api/src/controllers/token/token-historical-data.ts similarity index 98% rename from apps/indexer/src/api/controllers/token/token-historical-data.ts rename to apps/api/src/controllers/token/token-historical-data.ts index 844010d9f..cfa274ca3 100644 --- a/apps/indexer/src/api/controllers/token/token-historical-data.ts +++ b/apps/api/src/controllers/token/token-historical-data.ts @@ -3,7 +3,7 @@ import { OpenAPIHono as Hono, createRoute } from "@hono/zod-openapi"; import { TokenHistoricalPriceRequest, TokenHistoricalPriceResponse, -} from "@/api/mappers"; +} from "@/mappers"; export interface TokenHistoricalDataClient { getHistoricalTokenData( diff --git a/apps/indexer/src/api/controllers/token/token-properties.ts b/apps/api/src/controllers/token/token-properties.ts similarity index 93% rename from apps/indexer/src/api/controllers/token/token-properties.ts rename to apps/api/src/controllers/token/token-properties.ts index cfa61405a..88db476f0 100644 --- a/apps/indexer/src/api/controllers/token/token-properties.ts +++ b/apps/api/src/controllers/token/token-properties.ts @@ -1,8 +1,8 @@ import { OpenAPIHono as Hono, createRoute, z } from "@hono/zod-openapi"; import { DaoIdEnum } from "@/lib/enums"; -import { TokenService } from "@/api/services"; -import { TokenPropertiesResponseSchema, TokenMapper } from "@/api/mappers"; +import { TokenService } from "@/services"; +import { TokenPropertiesResponseSchema, TokenMapper } from "@/mappers"; import { CONTRACT_ADDRESSES } from "@/lib/constants"; interface TokenPriceClient { diff --git a/apps/indexer/src/api/controllers/transactions/index.ts b/apps/api/src/controllers/transactions/index.ts similarity index 95% rename from apps/indexer/src/api/controllers/transactions/index.ts rename to apps/api/src/controllers/transactions/index.ts index ce474f52b..3f1ffef47 100644 --- a/apps/indexer/src/api/controllers/transactions/index.ts +++ b/apps/api/src/controllers/transactions/index.ts @@ -1,10 +1,10 @@ import { OpenAPIHono as Hono, createRoute } from "@hono/zod-openapi"; -import { TransactionsService } from "@/api/services"; +import { TransactionsService } from "@/services"; import { TransactionsRequestSchema, TransactionsResponseSchema, -} from "@/api/mappers/"; +} from "@/mappers/"; export function transactions(app: Hono, service: TransactionsService) { app.openapi( diff --git a/apps/indexer/src/api/controllers/transfers/index.ts b/apps/api/src/controllers/transfers/index.ts similarity index 95% rename from apps/indexer/src/api/controllers/transfers/index.ts rename to apps/api/src/controllers/transfers/index.ts index 5993134d6..98053b89a 100644 --- a/apps/indexer/src/api/controllers/transfers/index.ts +++ b/apps/api/src/controllers/transfers/index.ts @@ -1,11 +1,11 @@ import { OpenAPIHono as Hono, createRoute } from "@hono/zod-openapi"; -import { TransfersService } from "@/api/services"; +import { TransfersService } from "@/services"; import { TransfersRequestRouteSchema, TransfersRequestQuerySchema, TransfersResponseSchema, -} from "@/api/mappers/"; +} from "@/mappers/"; export function transfers(app: Hono, service: TransfersService) { app.openapi( diff --git a/apps/indexer/src/api/controllers/treasury/index.ts b/apps/api/src/controllers/treasury/index.ts similarity index 97% rename from apps/indexer/src/api/controllers/treasury/index.ts rename to apps/api/src/controllers/treasury/index.ts index 607ee79d8..04715d772 100644 --- a/apps/indexer/src/api/controllers/treasury/index.ts +++ b/apps/api/src/controllers/treasury/index.ts @@ -1,10 +1,10 @@ import { OpenAPIHono as Hono, createRoute } from "@hono/zod-openapi"; -import { TreasuryService } from "@/api/services/treasury"; +import { TreasuryService } from "@/services/treasury"; import { TreasuryResponseSchema, TreasuryQuerySchema, -} from "@/api/mappers/treasury"; +} from "@/mappers/treasury"; export function treasury( app: Hono, diff --git a/apps/indexer/src/api/controllers/voting-power/historical.ts b/apps/api/src/controllers/voting-power/historical.ts similarity index 97% rename from apps/indexer/src/api/controllers/voting-power/historical.ts rename to apps/api/src/controllers/voting-power/historical.ts index 25ac5987b..d551933c7 100644 --- a/apps/indexer/src/api/controllers/voting-power/historical.ts +++ b/apps/api/src/controllers/voting-power/historical.ts @@ -1,13 +1,13 @@ import { OpenAPIHono as Hono, createRoute } from "@hono/zod-openapi"; -import { VotingPowerService } from "@/api/services"; +import { VotingPowerService } from "@/services"; import { HistoricalVotingPowersResponseSchema, HistoricalVotingPowerRequestQuerySchema, HistoricalVotingPowersResponseMapper, HistoricalVotingPowerRequestParamsSchema, HistoricalVotingPowerGlobalQuerySchema, -} from "@/api/mappers"; +} from "@/mappers"; export function historicalVotingPower(app: Hono, service: VotingPowerService) { app.openapi( diff --git a/apps/indexer/src/api/controllers/voting-power/index.ts b/apps/api/src/controllers/voting-power/index.ts similarity index 100% rename from apps/indexer/src/api/controllers/voting-power/index.ts rename to apps/api/src/controllers/voting-power/index.ts diff --git a/apps/indexer/src/api/controllers/voting-power/listing.ts b/apps/api/src/controllers/voting-power/listing.ts similarity index 94% rename from apps/indexer/src/api/controllers/voting-power/listing.ts rename to apps/api/src/controllers/voting-power/listing.ts index 5f572d8d3..e67fb54fb 100644 --- a/apps/indexer/src/api/controllers/voting-power/listing.ts +++ b/apps/api/src/controllers/voting-power/listing.ts @@ -1,13 +1,13 @@ import { OpenAPIHono as Hono, createRoute, z } from "@hono/zod-openapi"; -import { VotingPowerService } from "@/api/services"; +import { VotingPowerService } from "@/services"; import { VotingPowersRequestSchema, VotingPowersResponseSchema, VotingPowersMapper, VotingPowerResponseSchema, -} from "@/api/mappers/"; +} from "@/mappers/"; import { getAddress, isAddress } from "viem"; -import { VotingPowerMapper } from "@/api/mappers/voting-power/variations"; +import { VotingPowerMapper } from "@/mappers/voting-power/variations"; export function votingPowers(app: Hono, service: VotingPowerService) { app.openapi( diff --git a/apps/indexer/src/api/controllers/voting-power/variations.ts b/apps/api/src/controllers/voting-power/variations.ts similarity index 97% rename from apps/indexer/src/api/controllers/voting-power/variations.ts rename to apps/api/src/controllers/voting-power/variations.ts index 791ec172d..2727b6c2f 100644 --- a/apps/indexer/src/api/controllers/voting-power/variations.ts +++ b/apps/api/src/controllers/voting-power/variations.ts @@ -1,6 +1,6 @@ import { OpenAPIHono as Hono, createRoute } from "@hono/zod-openapi"; -import { VotingPowerService } from "@/api/services"; +import { VotingPowerService } from "@/services"; import { VotingPowerVariationsByAccountIdRequestQuerySchema, VotingPowerVariationsByAccountIdResponseSchema, @@ -9,7 +9,7 @@ import { VotingPowerVariationsResponseMapper, VotingPowerVariationsRequestQuerySchema, VotingPowerVariationsByAccountIdRequestParamsSchema, -} from "@/api/mappers/"; +} from "@/mappers/"; export function votingPowerVariations(app: Hono, service: VotingPowerService) { app.openapi( diff --git a/apps/api/src/database/index.ts b/apps/api/src/database/index.ts new file mode 100644 index 000000000..faff6e375 --- /dev/null +++ b/apps/api/src/database/index.ts @@ -0,0 +1,32 @@ +import type * as schema from "./schema"; + +import type { NodePgDatabase } from "drizzle-orm/node-postgres"; +import type { PgliteDatabase } from "drizzle-orm/pglite"; + +/** + * Full Drizzle database type with write capabilities + * This follows Ponder's Drizzle type definition pattern from: + * node_modules/ponder/src/types/db.ts + * + * Supports: + * - NodePgDatabase: PostgreSQL via node-postgres driver + * - PgliteDatabase: PGlite embedded PostgreSQL + */ +export type Drizzle = + | NodePgDatabase + | PgliteDatabase; +/** + * Read-only Drizzle database type (used in Ponder API context) + * Omits write operations: insert, update, delete, transaction + */ +export type ReadonlyDrizzle = Omit< + Drizzle, + | "insert" + | "update" + | "delete" + | "transaction" + | "refreshMaterializedView" + | "_" +>; + +export * from "./schema"; diff --git a/apps/api/src/database/schema.ts b/apps/api/src/database/schema.ts new file mode 100644 index 000000000..0ba4f7de3 --- /dev/null +++ b/apps/api/src/database/schema.ts @@ -0,0 +1,252 @@ +import { + pgTable, + index, + bigint, + pgEnum, + primaryKey, +} from "drizzle-orm/pg-core"; +import { Address, zeroAddress } from "viem"; + +import { MetricTypesArray } from "@/lib/constants"; + +export const token = pgTable("token", (drizzle) => ({ + id: drizzle.text().primaryKey(), + name: drizzle.text(), + decimals: drizzle.integer().notNull(), + totalSupply: bigint({ mode: "bigint" }).notNull().default(0n), + delegatedSupply: bigint({ mode: "bigint" }).notNull().default(0n), + cexSupply: bigint({ mode: "bigint" }).notNull().default(0n), + dexSupply: bigint({ mode: "bigint" }).notNull().default(0n), + lendingSupply: bigint({ mode: "bigint" }).notNull().default(0n), + circulatingSupply: bigint({ mode: "bigint" }).notNull().default(0n), + treasury: bigint({ mode: "bigint" }).notNull().default(0n), +})); + +export const account = pgTable("account", (drizzle) => ({ + id: drizzle.text().primaryKey(), +})); + +export const accountBalance = pgTable( + "account_balance", + (drizzle) => ({ + accountId: drizzle.text("account_id").$type
().notNull(), + tokenId: drizzle.text("token_id").notNull(), + balance: bigint({ mode: "bigint" }).notNull(), + // This field represents for who the account is delegating their voting power to + delegate: drizzle.text().default(zeroAddress).notNull(), + }), + (table) => ({ + pk: primaryKey({ + columns: [table.accountId, table.tokenId], + }), + accountBalanceDelegateIdx: index().on(table.delegate), + }), +); + +export const accountPower = pgTable( + "account_power", + (drizzle) => ({ + accountId: drizzle.text("account_id").$type
().notNull(), + daoId: drizzle.text("dao_id").notNull(), + votingPower: bigint({ mode: "bigint" }).default(BigInt(0)).notNull(), + votesCount: drizzle.integer("votes_count").default(0).notNull(), + proposalsCount: drizzle.integer("proposals_count").default(0).notNull(), + delegationsCount: drizzle.integer("delegations_count").default(0).notNull(), + lastVoteTimestamp: drizzle + .bigint({ mode: "bigint" }) + .default(BigInt(0)) + .notNull(), + }), + (table) => ({ + pk: primaryKey({ + columns: [table.accountId], + }), + lastVoteTimestamp: index().on(table.lastVoteTimestamp), + }), +); + +export const votingPowerHistory = pgTable( + "voting_power_history", + (drizzle) => ({ + transactionHash: drizzle.text("transaction_hash").notNull(), + daoId: drizzle.text("dao_id").notNull(), + accountId: drizzle.text("account_id").$type
().notNull(), + votingPower: bigint({ mode: "bigint" }).notNull(), + delta: bigint({ mode: "bigint" }).notNull(), + deltaMod: bigint({ mode: "bigint" }).notNull(), + timestamp: bigint({ mode: "bigint" }).notNull(), + logIndex: drizzle.integer("log_index").notNull(), + }), + (table) => ({ + pk: primaryKey({ + columns: [table.transactionHash, table.accountId, table.logIndex], + }), + }), +); + +export const balanceHistory = pgTable( + "balance_history", + (drizzle) => ({ + transactionHash: drizzle.text("transaction_hash").notNull(), + daoId: drizzle.text("dao_id").notNull(), + accountId: drizzle.text("account_id").$type
().notNull(), + balance: bigint({ mode: "bigint" }).notNull(), + delta: bigint({ mode: "bigint" }).notNull(), + deltaMod: bigint({ mode: "bigint" }).notNull(), + timestamp: bigint({ mode: "bigint" }).notNull(), + logIndex: drizzle.integer("log_index").notNull(), + }), + (table) => ({ + pk: primaryKey({ + columns: [table.transactionHash, table.accountId, table.logIndex], + }), + }), +); + +export const delegation = pgTable( + "delegations", + (drizzle) => ({ + transactionHash: drizzle.text("transaction_hash").notNull(), + daoId: drizzle.text("dao_id").notNull(), + delegateAccountId: drizzle.text("delegate_account_id").notNull(), + delegatorAccountId: drizzle.text("delegator_account_id").notNull(), + delegatedValue: bigint({ mode: "bigint" }).notNull().default(0n), + previousDelegate: drizzle.text("previous_delegate"), + timestamp: bigint({ mode: "bigint" }).notNull(), + logIndex: drizzle.integer("log_index").notNull(), + isCex: drizzle.boolean().notNull().default(false), + isDex: drizzle.boolean().notNull().default(false), + isLending: drizzle.boolean().notNull().default(false), + isTotal: drizzle.boolean().notNull().default(false), + }), + (table) => ({ + pk: primaryKey({ + columns: [ + table.transactionHash, + table.delegatorAccountId, + table.delegateAccountId, + ], + }), + delegationTransactionHashIdx: index().on(table.transactionHash), + delegationTimestampIdx: index().on(table.timestamp), + delegationDelegatorAccountIdIdx: index().on(table.delegatorAccountId), + delegationDelegateAccountIdIdx: index().on(table.delegateAccountId), + delegationDelegatedValueIdx: index().on(table.delegatedValue), + }), +); + +export const transfer = pgTable( + "transfers", + (drizzle) => ({ + transactionHash: drizzle.text("transaction_hash").notNull(), + daoId: drizzle.text("dao_id").notNull(), + tokenId: drizzle.text("token_id").notNull(), + amount: bigint({ mode: "bigint" }).notNull(), + fromAccountId: drizzle.text("from_account_id").$type
().notNull(), + toAccountId: drizzle.text("to_account_id").$type
().notNull(), + timestamp: bigint({ mode: "bigint" }).notNull(), + logIndex: drizzle.integer("log_index").notNull(), + isCex: drizzle.boolean().notNull().default(false), + isDex: drizzle.boolean().notNull().default(false), + isLending: drizzle.boolean().notNull().default(false), + isTotal: drizzle.boolean().notNull().default(false), + }), + (table) => ({ + pk: primaryKey({ + columns: [table.transactionHash, table.fromAccountId, table.toAccountId], + }), + transferTransactionHashIdx: index().on(table.transactionHash), + transferTimestampIdx: index().on(table.timestamp), + transferFromAccountIdIdx: index().on(table.fromAccountId), + transferToAccountIdIdx: index().on(table.toAccountId), + transferAmountIdx: index().on(table.amount), + }), +); + +export const votesOnchain = pgTable( + "votes_onchain", + (drizzle) => ({ + txHash: drizzle.text("tx_hash").notNull(), + daoId: drizzle.text("dao_id").notNull(), + voterAccountId: drizzle.text("voter_account_id").$type
().notNull(), + proposalId: drizzle.text("proposal_id").notNull(), + support: drizzle.text().notNull(), + votingPower: bigint({ mode: "bigint" }).notNull(), + reason: drizzle.text(), + timestamp: bigint({ mode: "bigint" }).notNull(), + }), + (table) => ({ + pk: primaryKey({ + columns: [table.voterAccountId, table.proposalId], + }), + }), +); + +export const proposalsOnchain = pgTable( + "proposals_onchain", + (drizzle) => ({ + id: drizzle.text().primaryKey(), + txHash: drizzle.text("tx_hash").notNull(), + daoId: drizzle.text("dao_id").notNull(), + proposerAccountId: drizzle + .text("proposer_account_id") + .$type
() + .notNull(), + targets: drizzle.json().$type().notNull(), + values: drizzle.json().$type().notNull(), + signatures: drizzle.json().$type().notNull(), + calldatas: drizzle.json().$type().notNull(), + startBlock: drizzle.integer("start_block").notNull(), + endBlock: drizzle.integer("end_block").notNull(), + description: drizzle.text().notNull(), + timestamp: bigint({ mode: "bigint" }).notNull(), + endTimestamp: bigint({ mode: "bigint" }).notNull(), + status: drizzle.text().notNull(), + forVotes: bigint({ mode: "bigint" }).default(0n).notNull(), + againstVotes: bigint({ mode: "bigint" }).default(0n).notNull(), + abstainVotes: bigint({ mode: "bigint" }).default(0n).notNull(), + proposalType: drizzle.integer("proposal_type"), + }), + (table) => [index().on(table.proposerAccountId)], +); + +export const metricType = pgEnum("metricType", MetricTypesArray); + +export const daoMetricsDayBucket = pgTable( + "dao_metrics_day_buckets", + (drizzle) => ({ + date: bigint({ mode: "bigint" }).notNull(), + daoId: drizzle.text("dao_id").notNull(), + tokenId: drizzle.text("token_id").notNull(), + metricType: metricType().notNull(), + open: bigint({ mode: "bigint" }).notNull(), + close: bigint({ mode: "bigint" }).notNull(), + low: bigint({ mode: "bigint" }).notNull(), + high: bigint({ mode: "bigint" }).notNull(), + average: bigint({ mode: "bigint" }).notNull(), + volume: bigint({ mode: "bigint" }).notNull(), + count: drizzle.integer().notNull(), + lastUpdate: bigint({ mode: "bigint" }).notNull(), + }), + (table) => ({ + pk: primaryKey({ + columns: [table.date, table.tokenId, table.metricType], + }), + }), +); + +export const transaction = pgTable("transaction", (drizzle) => ({ + transactionHash: drizzle.text("transaction_hash").primaryKey(), + fromAddress: drizzle.text("from_address"), + toAddress: drizzle.text("to_address"), + isCex: drizzle.boolean().notNull().default(false), + isDex: drizzle.boolean().notNull().default(false), + isLending: drizzle.boolean().notNull().default(false), + isTotal: drizzle.boolean().notNull().default(false), + timestamp: bigint({ mode: "bigint" }).notNull(), +})); + +export const tokenPrice = pgTable("token_price", (drizzle) => ({ + price: bigint({ mode: "bigint" }).notNull(), // price in ETH + timestamp: bigint({ mode: "bigint" }).primaryKey(), +})); diff --git a/apps/indexer/src/api/docs.ts b/apps/api/src/docs.ts similarity index 100% rename from apps/indexer/src/api/docs.ts rename to apps/api/src/docs.ts diff --git a/apps/api/src/env.ts b/apps/api/src/env.ts new file mode 100644 index 000000000..c366e5ea6 --- /dev/null +++ b/apps/api/src/env.ts @@ -0,0 +1,34 @@ +import { z } from "zod"; +import dotenv from "dotenv"; + +import { DaoIdEnum } from "@/lib/enums"; + +dotenv.config(); + +const envSchema = z.object({ + RPC_URL: z.string(), + DATABASE_URL: z.string().optional(), + DAO_ID: z.nativeEnum(DaoIdEnum), + CHAIN_ID: z.coerce.number(), + + // Treasury provider configuration + TREASURY_DATA_PROVIDER_ID: z + .enum(["DUNE", "DEFILLAMA", "COMPOUND"]) + .optional(), + TREASURY_DATA_PROVIDER_API_URL: z.string().optional(), + TREASURY_DATA_PROVIDER_API_KEY: z.string().optional(), + + COINGECKO_API_URL: z.string(), + COINGECKO_API_KEY: z.string(), + REDIS_URL: z.string().optional(), + PORT: z.coerce.number().default(42069), +}); + +const _env = envSchema.safeParse(process.env); + +if (_env.success === false) { + console.error("Invalid environment variables", _env.error.format()); + throw new Error("Invalid environment variables"); +} + +export const env = _env.data; diff --git a/apps/indexer/src/api/index.ts b/apps/api/src/index.ts similarity index 92% rename from apps/indexer/src/api/index.ts rename to apps/api/src/index.ts index 458bae68f..1da2caa34 100644 --- a/apps/indexer/src/api/index.ts +++ b/apps/api/src/index.ts @@ -1,7 +1,5 @@ -import { db } from "ponder:api"; -import { graphql } from "ponder"; import { OpenAPIHono as Hono } from "@hono/zod-openapi"; -import schema from "ponder:schema"; + import { logger } from "hono/logger"; import { fromZodError } from "zod-validation-error"; import { createPublicClient, http } from "viem"; @@ -29,10 +27,10 @@ import { votingPowers, delegations, historicalDelegations, -} from "@/api/controllers"; -import { docs } from "@/api/docs"; +} from "@/controllers"; +import { docs } from "@/docs"; import { env } from "@/env"; -import { DaoCache } from "@/api/cache/dao-cache"; +import { DaoCache } from "@/cache/dao-cache"; import { AccountBalanceRepository, AccountInteractionsRepository, @@ -50,8 +48,8 @@ import { VotingPowerRepository, DelegationsRepository, HistoricalDelegationsRepository, -} from "@/api/repositories"; -import { errorHandler } from "@/api/middlewares"; +} from "@/repositories"; +import { errorHandler } from "@/middlewares"; import { getClient } from "@/lib/client"; import { getChain } from "@/lib/utils"; import { @@ -72,7 +70,7 @@ import { parseTreasuryProviderConfig, HistoricalDelegationsService, DelegationsService, -} from "@/api/services"; +} from "@/services"; import { CONTRACT_ADDRESSES } from "@/lib/constants"; import { DaoIdEnum } from "@/lib/enums"; @@ -95,9 +93,6 @@ const app = new Hono({ app.use(logger()); app.onError(errorHandler); -app.use("/", graphql({ db, schema })); -app.use("/graphql", graphql({ db, schema })); - const chain = getChain(env.CHAIN_ID); if (!chain) { throw new Error(`Chain not found for chainId ${env.CHAIN_ID}`); @@ -169,10 +164,7 @@ historicalDelegations( ); // TODO: add support to partial delegations at some point -delegations( - app, - new DelegationsService(new DelegationsRepository()), -); +delegations(app, new DelegationsService(new DelegationsRepository())); const treasuryService = createTreasuryService( new TreasuryRepository(), diff --git a/apps/api/src/lib/blockTime.ts b/apps/api/src/lib/blockTime.ts new file mode 100644 index 000000000..e765535e8 --- /dev/null +++ b/apps/api/src/lib/blockTime.ts @@ -0,0 +1,15 @@ +import { DaysEnum } from "./enums"; + +export function calculateHistoricalBlockNumber( + days: DaysEnum, + currentBlockNumber: number, + blockTime: number, +): number { + const blocksToGoBack = Math.floor(days / blockTime); + const historicalBlockNumber = Math.max( + 0, + currentBlockNumber - blocksToGoBack, + ); + + return historicalBlockNumber; +} diff --git a/apps/api/src/lib/client.ts b/apps/api/src/lib/client.ts new file mode 100644 index 000000000..1dabe39c4 --- /dev/null +++ b/apps/api/src/lib/client.ts @@ -0,0 +1,70 @@ +import { Chain, Account, Transport, Client } from "viem"; + +import { DaoIdEnum } from "./enums"; +import { CONTRACT_ADDRESSES } from "./constants"; +import { + UNIClient, + SCRClient, + COMPClient, + ObolClient, + ZKClient, + ENSClient, + OPClient, + GTCClient, + Client as NounsClient, +} from "@/clients"; +import { DAOClient } from "@/interfaces"; + +export function getClient< + TTransport extends Transport = Transport, + TChain extends Chain = Chain, + TAccount extends Account | undefined = Account | undefined, +>( + daoId: DaoIdEnum, + client: Client, +): DAOClient | null { + switch (daoId) { + case DaoIdEnum.ENS: { + const { governor } = CONTRACT_ADDRESSES[daoId]; + return new ENSClient(client, governor.address); + } + case DaoIdEnum.UNI: { + const { governor } = CONTRACT_ADDRESSES[daoId]; + return new UNIClient(client, governor.address); + } + case DaoIdEnum.OP: { + const { governor } = CONTRACT_ADDRESSES[daoId]; + return new OPClient(client, governor.address); + } + case DaoIdEnum.TEST: { + const { governor } = CONTRACT_ADDRESSES[daoId]; + return new ENSClient(client, governor.address); + } + case DaoIdEnum.GTC: { + const { governor } = CONTRACT_ADDRESSES[daoId]; + return new GTCClient(client, governor.address); + } + case DaoIdEnum.NOUNS: { + const { governor } = CONTRACT_ADDRESSES[daoId]; + return new NounsClient(client, governor.address); + } + case DaoIdEnum.SCR: { + const { governor } = CONTRACT_ADDRESSES[daoId]; + return new SCRClient(client, governor.address); + } + case DaoIdEnum.COMP: { + const { governor } = CONTRACT_ADDRESSES[daoId]; + return new COMPClient(client, governor.address); + } + case DaoIdEnum.OBOL: { + const { governor } = CONTRACT_ADDRESSES[daoId]; + return new ObolClient(client, governor.address); + } + case DaoIdEnum.ZK: { + const { governor } = CONTRACT_ADDRESSES[daoId]; + return new ZKClient(client, governor.address); + } + default: + return null; + } +} diff --git a/apps/api/src/lib/constants.ts b/apps/api/src/lib/constants.ts new file mode 100644 index 000000000..a10c402fc --- /dev/null +++ b/apps/api/src/lib/constants.ts @@ -0,0 +1,347 @@ +import { Address } from "viem"; + +import { DaoIdEnum } from "./enums"; + +export const CONTRACT_ADDRESSES = { + [DaoIdEnum.UNI]: { + blockTime: 12, + tokenType: "ERC20", + // https://etherscan.io/address/0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984 + token: { + address: "0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984", + decimals: 18, + startBlock: 10861674, + }, + // https://etherscan.io/address/0x408ED6354d4973f66138C91495F2f2FCbd8724C3 + governor: { + address: "0x408ED6354d4973f66138C91495F2f2FCbd8724C3", + startBlock: 13059157, + }, + }, + [DaoIdEnum.ENS]: { + blockTime: 12, + tokenType: "ERC20", + // https://etherscan.io/address/0xC18360217D8F7Ab5e7c516566761Ea12Ce7F9D72 + token: { + address: "0xC18360217D8F7Ab5e7c516566761Ea12Ce7F9D72", + decimals: 18, + startBlock: 9380410, + }, + // https://etherscan.io/address/0x323a76393544d5ecca80cd6ef2a560c6a395b7e3 + governor: { + address: "0x323a76393544d5ecca80cd6ef2a560c6a395b7e3", + startBlock: 13533772, + }, + }, + [DaoIdEnum.ARB]: { + blockTime: 0.25, + // https://arbiscan.io/address/0x912CE59144191C1204E64559FE8253a0e49E6548 + tokenType: "ERC20", + token: { + address: "0x912CE59144191C1204E64559FE8253a0e49E6548", + decimals: 18, + startBlock: 70398200, + }, + }, + [DaoIdEnum.OP]: { + blockTime: 2, + tokenType: "ERC20", + optimisticProposalType: 2, + // https://optimistic.etherscan.io/token/0x4200000000000000000000000000000000000042 + token: { + address: "0x4200000000000000000000000000000000000042", + decimals: 18, + startBlock: 6490467, + }, + // https://optimistic.etherscan.io/address/0xcDF27F107725988f2261Ce2256bDfCdE8B382B10 + governor: { + address: "0xcDF27F107725988f2261Ce2256bDfCdE8B382B10", + startBlock: 71801427, + }, + }, + [DaoIdEnum.TEST]: { + blockTime: 12, + tokenType: "ERC20", + token: { + address: "0x244dE6b06E7087110b94Cde88A42d9aBA17efa52", + decimals: 18, + startBlock: 22635098, + }, + governor: { + address: "0x7c28FC9709650D49c8d0aED2f6ece6b191F192a9", + startBlock: 22635098, + }, + }, + [DaoIdEnum.GTC]: { + blockTime: 12, + // https://etherscan.io/address/0xDe30da39c46104798bB5aA3fe8B9e0e1F348163F + tokenType: "ERC20", + token: { + address: "0xDe30da39c46104798bB5aA3fe8B9e0e1F348163F", + decimals: 18, + startBlock: 12422079, + }, + // https://etherscan.io/address/0x9D4C63565D5618310271bF3F3c01b2954C1D1639 + governor: { + address: "0x9D4C63565D5618310271bF3F3c01b2954C1D1639", + startBlock: 17813942, + }, + // https://etherscan.io/address/0xDbD27635A534A3d3169Ef0498beB56Fb9c937489 + governorAlpha: { + address: "0xDbD27635A534A3d3169Ef0498beB56Fb9c937489", + startBlock: 12497481, + }, + }, + [DaoIdEnum.NOUNS]: { + blockTime: 12, + tokenType: "ERC721", + token: { + // https://etherscan.io/token/0x9C8fF314C9Bc7F6e59A9d9225Fb22946427eDC03 + address: "0x9C8fF314C9Bc7F6e59A9d9225Fb22946427eDC03", + decimals: 0, + startBlock: 12985438, + }, + governor: { + // https://etherscan.io/address/0x6f3e6272a167e8accb32072d08e0957f9c79223d + address: "0x6f3e6272a167e8accb32072d08e0957f9c79223d", + startBlock: 12985453, + }, + auction: { + // https://etherscan.io/address/0x830BD73E4184ceF73443C15111a1DF14e495C706 + address: "0x830BD73E4184ceF73443C15111a1DF14e495C706", + startBlock: 12985451, + }, + }, + [DaoIdEnum.SCR]: { + blockTime: 1.5, + // https://scrollscan.com/address/0xd29687c813D741E2F938F4aC377128810E217b1b + tokenType: "ERC20", + token: { + address: "0xd29687c813D741E2F938F4aC377128810E217b1b", + decimals: 18, + startBlock: 8949006, + }, + // https://scrollscan.com/address/0x2f3f2054776bd3c2fc30d750734a8f539bb214f0 + governor: { + address: "0x2f3f2054776bd3c2fc30d750734a8f539bb214f0", + startBlock: 8963441, + }, + }, + [DaoIdEnum.COMP]: { + blockTime: 12, + // https://etherscan.io/address/0xc00e94Cb662C3520282E6f5717214004A7f26888 + tokenType: "ERC20", + token: { + address: "0xc00e94Cb662C3520282E6f5717214004A7f26888", + decimals: 18, + startBlock: 9601359, + }, + // https://etherscan.io/address/0x309a862bbC1A00e45506cB8A802D1ff10004c8C0 + governor: { + address: "0x309a862bbC1A00e45506cB8A802D1ff10004c8C0", + startBlock: 21688680, + }, + }, + [DaoIdEnum.OBOL]: { + blockTime: 12, + tokenType: "ERC20", + // https://etherscan.io/address/0x0B010000b7624eb9B3DfBC279673C76E9D29D5F7 + // Token created: Sep-19-2022 11:12:47 PM UTC + token: { + address: "0x0B010000b7624eb9B3DfBC279673C76E9D29D5F7", + decimals: 18, + startBlock: 15570746, + }, + // https://etherscan.io/address/0xcB1622185A0c62A80494bEde05Ba95ef29Fbf85c + // Governor created: Feb-19-2025 10:34:47 PM UTC + governor: { + address: "0xcB1622185A0c62A80494bEde05Ba95ef29Fbf85c", + startBlock: 21883431, + }, + }, + [DaoIdEnum.ZK]: { + blockTime: 1, + tokenType: "ERC20", + // https://explorer.zksync.io/address/0x5A7d6b2F92C77FAD6CCaBd7EE0624E64907Eaf3E + token: { + address: "0x5A7d6b2F92C77FAD6CCaBd7EE0624E64907Eaf3E", + decimals: 18, + startBlock: 34572100, + }, + // https://explorer.zksync.io/address/0xb83FF6501214ddF40C91C9565d095400f3F45746 + governor: { + address: "0xb83FF6501214ddF40C91C9565d095400f3F45746", + startBlock: 55519658, + }, + }, +} as const; + +export const TreasuryAddresses: Record> = { + [DaoIdEnum.UNI]: { + timelock: "0x1a9C8182C09F50C8318d769245beA52c32BE35BC", + treasuryVester1: "0x4750c43867EF5F89869132ecCF19B9b6C4286E1a", + treasuryVester2: "0xe3953D9d317B834592aB58AB2c7A6aD22b54075D", + treasuryVester3: "0x4b4e140D1f131fdaD6fb59C13AF796fD194e4135", + treasuryVester4: "0x3D30B1aB88D487B0F3061F40De76845Bec3F1e94", + }, + [DaoIdEnum.ENS]: { + timelock: "0xFe89cc7aBB2C4183683ab71653C4cdc9B02D44b7", + endaoment: "0x4F2083f5fBede34C2714aFfb3105539775f7FE64", + oldEthRegistrarController: "0x283Af0B28c62C092C9727F1Ee09c02CA627EB7F5", + ethRegistrarController: "0x253553366Da8546fC250F225fe3d25d0C782303b", + }, + [DaoIdEnum.ARB]: {}, + [DaoIdEnum.OP]: {}, + [DaoIdEnum.NOUNS]: { + timelock: "0xb1a32fc9f9d8b2cf86c068cae13108809547ef71", + auction: "0x830BD73E4184ceF73443C15111a1DF14e495C706", + }, + [DaoIdEnum.TEST]: {}, + [DaoIdEnum.GTC]: { + "Gitcoin Timelock": "0x57a8865cfB1eCEf7253c27da6B4BC3dAEE5Be518", + "Gitcoin CSDO": "0x931896A8A9313F622a2AFCA76d1471B97955e551", + "Gitcoin Fraud Detection & Defense": + "0xD4567069C5a1c1fc8261d8Ff5C0B1d98f069Cf47", + "Gitcoin Grants Matching Pool": + "0xde21F729137C5Af1b01d73aF1dC21eFfa2B8a0d6", + "Gitcoin Merch, Memes and Marketing": + "0xC23DA3Ca9300571B9CF43298228353cbb3E1b4c0", + "Gitcoin Timelock Transfer 1": "0x6EEdE31a2A15340342B4BCb3039447d457aC7C4b", + "Gitcoin Timelock Transfer 2": "0xeD95D629c4Db80060C59432e81254D256AEc97E2", + "Vesting Address GTC 1": "0x2AA5d15Eb36E5960d056e8FeA6E7BB3e2a06A351", + "Staking contract GTC": "0x0E3efD5BE54CC0f4C64e0D186b0af4b7F2A0e95F", + "OKX Ventures": "0xe527BbDE3654E9ba824f9B72DFF495eEe60fD366", + "Protocol Labs 1": "0x154855f5522f6B04ce654175368F428852DCd55D", + "Matt Solomon": "0x7aD3d9819B06E800F8A65f3440D599A23D6A0BDf", + "Arbitrum Bridge": "0xa3A7B6F88361F48403514059F1F16C8E78d60EeC", + "Optimism Bridge": "0x99C9fc46f92E8a1c0deC1b1747d010903E884bE1", + "Radicle Timelock": "0x8dA8f82d2BbDd896822de723F55D6EdF416130ba", + "Vesting Address GTC 3": "0x2CDE9919e81b20B4B33DD562a48a84b54C48F00C", + "deltajuliet.eth 1": "0x5b1ddBEC956Ed39e1aC92AE3c3D99295ddD59865", + "deltajuliet.eth 2": "0x407466C56B8488c4d99558633Ff1AC5D84400B46", + "deltajuliet.eth 3": "0x14b9F70C3d4B367D496F3771EdA7EFA65282e55D", + "deltajuliet.eth 4": "0x0dcFc9323539A6eC47f9BC0A96882070540bf950", + "deltajuliet.eth 5": "0x08f3FB287AEc4E06EFF8de37410eaF52B05c7f56", + "Gitcoin Timelock Transfer 5": "0x9E75c3BFb82cf701AC0A74d6C1607461Ec65EfF9", + "Old Address, Large GTC Transfers 1": + "0xF5A7bA226CB94D87C29aDD2b59aC960904a163F3", + "Old Address, Large GTC Transfers 2": + "0xeD865C87c3509e3A908655777B13f7313b2fc196", + "Old Address, Large GTC Transfers 3": + "0xDD6a165B9e05549640149dF108AC0aF8579B7005", + "Old Address, Large GTC Transfers 4": + "0xaD467E6039F0Ca383b5FFd60F1C7a890acaB4bE3", + "Old Address, Large GTC Transfers 5": + "0x44d4d830788cc6D4d72C78203F5918a3E2761691", + "Old Address, Large GTC Transfers 6": + "0x38661187CfD779bEa00e14Bc5b986CF0C717A39B", + "Old Address, Large GTC Transfers 7": + "0x34237F91D2Ce322f3572376b82472C7FA56D7595", + "Old Address, Large GTC Transfers 8": + "0x2083e7B107347AE4F5Cb6Ff35EC5DAcf03391c57", + "Old Address, Large GTC Transfers 9": + "0x183a1CaF6750CF88E45812FCE0110D59d71833e4", + "Old Address, Large GTC Transfers 10": + "0x11e06eF6e42306dc40D2754Ef2629fB011d80aE9", + }, + [DaoIdEnum.SCR]: { + "DAO Treasury": "0x4cb06982dD097633426cf32038D9f1182a9aDA0c", + "Foundation Treasury": "0xfF120e015777E9AA9F1417a4009a65d2EdA78C13", + "Ecosystem Treasury": "0xeE198F4a91E5b05022dc90535729B2545D3b03DF", + }, + [DaoIdEnum.COMP]: { + Timelock: "0x6d903f6003cca6255D85CcA4D3B5E5146dC33925", + Comptroller: "0x3d9819210A31b4961b30EF54bE2aeD79B9c9Cd3B", + /// v2 markets + v2WBTC: "0xccF4429DB6322D5C611ee964527D42E5d685DD6a", + v2USDC: "0x39AA39c021dfbaE8faC545936693aC917d5E7563", + v2DAI: "0x5d3a536E4D6DbD6114cc1Ead35777bAB948E3643", + v2USDT: "0xf650C3d88D12dB855b8bf7D11Be6C55A4e07dCC9", + v2ETH: "0x4Ddc2D193948926D02f9B1fE9e1daa0718270ED5", + v2UNI: "0x35A18000230DA775CAc24873d00Ff85BccdeD550", + v2BAT: "0x6C8c6b02E7b2BE14d4fA6022Dfd6d75921D90E4E", + v2LINK: "0xFAce851a4921ce59e912d19329929CE6da6EB0c7", + v2TUSD: "0x12392F67bdf24faE0AF363c24aC620a2f67DAd86", + v2AAVE: "0xe65cdB6479BaC1e22340E4E755fAE7E509EcD06c", + v2COMP: "0x70e36f6BF80a52b3B46b3aF8e106CC0ed743E8e4", + ///v3 markets + //Ethereum markets + mainnetETH: "0xA17581A9E3356d9A858b789D68B4d866e593aE94", + mainnetstETH: "0x3D0bb1ccaB520A66e607822fC55BC921738fAFE3", + mainnetUSDT: "0x3Afdc9BCA9213A35503b077a6072F3D0d5AB0840", + mainnetUSDS: "0x5D409e56D886231aDAf00c8775665AD0f9897b56", + mainnetUSDC: "0xc3d688B66703497DAA19211EEdff47f25384cdc3", + mainnetWBTC: "0xe85Dc543813B8c2CFEaAc371517b925a166a9293", + // Optimism markets + opETH: "0xE36A30D249f7761327fd973001A32010b521b6Fd", + opUSDT: "0x995E394b8B2437aC8Ce61Ee0bC610D617962B214", + opUSDC: "0x2e44e174f7D53F0212823acC11C01A11d58c5bCB", + // Unichain markets + uniUSDC: "0x2c7118c4C88B9841FCF839074c26Ae8f035f2921", + uniETH: "0x6C987dDE50dB1dcDd32Cd4175778C2a291978E2a", + // Polygon markets + polyUSDT0: "0xaeB318360f27748Acb200CE616E389A6C9409a07", + polyUSDC: "0xF25212E676D1F7F89Cd72fFEe66158f541246445", + // Ronin markets + ronWETH: "0x4006ed4097ee51c09a04c3b0951d28ccf19e6dfe", + ronRON: "0xc0Afdbd1cEB621Ef576BA969ce9D4ceF78Dbc0c0", + // Mantle markets + manUSDe: "0x606174f62cd968d8e684c645080fa694c1D7786E", + // Base markets + manUSDbC: "0x9c4ec768c28520B50860ea7a15bd7213a9fF58bf", + manUSDC: "0xb125E6687d4313864e53df431d5425969c15Eb2F", + manAERO: "0x784efeB622244d2348d4F2522f8860B96fbEcE89", + manUSDS: "0x2c776041CCFe903071AF44aa147368a9c8EEA518", + manETH: "0x46e6b214b524310239732D51387075E0e70970bf", + // Arbitrum marketsVOTE + arbUSDT0: "0xd98Be00b5D27fc98112BdE293e487f8D4cA57d07", + arbUSDC: "0x9c4ec768c28520B50860ea7a15bd7213a9fF58bf", + "arbUSDC.e": "0xA5EDBDD9646f8dFF606d7448e414884C7d905dCA", + arbETH: "0x6f7D514bbD4aFf3BcD1140B7344b32f063dEe486", + // Linea markets + linUSDC: "0x8D38A3d6B3c3B7d96D6536DA7Eef94A9d7dbC991", + linETH: "0x60F2058379716A64a7A5d29219397e79bC552194", + // Scroll markets + scrUSDC: "0xB2f97c1Bd3bf02f5e74d13f02E3e26F93D77CE44", + }, + [DaoIdEnum.OBOL]: { + timelock: "0xCdBf527842Ab04Da548d33EB09d03DB831381Fb0", + "Ecosystem Treasury 1": "0x42D201CC4d9C1e31c032397F54caCE2f48C1FA72", + "Ecosystem Treasury 2": "0x54076088bE86943e27B99120c5905AAD8A1bD166", + "Staking Rewards Reserve": "0x33f3D61415784A5899b733976b0c1F9176051569", + "OBOL Incentives Reserve": "0xdc8A309111aB0574CA51cA9C7Dd0152738e4c374", + "Protocol Revenue": "0xDe5aE4De36c966747Ea7DF13BD9589642e2B1D0d", + "Grant Program": "0xa59f60A7684A69E63c07bEC087cEC3D0607cd5cE", + "DV Labs Treasury 2": "0x6BeFB6484AA10187947Dda81fC01e495f7168dB4", + }, + [DaoIdEnum.ZK]: { + timelock: "0xe5d21A9179CA2E1F0F327d598D464CcF60d89c3d", + }, +}; + +export enum ProposalStatus { + PENDING = "PENDING", + ACTIVE = "ACTIVE", + CANCELED = "CANCELED", + DEFEATED = "DEFEATED", + SUCCEEDED = "SUCCEEDED", + QUEUED = "QUEUED", + EXPIRED = "EXPIRED", + EXECUTED = "EXECUTED", + NO_QUORUM = "NO_QUORUM", +} + +export enum MetricTypesEnum { + TOTAL_SUPPLY = "TOTAL_SUPPLY", + DELEGATED_SUPPLY = "DELEGATED_SUPPLY", + CEX_SUPPLY = "CEX_SUPPLY", + DEX_SUPPLY = "DEX_SUPPLY", + LENDING_SUPPLY = "LENDING_SUPPLY", + CIRCULATING_SUPPLY = "CIRCULATING_SUPPLY", + TREASURY = "TREASURY", +} + +export const MetricTypesArray = Object.values(MetricTypesEnum) as [ + string, + ...string[], +]; diff --git a/apps/api/src/lib/date-helpers.ts b/apps/api/src/lib/date-helpers.ts new file mode 100644 index 000000000..f884e70a6 --- /dev/null +++ b/apps/api/src/lib/date-helpers.ts @@ -0,0 +1,62 @@ +/** + * Date and timestamp utilities for time-series data processing. + */ + +import { SECONDS_IN_DAY } from "./enums"; + +/** + * Truncate timestamp (seconds) to midnight UTC + */ +export const truncateTimestampToMidnight = (timestampSec: number): number => { + return Math.floor(timestampSec / SECONDS_IN_DAY) * SECONDS_IN_DAY; +}; + +/** + * Calculate cutoff timestamp for filtering data by days + */ +export const calculateCutoffTimestamp = (days: number): number => { + return Math.floor(Date.now() / 1000) - days * SECONDS_IN_DAY; +}; + +/** + * Normalize all timestamps in a Map to midnight UTC (seconds) + */ +export const normalizeMapTimestamps = ( + map: Map, +): Map => { + const normalized = new Map(); + map.forEach((value, ts) => { + normalized.set(truncateTimestampToMidnight(ts), value); + }); + return normalized; +}; + +/** + * Get effective start date, adjusting if no initial value exists. + * + * When querying time-series data with forward-fill, if there's no initial value + * before the requested start date, we should start from the first real data point + * to avoid returning zeros/nulls. + * + * @param params.referenceDate - Requested start date (after ?? startDate) + * @param params.datesFromDb - Array of timestamps from database + * @param params.hasInitialValue - Whether an initial value exists before referenceDate + * @returns Effective start date to use + */ +export function getEffectiveStartDate(params: { + referenceDate?: number; + datesFromDb: number[]; + hasInitialValue: boolean; +}): number | undefined { + const { referenceDate, datesFromDb, hasInitialValue } = params; + + if (!referenceDate) return undefined; + if (hasInitialValue || datesFromDb.length === 0) return referenceDate; + + const sortedDates = [...datesFromDb].sort((a, b) => a - b); + const firstRealDate = sortedDates[0]; + + return firstRealDate && referenceDate < firstRealDate + ? firstRealDate + : referenceDate; +} diff --git a/apps/api/src/lib/enums.ts b/apps/api/src/lib/enums.ts new file mode 100644 index 000000000..c090a553d --- /dev/null +++ b/apps/api/src/lib/enums.ts @@ -0,0 +1,29 @@ +export enum DaoIdEnum { + UNI = "UNI", + ENS = "ENS", + ARB = "ARB", + OP = "OP", + GTC = "GTC", + NOUNS = "NOUNS", + TEST = "TEST", + SCR = "SCR", + COMP = "COMP", + OBOL = "OBOL", + ZK = "ZK", +} + +export const SECONDS_IN_DAY = 24 * 60 * 60; + +/** + * Enum representing different time periods in seconds + * Used for filtering data over specific time ranges + */ +export enum DaysEnum { + "7d" = 7 * SECONDS_IN_DAY, + "30d" = 30 * SECONDS_IN_DAY, + "90d" = 90 * SECONDS_IN_DAY, + "180d" = 180 * SECONDS_IN_DAY, + "365d" = 365 * SECONDS_IN_DAY, +} + +export const DaysOpts = ["7d", "30d", "90d", "180d", "365d"] as const; diff --git a/apps/api/src/lib/query-helpers.ts b/apps/api/src/lib/query-helpers.ts new file mode 100644 index 000000000..987cbbfa5 --- /dev/null +++ b/apps/api/src/lib/query-helpers.ts @@ -0,0 +1,104 @@ +/** + * Query helpers for pagination and data filtering in time-series APIs. + */ + +import { truncateTimestampToMidnight } from "./date-helpers"; + +/** + * Filter data by cutoff date with fallback to last value before cutoff. + * + * Returns items with date >= cutoffDate. If no items match, returns the last + * item before the cutoff as fallback (using getLastValueBefore). + * + * @param sortedData - Array sorted by date ascending, items must have `date` property + * @param cutoffDate - Minimum date (inclusive) + * @returns Filtered data, or last value before cutoff if filter returns empty + * + * @example + * const data = [{ date: 1, value: 10 }, { date: 5, value: 20 }]; + * const result = filterWithFallback(data, 3); + * // Result: [{ date: 5, value: 20 }] + * + * const result2 = filterWithFallback(data, 100); + * // Result: [{ date: 5, value: 20 }] (fallback to last before cutoff) + */ +export function filterWithFallback( + sortedData: T[], + cutoffDate: number, +): T[] { + const filtered = sortedData.filter((item) => item.date >= cutoffDate); + + if (filtered.length === 0 && sortedData.length > 0) { + const lastBefore = getLastValueBefore(sortedData, cutoffDate); + return lastBefore ? [lastBefore] : []; + } + + return filtered; +} + +/** + * Get the last value before a given date from sorted data. + * + * Useful for finding the initial value for forward-fill when the requested + * time range starts after the first available data point. + * + * @param sortedData - Array sorted by date ascending, items must have `date` property + * @param beforeDate - The cutoff date (exclusive) + * @returns The last item before the date, or undefined if none exists + * + * @example + * const data = [{ date: 1, value: 10 }, { date: 5, value: 20 }]; + * const result = getLastValueBefore(data, 3); + * // Result: { date: 1, value: 10 } + */ +export function getLastValueBefore( + sortedData: T[], + beforeDate: number, +): T | undefined { + for (let i = sortedData.length - 1; i >= 0; i--) { + const item = sortedData[i]; + if (item !== undefined && item.date < beforeDate) { + return item; + } + } + return undefined; +} + +/** + * Apply cursor-based pagination to time-series items. + * + * Filters items by after/before cursors and applies limit. + * Calculates hasNextPage based on whether more data exists. + * + * @param params.items - Array of items with date property + * @param params.after - Return items after this timestamp (exclusive) + * @param params.before - Return items before this timestamp (exclusive) + * @param params.limit - Maximum items to return + * @param params.endDate - If provided, hasNextPage uses simple length check; + * otherwise checks if last item reached today + * @returns Paginated items and hasNextPage flag + */ +export function applyCursorPagination(params: { + items: T[]; + skip?: number; + limit: number; + endDate?: number; +}): { items: T[]; hasNextPage: boolean } { + const { items: allItems, skip, limit, endDate } = params; + + if (skip !== undefined && skip > 0) { + const items = allItems.slice(skip, skip + limit); + const hasNextPage = allItems.length > skip + limit; + return { items, hasNextPage }; + } + + const items = allItems.slice(0, limit); + const today = truncateTimestampToMidnight(Math.floor(Date.now() / 1000)); + const lastItemDate = Number(items[items.length - 1]?.date ?? 0); + + const hasNextPage = endDate + ? allItems.length > limit + : allItems.length > limit && lastItemDate < today; + + return { items, hasNextPage }; +} diff --git a/apps/api/src/lib/time-series.ts b/apps/api/src/lib/time-series.ts new file mode 100644 index 000000000..5776ca935 --- /dev/null +++ b/apps/api/src/lib/time-series.ts @@ -0,0 +1,105 @@ +/** + * Core time-series utilities for forward-fill and timeline generation. + * + * Forward-fill: Use the last known value for any missing data points. + */ + +import { SECONDS_IN_DAY } from "./enums"; +import { truncateTimestampToMidnight } from "./date-helpers"; + +/** + * Forward-fill sparse data across a master timeline. + * + * Works with any key type (number, bigint, string) and any value type. + * + * @param timeline - Sorted array of timestamps/keys + * @param sparseData - Map of key to value (may have gaps) + * @param initialValue - Optional initial value when no data exists before first entry + * @returns Map with values filled for all timeline keys + * + * @example + * // With numbers + * const filled = forwardFill([1000, 2000, 3000], new Map([[1000, 10]]), 0); + * // Result: Map { 1000 => 10, 2000 => 10, 3000 => 10 } + * + */ +export function forwardFill( + timeline: K[], + sparseData: Map, + initialValue?: V, +): Map { + const result = new Map(); + let lastKnownValue: V | undefined = initialValue; + + for (const key of timeline) { + if (sparseData.has(key)) { + lastKnownValue = sparseData.get(key); + } + + if (lastKnownValue !== undefined) { + result.set(key, lastKnownValue); + } + } + + return result; +} + +/** + * Create daily timeline from first timestamp to last timestamp (seconds). + * + * @param firstTimestamp - Start timestamp in seconds (will be truncated to midnight) + * @param lastTimestamp - End timestamp in seconds (will be truncated to midnight) + * @returns Array of daily timestamps (midnight UTC) in seconds + */ +export function createDailyTimeline( + firstTimestamp: number, + lastTimestamp?: number, +): number[] { + if (!lastTimestamp) { + lastTimestamp = truncateTimestampToMidnight(Math.floor(Date.now() / 1000)); + } + if (firstTimestamp > lastTimestamp) return []; + const startMidnight = truncateTimestampToMidnight(firstTimestamp); + const endMidnight = truncateTimestampToMidnight(lastTimestamp); + const totalDays = + Math.floor((endMidnight - startMidnight) / SECONDS_IN_DAY) + 1; + + return Array.from( + { length: totalDays }, + (_, i) => startMidnight + i * SECONDS_IN_DAY, + ); +} + +/** + * Generate ordered daily timeline from dates array. + * + * Creates a complete daily timeline from startDate (or first date in array) + * to endDate (or today), optionally reversed for descending order. + * + * @param params.datesFromDb - Array of timestamps from database (will be sorted) + * @param params.startDate - Optional start date override + * @param params.endDate - Optional end date (defaults to today) + * @param params.orderDirection - "asc" or "desc" ordering + * @returns Array of daily timestamps + */ +export function generateOrderedTimeline(params: { + datesFromDb: number[]; + startDate?: number; + endDate?: number; + orderDirection?: "asc" | "desc"; +}): number[] { + const { datesFromDb, startDate, endDate, orderDirection } = params; + + if (datesFromDb.length === 0 && !startDate) return []; + + const sortedDates = [...datesFromDb].sort((a, b) => a - b); + const firstDate = startDate ?? sortedDates[0]; + const lastDate = + endDate ?? truncateTimestampToMidnight(Math.floor(Date.now() / 1000)); + + if (!firstDate || !lastDate) return []; + + const timeline = createDailyTimeline(firstDate, lastDate); + if (orderDirection === "desc") timeline.reverse(); + return timeline; +} diff --git a/apps/api/src/lib/utils.ts b/apps/api/src/lib/utils.ts new file mode 100644 index 000000000..837c8d24c --- /dev/null +++ b/apps/api/src/lib/utils.ts @@ -0,0 +1,5 @@ +import * as chains from "viem/chains"; + +export function getChain(chainId: number): chains.Chain | undefined { + return Object.values(chains).find((chain) => chain.id === chainId); +} diff --git a/apps/indexer/src/api/mappers/account-balance/general.ts b/apps/api/src/mappers/account-balance/general.ts similarity index 86% rename from apps/indexer/src/api/mappers/account-balance/general.ts rename to apps/api/src/mappers/account-balance/general.ts index c3053ba1a..c82ca09c3 100644 --- a/apps/indexer/src/api/mappers/account-balance/general.ts +++ b/apps/api/src/mappers/account-balance/general.ts @@ -1,5 +1,5 @@ import { z } from "@hono/zod-openapi"; -import { accountBalance } from "ponder:schema"; +import { accountBalance } from "@/database"; import { Address, getAddress, isAddress } from "viem"; export const AccountBalancesRequestSchema = z.object({ @@ -23,10 +23,12 @@ export const AccountBalancesRequestSchema = z.object({ .string() .refine(isAddress, "Invalid address") .transform((addr) => [getAddress(addr)]), - z.array(z - .string() - .refine(isAddress, "Invalid addresses") - .transform((addr) => getAddress(addr))), + z.array( + z + .string() + .refine(isAddress, "Invalid addresses") + .transform((addr) => getAddress(addr)), + ), ]) .optional() .transform((val) => (val === undefined ? [] : val)), @@ -36,10 +38,11 @@ export const AccountBalancesRequestSchema = z.object({ .string() .refine(isAddress, "Invalid address") .transform((addr) => [getAddress(addr)]), - z.array(z - .string() - .refine(isAddress, "Invalid addresses") - .transform((addr) => getAddress(addr)), + z.array( + z + .string() + .refine(isAddress, "Invalid addresses") + .transform((addr) => getAddress(addr)), ), ]) .optional() diff --git a/apps/indexer/src/api/mappers/account-balance/historical.ts b/apps/api/src/mappers/account-balance/historical.ts similarity index 94% rename from apps/indexer/src/api/mappers/account-balance/historical.ts rename to apps/api/src/mappers/account-balance/historical.ts index 2b489e2cf..d7e5cb8cc 100644 --- a/apps/indexer/src/api/mappers/account-balance/historical.ts +++ b/apps/api/src/mappers/account-balance/historical.ts @@ -1,10 +1,10 @@ import { z } from "@hono/zod-openapi"; -import { balanceHistory } from "ponder:schema"; +import { balanceHistory } from "@/database"; import { getAddress, isAddress } from "viem"; import { DBTransfer } from "../transfers"; export type DBHistoricalBalance = typeof balanceHistory.$inferSelect; -export type DBHistoricalBalanceWithRelations = DBHistoricalBalance & { +export type DBHistoricalBalanceWithRelations = this.dbHistoricalBalance & { transfer: DBTransfer; }; @@ -12,7 +12,7 @@ export const HistoricalBalanceRequestParamsSchema = z.object({ address: z .string() .refine((addr) => isAddress(addr)) - .transform((addr) => getAddress(addr)) + .transform((addr) => getAddress(addr)), }); export const HistoricalBalanceRequestQuerySchema = z.object({ diff --git a/apps/indexer/src/api/mappers/account-balance/index.ts b/apps/api/src/mappers/account-balance/index.ts similarity index 100% rename from apps/indexer/src/api/mappers/account-balance/index.ts rename to apps/api/src/mappers/account-balance/index.ts diff --git a/apps/indexer/src/api/mappers/account-balance/interactions.ts b/apps/api/src/mappers/account-balance/interactions.ts similarity index 97% rename from apps/indexer/src/api/mappers/account-balance/interactions.ts rename to apps/api/src/mappers/account-balance/interactions.ts index 60bd90f0d..318f333ff 100644 --- a/apps/indexer/src/api/mappers/account-balance/interactions.ts +++ b/apps/api/src/mappers/account-balance/interactions.ts @@ -66,7 +66,7 @@ export type AccountInteractionsResponse = z.infer< typeof AccountInteractionsResponseSchema >; -export type DBAccountInteraction = DBAccountBalanceVariation & { +export type DBAccountInteraction = this.dbAccountBalanceVariation & { totalVolume: bigint; transferCount: bigint; }; diff --git a/apps/indexer/src/api/mappers/account-balance/variations.ts b/apps/api/src/mappers/account-balance/variations.ts similarity index 100% rename from apps/indexer/src/api/mappers/account-balance/variations.ts rename to apps/api/src/mappers/account-balance/variations.ts diff --git a/apps/indexer/src/api/mappers/constants.ts b/apps/api/src/mappers/constants.ts similarity index 100% rename from apps/indexer/src/api/mappers/constants.ts rename to apps/api/src/mappers/constants.ts diff --git a/apps/indexer/src/api/mappers/dao/index.ts b/apps/api/src/mappers/dao/index.ts similarity index 100% rename from apps/indexer/src/api/mappers/dao/index.ts rename to apps/api/src/mappers/dao/index.ts diff --git a/apps/indexer/src/api/mappers/delegation-percentage/index.ts b/apps/api/src/mappers/delegation-percentage/index.ts similarity index 100% rename from apps/indexer/src/api/mappers/delegation-percentage/index.ts rename to apps/api/src/mappers/delegation-percentage/index.ts diff --git a/apps/indexer/src/api/mappers/delegations/delegations.ts b/apps/api/src/mappers/delegations/delegations.ts similarity index 95% rename from apps/indexer/src/api/mappers/delegations/delegations.ts rename to apps/api/src/mappers/delegations/delegations.ts index 1f7e3ebc0..46393fd4b 100644 --- a/apps/indexer/src/api/mappers/delegations/delegations.ts +++ b/apps/api/src/mappers/delegations/delegations.ts @@ -1,7 +1,7 @@ import { z } from "@hono/zod-openapi"; import { getAddress, isAddress } from "viem"; import { DelegationItem, DelegationsResponse } from "./historical"; -import { delegation } from "ponder:schema"; +import { delegation } from "@/database"; export type DBDelegation = typeof delegation.$inferSelect; diff --git a/apps/indexer/src/api/mappers/delegations/historical.ts b/apps/api/src/mappers/delegations/historical.ts similarity index 100% rename from apps/indexer/src/api/mappers/delegations/historical.ts rename to apps/api/src/mappers/delegations/historical.ts diff --git a/apps/indexer/src/api/mappers/delegations/index.ts b/apps/api/src/mappers/delegations/index.ts similarity index 100% rename from apps/indexer/src/api/mappers/delegations/index.ts rename to apps/api/src/mappers/delegations/index.ts diff --git a/apps/indexer/src/api/mappers/index.ts b/apps/api/src/mappers/index.ts similarity index 100% rename from apps/indexer/src/api/mappers/index.ts rename to apps/api/src/mappers/index.ts diff --git a/apps/indexer/src/api/mappers/last-update/index.ts b/apps/api/src/mappers/last-update/index.ts similarity index 100% rename from apps/indexer/src/api/mappers/last-update/index.ts rename to apps/api/src/mappers/last-update/index.ts diff --git a/apps/indexer/src/api/mappers/proposals/activity.ts b/apps/api/src/mappers/proposals/activity.ts similarity index 100% rename from apps/indexer/src/api/mappers/proposals/activity.ts rename to apps/api/src/mappers/proposals/activity.ts diff --git a/apps/indexer/src/api/mappers/proposals/index.ts b/apps/api/src/mappers/proposals/index.ts similarity index 100% rename from apps/indexer/src/api/mappers/proposals/index.ts rename to apps/api/src/mappers/proposals/index.ts diff --git a/apps/indexer/src/api/mappers/proposals/proposals.ts b/apps/api/src/mappers/proposals/proposals.ts similarity index 98% rename from apps/indexer/src/api/mappers/proposals/proposals.ts rename to apps/api/src/mappers/proposals/proposals.ts index edcc9ecd0..3d2930653 100644 --- a/apps/indexer/src/api/mappers/proposals/proposals.ts +++ b/apps/api/src/mappers/proposals/proposals.ts @@ -1,5 +1,5 @@ import { z } from "@hono/zod-openapi"; -import { proposalsOnchain } from "ponder:schema"; +import { proposalsOnchain } from "@/database"; export type DBProposal = typeof proposalsOnchain.$inferSelect; diff --git a/apps/indexer/src/api/mappers/proposals/voters.ts b/apps/api/src/mappers/proposals/voters.ts similarity index 100% rename from apps/indexer/src/api/mappers/proposals/voters.ts rename to apps/api/src/mappers/proposals/voters.ts diff --git a/apps/indexer/src/api/mappers/proposals/votes.ts b/apps/api/src/mappers/proposals/votes.ts similarity index 97% rename from apps/indexer/src/api/mappers/proposals/votes.ts rename to apps/api/src/mappers/proposals/votes.ts index f27cd3f21..84015a20c 100644 --- a/apps/indexer/src/api/mappers/proposals/votes.ts +++ b/apps/api/src/mappers/proposals/votes.ts @@ -1,5 +1,5 @@ import { z } from "@hono/zod-openapi"; -import { votesOnchain } from "ponder:schema"; +import { votesOnchain } from "@/database"; import { getAddress, isAddress } from "viem"; export type DBVote = typeof votesOnchain.$inferSelect; diff --git a/apps/indexer/src/api/mappers/shared.ts b/apps/api/src/mappers/shared.ts similarity index 100% rename from apps/indexer/src/api/mappers/shared.ts rename to apps/api/src/mappers/shared.ts diff --git a/apps/indexer/src/api/mappers/token-metrics/index.ts b/apps/api/src/mappers/token-metrics/index.ts similarity index 100% rename from apps/indexer/src/api/mappers/token-metrics/index.ts rename to apps/api/src/mappers/token-metrics/index.ts diff --git a/apps/indexer/src/api/mappers/token/index.ts b/apps/api/src/mappers/token/index.ts similarity index 97% rename from apps/indexer/src/api/mappers/token/index.ts rename to apps/api/src/mappers/token/index.ts index c152b23cc..85eac7c54 100644 --- a/apps/indexer/src/api/mappers/token/index.ts +++ b/apps/api/src/mappers/token/index.ts @@ -1,5 +1,5 @@ import { z } from "@hono/zod-openapi"; -import { token } from "ponder:schema"; +import { token } from "@/database"; export const TokenHistoricalPriceRequest = z.object({ skip: z.coerce diff --git a/apps/indexer/src/api/mappers/transactions/index.ts b/apps/api/src/mappers/transactions/index.ts similarity index 99% rename from apps/indexer/src/api/mappers/transactions/index.ts rename to apps/api/src/mappers/transactions/index.ts index 4bb72e2de..527b29cec 100644 --- a/apps/indexer/src/api/mappers/transactions/index.ts +++ b/apps/api/src/mappers/transactions/index.ts @@ -1,7 +1,7 @@ import { getAddress, isAddress } from "viem"; import { z } from "@hono/zod-openapi"; -import { transaction } from "ponder:schema"; +import { transaction } from "@/database"; import { DBTransfer, diff --git a/apps/indexer/src/api/mappers/transfers/index.ts b/apps/api/src/mappers/transfers/index.ts similarity index 98% rename from apps/indexer/src/api/mappers/transfers/index.ts rename to apps/api/src/mappers/transfers/index.ts index 0eee20b7f..2e20cc1cb 100644 --- a/apps/indexer/src/api/mappers/transfers/index.ts +++ b/apps/api/src/mappers/transfers/index.ts @@ -1,6 +1,6 @@ import { z } from "@hono/zod-openapi"; -import { transfer } from "ponder:schema"; +import { transfer } from "@/database"; import { getAddress, isAddress } from "viem"; export type DBTransfer = typeof transfer.$inferSelect; diff --git a/apps/indexer/src/api/mappers/treasury/index.ts b/apps/api/src/mappers/treasury/index.ts similarity index 100% rename from apps/indexer/src/api/mappers/treasury/index.ts rename to apps/api/src/mappers/treasury/index.ts diff --git a/apps/indexer/src/api/mappers/voting-power/historical.ts b/apps/api/src/mappers/voting-power/historical.ts similarity index 96% rename from apps/indexer/src/api/mappers/voting-power/historical.ts rename to apps/api/src/mappers/voting-power/historical.ts index 6f7b4e6f0..82466d0cd 100644 --- a/apps/indexer/src/api/mappers/voting-power/historical.ts +++ b/apps/api/src/mappers/voting-power/historical.ts @@ -1,5 +1,5 @@ import { z } from "@hono/zod-openapi"; -import { delegation, votingPowerHistory } from "ponder:schema"; +import { delegation, votingPowerHistory } from "@/database"; import { DBTransfer } from "../transfers"; import { getAddress, isAddress } from "viem"; @@ -7,7 +7,7 @@ import { getAddress, isAddress } from "viem"; type DBDelegation = typeof delegation.$inferSelect; export type DBHistoricalVotingPower = typeof votingPowerHistory.$inferSelect; -export type DBHistoricalVotingPowerWithRelations = DBHistoricalVotingPower & { +export type DBHistoricalVotingPowerWithRelations = this.dbHistoricalVotingPower & { delegations: DBDelegation | null; transfers: DBTransfer | null; }; diff --git a/apps/indexer/src/api/mappers/voting-power/index.ts b/apps/api/src/mappers/voting-power/index.ts similarity index 100% rename from apps/indexer/src/api/mappers/voting-power/index.ts rename to apps/api/src/mappers/voting-power/index.ts diff --git a/apps/indexer/src/api/mappers/voting-power/variations.ts b/apps/api/src/mappers/voting-power/variations.ts similarity index 99% rename from apps/indexer/src/api/mappers/voting-power/variations.ts rename to apps/api/src/mappers/voting-power/variations.ts index 141ee5122..b7cb6042b 100644 --- a/apps/indexer/src/api/mappers/voting-power/variations.ts +++ b/apps/api/src/mappers/voting-power/variations.ts @@ -1,6 +1,6 @@ import { z } from "@hono/zod-openapi"; import { Address, getAddress, isAddress } from "viem"; -import { accountPower } from "ponder:schema"; +import { accountPower } from "@/database"; import { PeriodResponseSchema, TimestampResponseMapper } from "../shared"; diff --git a/apps/indexer/src/api/middlewares/errorHandler.ts b/apps/api/src/middlewares/errorHandler.ts similarity index 100% rename from apps/indexer/src/api/middlewares/errorHandler.ts rename to apps/api/src/middlewares/errorHandler.ts diff --git a/apps/indexer/src/api/middlewares/index.ts b/apps/api/src/middlewares/index.ts similarity index 100% rename from apps/indexer/src/api/middlewares/index.ts rename to apps/api/src/middlewares/index.ts diff --git a/apps/indexer/src/api/repositories/account-balance/historical.ts b/apps/api/src/repositories/account-balance/historical.ts similarity index 88% rename from apps/indexer/src/api/repositories/account-balance/historical.ts rename to apps/api/src/repositories/account-balance/historical.ts index 5779ffbb9..fe0c763f1 100644 --- a/apps/indexer/src/api/repositories/account-balance/historical.ts +++ b/apps/api/src/repositories/account-balance/historical.ts @@ -1,11 +1,13 @@ import { Address } from "viem"; import { gte, and, lte, desc, eq, asc, sql } from "drizzle-orm"; -import { db } from "ponder:api"; +import { Drizzle } from "@/database"; -import { DBHistoricalBalanceWithRelations } from "@/api/mappers"; -import { balanceHistory, transfer } from "ponder:schema"; +import { DBHistoricalBalanceWithRelations } from "@/mappers"; +import { balanceHistory, transfer } from "@/database"; export class HistoricalBalanceRepository { + constructor(private readonly db: Drizzle) {} + async getHistoricalBalances( accountId: Address, skip: number, @@ -17,7 +19,7 @@ export class HistoricalBalanceRepository { fromDate?: number, toDate?: number, ): Promise { - const result = await db + const result = await this.db .select() .from(balanceHistory) .innerJoin( @@ -62,7 +64,7 @@ export class HistoricalBalanceRepository { minDelta?: string, maxDelta?: string, ): Promise { - return await db.$count( + return await this.db.$count( balanceHistory, and( eq(balanceHistory.accountId, accountId), diff --git a/apps/indexer/src/api/repositories/account-balance/index.ts b/apps/api/src/repositories/account-balance/index.ts similarity index 100% rename from apps/indexer/src/api/repositories/account-balance/index.ts rename to apps/api/src/repositories/account-balance/index.ts diff --git a/apps/indexer/src/api/repositories/account-balance/interactions.ts b/apps/api/src/repositories/account-balance/interactions.ts similarity index 89% rename from apps/indexer/src/api/repositories/account-balance/interactions.ts rename to apps/api/src/repositories/account-balance/interactions.ts index 3a48286bd..244207204 100644 --- a/apps/indexer/src/api/repositories/account-balance/interactions.ts +++ b/apps/api/src/repositories/account-balance/interactions.ts @@ -1,11 +1,13 @@ import { Address } from "viem"; -import { asc, desc, gte, sql, and, eq, or, gt, lt, lte } from "ponder"; -import { db } from "ponder:api"; -import { transfer, accountBalance } from "ponder:schema"; +import { asc, desc, gte, sql, and, eq, or, gt, lt, lte } from "drizzle-orm"; +import { Drizzle } from "@/database"; +import { transfer, accountBalance } from "@/database"; import { AccountInteractions, Filter } from "../../mappers"; export class AccountInteractionsRepository { + constructor(private readonly db: Drizzle) {} + async getAccountInteractions( accountId: Address, fromTimestamp: number | undefined, @@ -38,13 +40,13 @@ export class AccountInteractionsRepository { } // Aggregate outgoing transfers (negative amounts) - const scopedTransfers = db + const scopedTransfers = this.db .select() .from(transfer) .where(and(...transferCriteria)) .as("scoped_transfers"); - const transfersFrom = db + const transfersFrom = this.db .select({ accountId: scopedTransfers.fromAccountId, fromAmount: sql`-SUM(${transfer.amount})`.as("from_amount"), @@ -55,7 +57,7 @@ export class AccountInteractionsRepository { .as("transfers_from"); // Aggregate incoming transfers (positive amounts) - const transfersTo = db + const transfersTo = this.db .select({ accountId: scopedTransfers.toAccountId, toAmount: sql`SUM(${transfer.amount})`.as("to_amount"), @@ -66,7 +68,7 @@ export class AccountInteractionsRepository { .as("transfers_to"); // Combine both aggregations - const combined = db + const combined = this.db .select({ accountId: accountBalance.accountId, currentBalance: accountBalance.balance, @@ -97,7 +99,7 @@ export class AccountInteractionsRepository { ) .as("combined"); - const subquery = db + const subquery = this.db .select({ accountId: combined.accountId, currentBalance: combined.currentBalance, @@ -127,7 +129,7 @@ export class AccountInteractionsRepository { ? sql`${subquery.fromCount} + ${subquery.toCount}` : sql`ABS(${subquery.fromChange}) + ABS(${subquery.toChange})`; - const baseQuery = db + const baseQuery = this.db .select() .from(subquery) .where( @@ -142,7 +144,7 @@ export class AccountInteractionsRepository { ) .orderBy(orderDirectionFn(orderByField)); - const totalCountResult = await db + const totalCountResult = await this.db .select({ count: sql`COUNT(*)`.as("count"), }) @@ -170,9 +172,9 @@ export class AccountInteractionsRepository { transferCount: BigInt(transferCount), percentageChange: (currentBalance - BigInt(absoluteChange) ? Number( - (BigInt(absoluteChange) * 10000n) / - (currentBalance - BigInt(absoluteChange)), - ) / 100 + (BigInt(absoluteChange) * 10000n) / + (currentBalance - BigInt(absoluteChange)), + ) / 100 : 0 ).toString(), }), diff --git a/apps/indexer/src/api/repositories/account-balance/listing.ts b/apps/api/src/repositories/account-balance/listing.ts similarity index 88% rename from apps/indexer/src/api/repositories/account-balance/listing.ts rename to apps/api/src/repositories/account-balance/listing.ts index 892ae2fc1..478a7a025 100644 --- a/apps/indexer/src/api/repositories/account-balance/listing.ts +++ b/apps/api/src/repositories/account-balance/listing.ts @@ -1,4 +1,4 @@ -import { AmountFilter, DBAccountBalance } from "@/api/mappers"; +import { AmountFilter, DBAccountBalance } from "@/mappers"; import { and, asc, @@ -11,11 +11,13 @@ import { SQL, sql, } from "drizzle-orm"; -import { db } from "ponder:api"; -import { accountBalance } from "ponder:schema"; +import { Drizzle } from "@/database"; +import { accountBalance } from "@/database"; import { Address } from "viem"; export class AccountBalanceRepository { + constructor(private readonly db: Drizzle) {} + async getAccountBalances( skip: number, limit: number, @@ -36,7 +38,7 @@ export class AccountBalanceRepository { ); // Get total count with filters - const totalCount = await db + const totalCount = await this.db .select({ count: sql`COUNT(*)`.as("count"), }) @@ -44,7 +46,7 @@ export class AccountBalanceRepository { .where(filter); // Get paginated results - const page = await db + const page = await this.db .select() .from(accountBalance) .where(filter) @@ -65,7 +67,7 @@ export class AccountBalanceRepository { async getAccountBalance( accountId: Address, ): Promise { - const [result] = await db + const [result] = await this.db .select() .from(accountBalance) .where(eq(accountBalance.accountId, accountId)) diff --git a/apps/indexer/src/api/repositories/account-balance/variations.ts b/apps/api/src/repositories/account-balance/variations.ts similarity index 89% rename from apps/indexer/src/api/repositories/account-balance/variations.ts rename to apps/api/src/repositories/account-balance/variations.ts index d082a4029..560341120 100644 --- a/apps/indexer/src/api/repositories/account-balance/variations.ts +++ b/apps/api/src/repositories/account-balance/variations.ts @@ -1,11 +1,13 @@ -import { asc, desc, gte, sql, and, inArray, eq, lte } from "ponder"; -import { db } from "ponder:api"; -import { accountBalance, balanceHistory } from "ponder:schema"; -import { DBAccountBalanceVariation } from "@/api/mappers"; +import { asc, desc, gte, sql, and, inArray, eq, lte } from "drizzle-orm"; +import { Drizzle } from "@/database"; +import { accountBalance, balanceHistory } from "@/database"; +import { DBAccountBalanceVariation } from "@/mappers"; import { Address } from "viem"; -import { PERCENTAGE_NO_BASELINE } from "@/api/mappers/constants"; +import { PERCENTAGE_NO_BASELINE } from "@/mappers/constants"; export class BalanceVariationsRepository { + constructor(private readonly db: Drizzle) {} + async getAccountBalanceVariations( fromTimestamp: number | undefined, toTimestamp: number | undefined, @@ -16,7 +18,7 @@ export class BalanceVariationsRepository { ): Promise { const orderDirectionFn = orderDirection === "asc" ? asc : desc; - const latestBeforeFrom = db + const latestBeforeFrom = this.db .select({ accountId: balanceHistory.accountId, balance: balanceHistory.balance, @@ -36,7 +38,7 @@ export class BalanceVariationsRepository { ) .as("latest_before_from"); - const latestBeforeTo = db + const latestBeforeTo = this.db .select({ accountId: balanceHistory.accountId, balance: balanceHistory.balance, @@ -56,7 +58,7 @@ export class BalanceVariationsRepository { ) .as("latest_before_to"); - return await db + return await this.db .select({ accountId: sql
`COALESCE(from_data.account_id, to_data.account_id)`, previousBalance: sql`COALESCE(from_data.balance, 0)`, @@ -90,7 +92,7 @@ export class BalanceVariationsRepository { fromTimestamp: number | undefined, toTimestamp: number | undefined, ): Promise { - const history = db + const history = this.db .select({ accountId: balanceHistory.accountId, delta: balanceHistory.delta, @@ -110,7 +112,7 @@ export class BalanceVariationsRepository { ) .as("history"); - const [delta] = await db + const [delta] = await this.db .select({ accountId: history.accountId, absoluteChange: sql`SUM(${history.delta})`.as("agg_delta"), @@ -118,7 +120,7 @@ export class BalanceVariationsRepository { .from(history) .groupBy(history.accountId); - const [currentBalance] = await db + const [currentBalance] = await this.db .select({ value: accountBalance.balance }) .from(accountBalance) .where(eq(accountBalance.accountId, address)); diff --git a/apps/indexer/src/api/repositories/daoMetricsDayBucket/index.ts b/apps/api/src/repositories/daoMetricsDayBucket/index.ts similarity index 88% rename from apps/indexer/src/api/repositories/daoMetricsDayBucket/index.ts rename to apps/api/src/repositories/daoMetricsDayBucket/index.ts index e8a1ce495..7e27640c2 100644 --- a/apps/indexer/src/api/repositories/daoMetricsDayBucket/index.ts +++ b/apps/api/src/repositories/daoMetricsDayBucket/index.ts @@ -1,8 +1,10 @@ -import { db } from "ponder:api"; -import { daoMetricsDayBucket } from "ponder:schema"; -import { and, gte, lte, desc, asc, eq, lt, inArray } from "ponder"; +import { Drizzle } from "@/database"; +import { daoMetricsDayBucket } from "@/database"; +import { and, gte, lte, desc, asc, eq, lt, inArray } from "drizzle-orm"; export class DaoMetricsDayBucketRepository { + constructor(private readonly db: Drizzle) {} + /** * Fetches metrics by type and date range * @param filters - Metric types, date range, and ordering filters diff --git a/apps/indexer/src/api/repositories/delegations/general.ts b/apps/api/src/repositories/delegations/general.ts similarity index 59% rename from apps/indexer/src/api/repositories/delegations/general.ts rename to apps/api/src/repositories/delegations/general.ts index 4bce9b7b3..ab9d543e6 100644 --- a/apps/indexer/src/api/repositories/delegations/general.ts +++ b/apps/api/src/repositories/delegations/general.ts @@ -1,12 +1,14 @@ -import { DBDelegation } from "@/api/mappers"; +import { DBDelegation } from "@/mappers"; import { desc, eq } from "drizzle-orm"; -import { db } from "ponder:api"; -import { delegation } from "ponder:schema"; +import { Drizzle } from "@/database"; +import { delegation } from "@/database"; import { Address } from "viem"; export class DelegationsRepository { + constructor(private readonly db: Drizzle) {} + async getDelegations(address: Address): Promise { - const result = await db.query.delegation.findMany({ + const result = await this.db.query.delegation.findMany({ where: eq(delegation.delegateAccountId, address), orderBy: [desc(delegation.timestamp), desc(delegation.logIndex)], }); diff --git a/apps/indexer/src/api/repositories/delegations/historical.ts b/apps/api/src/repositories/delegations/historical.ts similarity index 87% rename from apps/indexer/src/api/repositories/delegations/historical.ts rename to apps/api/src/repositories/delegations/historical.ts index fd2b54d79..a256ef53f 100644 --- a/apps/indexer/src/api/repositories/delegations/historical.ts +++ b/apps/api/src/repositories/delegations/historical.ts @@ -1,10 +1,12 @@ -import { DBDelegation } from "@/api/mappers"; +import { DBDelegation } from "@/mappers"; import { asc, desc, eq, gte, lte, SQL, inArray, and, sql } from "drizzle-orm"; -import { db } from "ponder:api"; -import { delegation } from "ponder:schema"; +import { Drizzle } from "@/database"; +import { delegation } from "@/database"; import { Address } from "viem"; export class HistoricalDelegationsRepository { + constructor(private readonly db: Drizzle) {} + async getHistoricalDelegations( // TODO: add support to partial delegations at some point address: Address, @@ -18,7 +20,7 @@ export class HistoricalDelegationsRepository { items: DBDelegation[]; totalCount: number; }> { - const baseQuery = db + const baseQuery = this.db .select() .from(delegation) .where(this.filterToSql(address, fromValue, toValue, delegateAddressIn)) @@ -28,7 +30,7 @@ export class HistoricalDelegationsRepository { : desc(delegation.timestamp), ); - const [totalCount] = await db + const [totalCount] = await this.db .select({ count: sql`COUNT(*)`.as("count"), }) diff --git a/apps/indexer/src/api/repositories/delegations/index.ts b/apps/api/src/repositories/delegations/index.ts similarity index 100% rename from apps/indexer/src/api/repositories/delegations/index.ts rename to apps/api/src/repositories/delegations/index.ts diff --git a/apps/indexer/src/api/repositories/drizzle/index.ts b/apps/api/src/repositories/drizzle/index.ts similarity index 90% rename from apps/indexer/src/api/repositories/drizzle/index.ts rename to apps/api/src/repositories/drizzle/index.ts index 8c5afa98a..1fbd95e45 100644 --- a/apps/indexer/src/api/repositories/drizzle/index.ts +++ b/apps/api/src/repositories/drizzle/index.ts @@ -12,14 +12,14 @@ import { isNull, count, max, -} from "ponder"; -import { db } from "ponder:api"; +} from "drizzle-orm"; +import { Drizzle } from "@/database"; import { accountPower, proposalsOnchain, votesOnchain, votingPowerHistory, -} from "ponder:schema"; +} from "@/database"; import { SQL } from "drizzle-orm"; import { Address } from "viem"; @@ -28,11 +28,13 @@ import { AverageTurnoutCompareQueryResult, ProposalsCompareQueryResult, VotesCompareQueryResult, -} from "@/api/controllers"; +} from "@/controllers"; import { DaysEnum } from "@/lib/enums"; -import { DBProposal, DBVote } from "@/api/mappers"; +import { DBProposal, DBVote } from "@/mappers"; export class DrizzleRepository { + constructor(private readonly db: Drizzle) {} + async getSupplyComparison(metricType: string, days: DaysEnum) { const query = sql` WITH old_data AS ( @@ -54,9 +56,10 @@ export class DrizzleRepository { LEFT JOIN old_data ON 1=1; `; - const result = await db.execute<{ oldValue: string; currentValue: string }>( - query, - ); + const result = await this.db.execute<{ + oldValue: string; + currentValue: string; + }>(query); return result.rows[0]; } @@ -66,7 +69,7 @@ export class DrizzleRepository { FROM "account_power" ap WHERE ap."last_vote_timestamp" >= ${this.now() - days} `; - const result = await db.execute(query); + const result = await this.db.execute(query); return result.rows[0]; } @@ -84,7 +87,7 @@ export class DrizzleRepository { SELECT * FROM current_proposals JOIN old_proposals ON 1=1; `; - const result = await db.execute(query); + const result = await this.db.execute(query); return result.rows[0]; } @@ -102,7 +105,7 @@ export class DrizzleRepository { SELECT * FROM current_votes JOIN old_votes ON 1=1; `; - const result = await db.execute(query); + const result = await this.db.execute(query); return result.rows[0]; } @@ -122,7 +125,8 @@ export class DrizzleRepository { SELECT * FROM current_average_turnout JOIN old_average_turnout ON 1=1; `; - const result = await db.execute(query); + const result = + await this.db.execute(query); return result.rows[0]; } @@ -155,7 +159,7 @@ export class DrizzleRepository { notInArray(proposalsOnchain.proposalType, proposalTypeExclude), ); } - return await db + return await this.db .select() .from(proposalsOnchain) .where(and(...whereClauses)) @@ -169,7 +173,7 @@ export class DrizzleRepository { } async getProposalById(proposalId: string): Promise { - return await db.query.proposalsOnchain.findFirst({ + return await this.db.query.proposalsOnchain.findFirst({ where: eq(proposalsOnchain.id, proposalId), }); } @@ -185,7 +189,7 @@ export class DrizzleRepository { orderDirection: "asc" | "desc", addresses?: Address[], ): Promise<{ voter: Address; votingPower: bigint }[]> { - return await db + return await this.db .select({ voter: accountPower.accountId, votingPower: accountPower.votingPower, @@ -215,7 +219,7 @@ export class DrizzleRepository { } async getProposalNonVotersCount(proposalId: string): Promise { - const countResult = await db + const countResult = await this.db .select({ count: count(accountPower.accountId) }) .from(accountPower) .leftJoin( @@ -234,7 +238,7 @@ export class DrizzleRepository { async getLastVotersTimestamp( voters: Address[], ): Promise> { - const timestamps = await db + const timestamps = await this.db .select({ voterAccountId: votesOnchain.voterAccountId, lastVoteTimestamp: max(votesOnchain.timestamp), @@ -256,7 +260,7 @@ export class DrizzleRepository { voters: Address[], comparisonTimestamp: number, ): Promise> { - const currentPower = db.$with("current_power").as( + const currentPower = this.db.$with("current_power").as( db .selectDistinctOn([votingPowerHistory.accountId], { accountId: votingPowerHistory.accountId, @@ -270,7 +274,7 @@ export class DrizzleRepository { ), ); - const oldPower = db.$with("old_power").as( + const oldPower = this.db.$with("old_power").as( db .selectDistinctOn([votingPowerHistory.accountId], { accountId: votingPowerHistory.accountId, @@ -289,7 +293,7 @@ export class DrizzleRepository { ), ); - const result = await db + const result = await this.db .with(currentPower, oldPower) .select({ voterAccountId: currentPower.accountId, @@ -335,7 +339,7 @@ export class DrizzleRepository { : votesOnchain.timestamp; const orderFn = orderDirection === "asc" ? asc : desc; - return await db + return await this.db .select() .from(votesOnchain) .where(and(...whereClauses)) @@ -361,7 +365,7 @@ export class DrizzleRepository { whereClauses.push(inArray(votesOnchain.voterAccountId, voterAddressIn)); } - return await db.$count(votesOnchain, and(...whereClauses)); + return await this.db.$count(votesOnchain, and(...whereClauses)); } now() { diff --git a/apps/indexer/src/api/repositories/index.ts b/apps/api/src/repositories/index.ts similarity index 100% rename from apps/indexer/src/api/repositories/index.ts rename to apps/api/src/repositories/index.ts diff --git a/apps/indexer/src/api/repositories/last-update/index.ts b/apps/api/src/repositories/last-update/index.ts similarity index 79% rename from apps/indexer/src/api/repositories/last-update/index.ts rename to apps/api/src/repositories/last-update/index.ts index fcf8ce9aa..9586c9c06 100644 --- a/apps/indexer/src/api/repositories/last-update/index.ts +++ b/apps/api/src/repositories/last-update/index.ts @@ -1,15 +1,21 @@ -import { db } from "ponder:api"; -import { inArray } from "ponder"; -import { daoMetricsDayBucket } from "ponder:schema"; +import { Drizzle } from "@/database"; +import { inArray } from "drizzle-orm"; +import { daoMetricsDayBucket } from "@/database"; -import { ChartType } from "@/api/mappers/"; +import { ChartType } from "@/mappers/"; import { MetricTypesEnum } from "@/lib/constants"; export interface LastUpdateRepository { + +constructor(private readonly db: Drizzle) {} + getLastUpdate(chart: ChartType): Promise; } export class LastUpdateRepositoryImpl implements LastUpdateRepository { + +constructor(private readonly db: Drizzle) {} + async getLastUpdate(chart: ChartType) { let metricsToCheck: MetricTypesEnum[] = []; @@ -36,7 +42,7 @@ export class LastUpdateRepositoryImpl implements LastUpdateRepository { break; } // Find the record with the greatest timestamp for the specified metrics - const lastUpdate = await db.query.daoMetricsDayBucket.findFirst({ + const lastUpdate = await this.db.query.daoMetricsDayBucket.findFirst({ columns: { lastUpdate: true, }, diff --git a/apps/indexer/src/api/repositories/proposals-activity/index.ts b/apps/api/src/repositories/proposals-activity/index.ts similarity index 94% rename from apps/indexer/src/api/repositories/proposals-activity/index.ts rename to apps/api/src/repositories/proposals-activity/index.ts index f35fd29ed..48ac87c91 100644 --- a/apps/indexer/src/api/repositories/proposals-activity/index.ts +++ b/apps/api/src/repositories/proposals-activity/index.ts @@ -1,8 +1,8 @@ import { Address } from "viem"; import { DaoIdEnum } from "@/lib/enums"; -import { asc, eq, sql } from "ponder"; -import { db } from "ponder:api"; -import { votesOnchain } from "ponder:schema"; +import { asc, eq, sql } from "drizzle-orm"; +import { Drizzle } from "@/database"; +import { votesOnchain } from "@/database"; export type DbProposal = { id: string; @@ -44,6 +44,9 @@ export type OrderByField = "votingPower" | "voteTiming" | "timestamp"; export type OrderDirection = "asc" | "desc"; export interface ProposalsActivityRepository { + +constructor(private readonly db: Drizzle) {} + getFirstVoteTimestamp(address: Address): Promise; getProposals( @@ -75,10 +78,13 @@ export interface ProposalsActivityRepository { /* eslint-disable */ export class DrizzleProposalsActivityRepository implements ProposalsActivityRepository { + +constructor(private readonly db: Drizzle) {} + /* eslint-enable */ async getFirstVoteTimestamp(address: Address): Promise { - const firstVote = await db.query.votesOnchain.findFirst({ + const firstVote = await this.db.query.votesOnchain.findFirst({ where: eq(votesOnchain.voterAccountId, address), columns: { timestamp: true, @@ -102,7 +108,7 @@ export class DrizzleProposalsActivityRepository implements ProposalsActivityRepo ORDER BY timestamp DESC `; - const result = await db.execute(query); + const result = await this.db.execute(query); return result.rows; } @@ -121,7 +127,7 @@ export class DrizzleProposalsActivityRepository implements ProposalsActivityRepo AND proposal_id IN (${sql.raw(proposalIds.map((id) => `'${id}'`).join(","))}) `; - const result = await db.execute(query); + const result = await this.db.execute(query); return result.rows; } diff --git a/apps/indexer/src/api/repositories/token/erc20.ts b/apps/api/src/repositories/token/erc20.ts similarity index 55% rename from apps/indexer/src/api/repositories/token/erc20.ts rename to apps/api/src/repositories/token/erc20.ts index bb37f46de..38aba1dc3 100644 --- a/apps/indexer/src/api/repositories/token/erc20.ts +++ b/apps/api/src/repositories/token/erc20.ts @@ -1,14 +1,16 @@ import { eq } from "drizzle-orm"; -import { db } from "ponder:api"; -import { token } from "ponder:schema"; -import { DBToken } from "@/api/mappers"; +import { Drizzle } from "@/database"; +import { token } from "@/database"; +import { DBToken } from "@/mappers"; import { DaoIdEnum } from "@/lib/enums"; export class TokenRepository { + constructor(private readonly db: Drizzle) {} + async getTokenPropertiesByName( tokenName: DaoIdEnum, ): Promise { - return await db.query.token.findFirst({ + return await this.db.query.token.findFirst({ where: eq(token.name, tokenName), }); } diff --git a/apps/indexer/src/api/repositories/token/index.ts b/apps/api/src/repositories/token/index.ts similarity index 100% rename from apps/indexer/src/api/repositories/token/index.ts rename to apps/api/src/repositories/token/index.ts diff --git a/apps/indexer/src/api/repositories/token/nft.ts b/apps/api/src/repositories/token/nft.ts similarity index 74% rename from apps/indexer/src/api/repositories/token/nft.ts rename to apps/api/src/repositories/token/nft.ts index f0ccefdff..a74fb3d3c 100644 --- a/apps/indexer/src/api/repositories/token/nft.ts +++ b/apps/api/src/repositories/token/nft.ts @@ -1,10 +1,12 @@ -import { db } from "ponder:api"; -import { tokenPrice } from "ponder:schema"; -import { desc, sql } from "ponder"; +import { Drizzle } from "@/database"; +import { tokenPrice } from "@/database"; +import { desc, sql } from "drizzle-orm"; -import { TokenHistoricalPriceResponse } from "@/api/mappers"; +import { TokenHistoricalPriceResponse } from "@/mappers"; export class NFTPriceRepository { + constructor(private readonly db: Drizzle) {} + /** * Repository for handling NFT price data and calculations. * Provides methods to retrieve historical NFT auction prices with rolling averages. @@ -13,7 +15,7 @@ export class NFTPriceRepository { limit: number, offset: number, ): Promise { - return await db + return await this.db .select({ price: sql` CAST( @@ -32,7 +34,7 @@ export class NFTPriceRepository { } async getTokenPrice(): Promise { - return (await db.query.tokenPrice.findFirst({ + return (await this.db.query.tokenPrice.findFirst({ orderBy: desc(tokenPrice.timestamp), }))!.price.toString(); } diff --git a/apps/indexer/src/api/repositories/transactions/index.ts b/apps/api/src/repositories/transactions/index.ts similarity index 97% rename from apps/indexer/src/api/repositories/transactions/index.ts rename to apps/api/src/repositories/transactions/index.ts index 96661090b..eebdce071 100644 --- a/apps/indexer/src/api/repositories/transactions/index.ts +++ b/apps/api/src/repositories/transactions/index.ts @@ -1,9 +1,11 @@ -import { DBTransaction, TransactionsRequest } from "@/api/mappers"; +import { DBTransaction, TransactionsRequest } from "@/mappers"; import { sql, eq, or, countDistinct, SQLChunk } from "drizzle-orm"; -import { db } from "ponder:api"; -import { delegation, transaction, transfer } from "ponder:schema"; +import { Drizzle } from "@/database"; +import { delegation, transaction, transfer } from "@/database"; export class TransactionsRepository { + constructor(private readonly db: Drizzle) {} + async getFilteredAggregateTransactions( filter: TransactionsRequest, ): Promise { @@ -84,7 +86,7 @@ export class TransactionsRepository { LEFT JOIN delegation_aggregates da ON da.transaction_hash = lt.transaction_hash ORDER BY lt.timestamp DESC; `; - const result = await db.execute(query); + const result = await this.db.execute(query); return result.rows; } @@ -95,7 +97,7 @@ export class TransactionsRepository { const { transfer: transferFilter, delegation: delegationFilter } = this.filterToSql(filter); - const query = await db + const query = await this.db .select({ count: countDistinct( sql`coalesce(${transfer.transactionHash}, ${delegation.transactionHash})`, diff --git a/apps/indexer/src/api/repositories/transfers/index.ts b/apps/api/src/repositories/transfers/index.ts similarity index 91% rename from apps/indexer/src/api/repositories/transfers/index.ts rename to apps/api/src/repositories/transfers/index.ts index c6336fec3..303ca3fbc 100644 --- a/apps/indexer/src/api/repositories/transfers/index.ts +++ b/apps/api/src/repositories/transfers/index.ts @@ -1,15 +1,17 @@ -import { db } from "ponder:api"; +import { Drizzle } from "@/database"; import { and, asc, desc, eq, gte, lte, or } from "drizzle-orm"; -import { transfer } from "ponder:schema"; +import { transfer } from "@/database"; -import { DBTransfer, TransfersRequest } from "@/api/mappers"; +import { DBTransfer, TransfersRequest } from "@/mappers"; export class TransfersRepository { + constructor(private readonly db: Drizzle) {} + async getTransfersCount(req: TransfersRequest): Promise { const addressQuery = this.buildAddressQuery(req); if (!addressQuery) return 0; - return await db.$count( + return await this.db.$count( transfer, and( addressQuery, @@ -31,7 +33,7 @@ export class TransfersRepository { const addressQuery = this.buildAddressQuery(req); if (!addressQuery) return []; - return await db.query.transfer.findMany({ + return await this.db.query.transfer.findMany({ where: (transfer, { gte, lte, and }) => and( addressQuery, diff --git a/apps/indexer/src/api/repositories/treasury/index.ts b/apps/api/src/repositories/treasury/index.ts similarity index 82% rename from apps/indexer/src/api/repositories/treasury/index.ts rename to apps/api/src/repositories/treasury/index.ts index d4bc4ae9f..dc1a14957 100644 --- a/apps/indexer/src/api/repositories/treasury/index.ts +++ b/apps/api/src/repositories/treasury/index.ts @@ -1,12 +1,14 @@ -import { db } from "ponder:api"; -import { daoMetricsDayBucket } from "ponder:schema"; -import { and, eq, gte, lte, desc } from "ponder"; +import { Drizzle } from "@/database"; +import { daoMetricsDayBucket } from "@/database"; +import { and, eq, gte, lte, desc } from "drizzle-orm"; import { MetricTypesEnum } from "@/lib/constants"; /** * Repository for treasury-related database queries. */ export class TreasuryRepository { + constructor(private readonly db: Drizzle) {} + /** * Fetch DAO token quantities from daoMetricsDayBucket table * @param cutoffTimestamp - The timestamp to filter the data @@ -15,7 +17,7 @@ export class TreasuryRepository { async getTokenQuantities( cutoffTimestamp: number, ): Promise> { - const results = await db.query.daoMetricsDayBucket.findMany({ + const results = await this.db.query.daoMetricsDayBucket.findMany({ columns: { date: true, close: true, @@ -45,7 +47,7 @@ export class TreasuryRepository { async getLastTokenQuantityBeforeDate( cutoffTimestamp: number, ): Promise { - const result = await db.query.daoMetricsDayBucket.findFirst({ + const result = await this.db.query.daoMetricsDayBucket.findFirst({ where: and( eq(daoMetricsDayBucket.metricType, MetricTypesEnum.TREASURY), lte(daoMetricsDayBucket.date, BigInt(cutoffTimestamp)), diff --git a/apps/indexer/src/api/repositories/voting-power/general.ts b/apps/api/src/repositories/voting-power/general.ts similarity index 84% rename from apps/indexer/src/api/repositories/voting-power/general.ts rename to apps/api/src/repositories/voting-power/general.ts index 3e6489069..afcceaaca 100644 --- a/apps/indexer/src/api/repositories/voting-power/general.ts +++ b/apps/api/src/repositories/voting-power/general.ts @@ -12,23 +12,25 @@ import { gte, lte, } from "drizzle-orm"; -import { db } from "ponder:api"; +import { Drizzle } from "@/database"; import { votingPowerHistory, delegation, transfer, accountPower, -} from "ponder:schema"; +} from "@/database"; import { AmountFilter, DBAccountPower, DBVotingPowerVariation, DBHistoricalVotingPowerWithRelations, -} from "@/api/mappers"; -import { PERCENTAGE_NO_BASELINE } from "@/api/mappers/constants"; +} from "@/mappers"; +import { PERCENTAGE_NO_BASELINE } from "@/mappers/constants"; export class VotingPowerRepository { + constructor(private readonly db: Drizzle) {} + async getHistoricalVotingPowerCount( accountId?: Address, minDelta?: string, @@ -36,7 +38,7 @@ export class VotingPowerRepository { fromDate?: number, toDate?: number, ): Promise { - return await db.$count( + return await this.db.$count( votingPowerHistory, and( accountId ? eq(votingPowerHistory.accountId, accountId) : undefined, @@ -65,7 +67,7 @@ export class VotingPowerRepository { fromDate?: number, toDate?: number, ): Promise { - const result = await db + const result = await this.db .select() .from(votingPowerHistory) .leftJoin( @@ -108,15 +110,15 @@ export class VotingPowerRepository { .orderBy( orderDirection === "asc" ? asc( - orderBy === "timestamp" - ? votingPowerHistory.timestamp - : votingPowerHistory.deltaMod, - ) + orderBy === "timestamp" + ? votingPowerHistory.timestamp + : votingPowerHistory.deltaMod, + ) : desc( - orderBy === "timestamp" - ? votingPowerHistory.timestamp - : votingPowerHistory.deltaMod, - ), + orderBy === "timestamp" + ? votingPowerHistory.timestamp + : votingPowerHistory.deltaMod, + ), ) .limit(limit) .offset(skip); @@ -125,12 +127,12 @@ export class VotingPowerRepository { ...row.voting_power_history, delegations: row.transfers && - row.transfers?.logIndex > (row.delegations?.logIndex || 0) + row.transfers?.logIndex > (row.delegations?.logIndex || 0) ? null : row.delegations, transfers: row.delegations && - row.delegations?.logIndex > (row.transfers?.logIndex || 0) + row.delegations?.logIndex > (row.transfers?.logIndex || 0) ? null : row.transfers, })); @@ -146,7 +148,7 @@ export class VotingPowerRepository { ): Promise { const orderDirectionFn = orderDirection === "asc" ? asc : desc; - const latestBeforeFrom = db + const latestBeforeFrom = this.db .select({ accountId: votingPowerHistory.accountId, votingPower: votingPowerHistory.votingPower, @@ -168,7 +170,7 @@ export class VotingPowerRepository { ) .as("latest_before_from"); - const latestBeforeTo = db + const latestBeforeTo = this.db .select({ accountId: votingPowerHistory.accountId, votingPower: votingPowerHistory.votingPower, @@ -190,7 +192,7 @@ export class VotingPowerRepository { ) .as("latest_before_to"); - return await db + return await this.db .select({ accountId: sql
`COALESCE(from_data.account_id, to_data.account_id)`, previousVotingPower: sql`COALESCE(from_data.voting_power, 0)`, @@ -224,7 +226,7 @@ export class VotingPowerRepository { startTimestamp: number | undefined, endTimestamp: number | undefined, ): Promise { - const history = db + const history = this.db .select({ accountId: votingPowerHistory.accountId, delta: votingPowerHistory.delta, @@ -244,7 +246,7 @@ export class VotingPowerRepository { ) .as("history"); - const [delta] = await db + const [delta] = await this.db .select({ accountId: history.accountId, absoluteChange: sql`SUM(${history.delta})`.as("agg_delta"), @@ -252,7 +254,7 @@ export class VotingPowerRepository { .from(history) .groupBy(history.accountId); - const [currentAccountPower] = await db + const [currentAccountPower] = await this.db .select({ currentVotingPower: accountPower.votingPower }) .from(accountPower) .where(eq(accountPower.accountId, accountId)); @@ -264,8 +266,8 @@ export class VotingPowerRepository { const oldVotingPower = currentVotingPower - numericAbsoluteChange; const percentageChange = oldVotingPower ? ( - Number((numericAbsoluteChange * 10000n) / oldVotingPower) / 100 - ).toFixed(2) + Number((numericAbsoluteChange * 10000n) / oldVotingPower) / 100 + ).toFixed(2) : "0"; return { @@ -290,7 +292,7 @@ export class VotingPowerRepository { ? accountPower.votingPower : accountPower.delegationsCount; - const items = await db + const items = await this.db .select() .from(accountPower) .where(this.filterToSql(addresses, amountFilter)) @@ -298,7 +300,7 @@ export class VotingPowerRepository { .offset(skip) .limit(limit); - const [totalCount] = await db + const [totalCount] = await this.db .select({ count: sql`COUNT(*)`.as("count"), }) @@ -314,28 +316,30 @@ export class VotingPowerRepository { async getVotingPowersByAccountId( accountId: Address, ): Promise { - const [result] = await db + const [result] = await this.db .select() .from(accountPower) .where(eq(accountPower.accountId, accountId)); - return result ? { - accountId: result.accountId, - votingPower: result.votingPower, - delegationsCount: result.delegationsCount, - votesCount: result.votesCount, - proposalsCount: result.proposalsCount, - daoId: result.daoId, - lastVoteTimestamp: result.lastVoteTimestamp, - } : { - accountId: accountId, - votingPower: 0n, - delegationsCount: 0, - votesCount: 0, - proposalsCount: 0, - daoId: "", - lastVoteTimestamp: 0n, - }; + return result + ? { + accountId: result.accountId, + votingPower: result.votingPower, + delegationsCount: result.delegationsCount, + votesCount: result.votesCount, + proposalsCount: result.proposalsCount, + daoId: result.daoId, + lastVoteTimestamp: result.lastVoteTimestamp, + } + : { + accountId: accountId, + votingPower: 0n, + delegationsCount: 0, + votesCount: 0, + proposalsCount: 0, + daoId: "", + lastVoteTimestamp: 0n, + }; } private filterToSql( diff --git a/apps/indexer/src/api/repositories/voting-power/index.ts b/apps/api/src/repositories/voting-power/index.ts similarity index 100% rename from apps/indexer/src/api/repositories/voting-power/index.ts rename to apps/api/src/repositories/voting-power/index.ts diff --git a/apps/indexer/src/api/repositories/voting-power/nouns.ts b/apps/api/src/repositories/voting-power/nouns.ts similarity index 92% rename from apps/indexer/src/api/repositories/voting-power/nouns.ts rename to apps/api/src/repositories/voting-power/nouns.ts index da6a3e6b0..782087377 100644 --- a/apps/indexer/src/api/repositories/voting-power/nouns.ts +++ b/apps/api/src/repositories/voting-power/nouns.ts @@ -1,11 +1,13 @@ import { Address } from "viem"; import { gte, and, lte, desc, eq, asc, sql } from "drizzle-orm"; -import { db } from "ponder:api"; -import { votingPowerHistory, delegation, transfer } from "ponder:schema"; +import { Drizzle } from "@/database"; +import { votingPowerHistory, delegation, transfer } from "@/database"; -import { DBHistoricalVotingPowerWithRelations } from "@/api/mappers"; +import { DBHistoricalVotingPowerWithRelations } from "@/mappers"; export class NounsVotingPowerRepository { + constructor(private readonly db: Drizzle) {} + async getHistoricalVotingPowerCount( accountId?: Address, minDelta?: string, @@ -13,7 +15,7 @@ export class NounsVotingPowerRepository { fromDate?: number, toDate?: number, ): Promise { - return await db.$count( + return await this.db.$count( votingPowerHistory, and( accountId ? eq(votingPowerHistory.accountId, accountId) : undefined, @@ -42,7 +44,7 @@ export class NounsVotingPowerRepository { fromDate?: number, toDate?: number, ): Promise { - const result = await db + const result = await this.db .select() .from(votingPowerHistory) .where( diff --git a/apps/indexer/src/api/services/account-balance/historical.ts b/apps/api/src/services/account-balance/historical.ts similarity index 92% rename from apps/indexer/src/api/services/account-balance/historical.ts rename to apps/api/src/services/account-balance/historical.ts index 6cad5728e..020887090 100644 --- a/apps/indexer/src/api/services/account-balance/historical.ts +++ b/apps/api/src/services/account-balance/historical.ts @@ -1,8 +1,11 @@ import { Address } from "viem"; -import { DBHistoricalBalanceWithRelations } from "@/api/mappers"; +import { DBHistoricalBalanceWithRelations } from "@/mappers"; interface Repository { + +constructor(private readonly db: Drizzle) {} + getHistoricalBalances( accountId: Address, skip: number, diff --git a/apps/indexer/src/api/services/account-balance/index.ts b/apps/api/src/services/account-balance/index.ts similarity index 100% rename from apps/indexer/src/api/services/account-balance/index.ts rename to apps/api/src/services/account-balance/index.ts diff --git a/apps/indexer/src/api/services/account-balance/listing.ts b/apps/api/src/services/account-balance/listing.ts similarity index 92% rename from apps/indexer/src/api/services/account-balance/listing.ts rename to apps/api/src/services/account-balance/listing.ts index 5a0f6c125..163c775d6 100644 --- a/apps/indexer/src/api/services/account-balance/listing.ts +++ b/apps/api/src/services/account-balance/listing.ts @@ -1,9 +1,12 @@ -import { AmountFilter, DBAccountBalance } from "@/api/mappers"; +import { AmountFilter, DBAccountBalance } from "@/mappers"; import { TreasuryAddresses } from "@/lib/constants"; import { DaoIdEnum } from "@/lib/enums"; import { Address } from "viem"; interface AccountBalanceRepository { + +constructor(private readonly db: Drizzle) {} + getAccountBalances( skip: number, limit: number, diff --git a/apps/indexer/src/api/services/account-balance/variations.ts b/apps/api/src/services/account-balance/variations.ts similarity index 96% rename from apps/indexer/src/api/services/account-balance/variations.ts rename to apps/api/src/services/account-balance/variations.ts index 09bfbde74..fc0a6cb32 100644 --- a/apps/indexer/src/api/services/account-balance/variations.ts +++ b/apps/api/src/services/account-balance/variations.ts @@ -2,10 +2,13 @@ import { DBAccountBalanceVariation, AccountInteractions, Filter, -} from "@/api/mappers"; +} from "@/mappers"; import { Address } from "viem"; interface AccountBalanceRepository { + +constructor(private readonly db: Drizzle) {} + getAccountBalanceVariations( fromTimestamp: number | undefined, toTimestamp: number | undefined, @@ -23,6 +26,9 @@ interface AccountBalanceRepository { } interface AccountInteractionsRepository { + +constructor(private readonly db: Drizzle) {} + getAccountInteractions( accountId: Address, fromTimestamp: number | undefined, diff --git a/apps/indexer/src/api/services/coingecko/index.ts b/apps/api/src/services/coingecko/index.ts similarity index 96% rename from apps/indexer/src/api/services/coingecko/index.ts rename to apps/api/src/services/coingecko/index.ts index 1eaa22ca6..fbf3a904f 100644 --- a/apps/indexer/src/api/services/coingecko/index.ts +++ b/apps/api/src/services/coingecko/index.ts @@ -10,8 +10,8 @@ import { } from "./types"; import { DAYS_IN_YEAR } from "@/lib/constants"; import { DaoIdEnum } from "@/lib/enums"; -import { TokenHistoricalPriceResponse } from "@/api/mappers"; -import { PriceProvider } from "@/api/services/treasury/types"; +import { TokenHistoricalPriceResponse } from "@/mappers"; +import { PriceProvider } from "@/services/treasury/types"; import { truncateTimestampToMidnight } from "@/lib/date-helpers"; const createCoingeckoTokenPriceDataSchema = ( diff --git a/apps/indexer/src/api/services/coingecko/types.ts b/apps/api/src/services/coingecko/types.ts similarity index 100% rename from apps/indexer/src/api/services/coingecko/types.ts rename to apps/api/src/services/coingecko/types.ts diff --git a/apps/indexer/src/api/services/dao/index.ts b/apps/api/src/services/dao/index.ts similarity index 92% rename from apps/indexer/src/api/services/dao/index.ts rename to apps/api/src/services/dao/index.ts index 6a5d92101..1549fe5e5 100644 --- a/apps/indexer/src/api/services/dao/index.ts +++ b/apps/api/src/services/dao/index.ts @@ -1,6 +1,6 @@ import { DAOClient } from "@/interfaces/client"; -import { DaoDataCache } from "@/api/cache/dao-cache.interface"; -import { DaoResponse } from "@/api/mappers"; +import { DaoDataCache } from "@/cache/dao-cache.interface"; +import { DaoResponse } from "@/mappers"; export class DaoService { constructor( diff --git a/apps/indexer/src/api/services/delegation-percentage/delegation-percentage.service.test.ts b/apps/api/src/services/delegation-percentage/delegation-percentage.service.test.ts similarity index 99% rename from apps/indexer/src/api/services/delegation-percentage/delegation-percentage.service.test.ts rename to apps/api/src/services/delegation-percentage/delegation-percentage.service.test.ts index 0fe608a84..bfeb6cf79 100644 --- a/apps/indexer/src/api/services/delegation-percentage/delegation-percentage.service.test.ts +++ b/apps/api/src/services/delegation-percentage/delegation-percentage.service.test.ts @@ -1,5 +1,5 @@ import { DelegationPercentageService } from "./delegation-percentage"; -import { DaoMetricsDayBucketRepository } from "@/api/repositories/"; +import { DaoMetricsDayBucketRepository } from "@/repositories/"; import { MetricTypesEnum } from "@/lib/constants"; /** diff --git a/apps/indexer/src/api/services/delegation-percentage/delegation-percentage.test.ts b/apps/api/src/services/delegation-percentage/delegation-percentage.test.ts similarity index 99% rename from apps/indexer/src/api/services/delegation-percentage/delegation-percentage.test.ts rename to apps/api/src/services/delegation-percentage/delegation-percentage.test.ts index 0fe608a84..bfeb6cf79 100644 --- a/apps/indexer/src/api/services/delegation-percentage/delegation-percentage.test.ts +++ b/apps/api/src/services/delegation-percentage/delegation-percentage.test.ts @@ -1,5 +1,5 @@ import { DelegationPercentageService } from "./delegation-percentage"; -import { DaoMetricsDayBucketRepository } from "@/api/repositories/"; +import { DaoMetricsDayBucketRepository } from "@/repositories/"; import { MetricTypesEnum } from "@/lib/constants"; /** diff --git a/apps/indexer/src/api/services/delegation-percentage/delegation-percentage.ts b/apps/api/src/services/delegation-percentage/delegation-percentage.ts similarity index 98% rename from apps/indexer/src/api/services/delegation-percentage/delegation-percentage.ts rename to apps/api/src/services/delegation-percentage/delegation-percentage.ts index eade26b2b..2cb33f4ef 100644 --- a/apps/indexer/src/api/services/delegation-percentage/delegation-percentage.ts +++ b/apps/api/src/services/delegation-percentage/delegation-percentage.ts @@ -30,12 +30,12 @@ import { MetricTypesEnum } from "@/lib/constants"; import { forwardFill, generateOrderedTimeline } from "@/lib/time-series"; import { applyCursorPagination } from "@/lib/query-helpers"; import { getEffectiveStartDate } from "@/lib/date-helpers"; -import { DaoMetricsDayBucketRepository } from "@/api/repositories/"; +import { DaoMetricsDayBucketRepository } from "@/repositories/"; import { DelegationPercentageItem, DelegationPercentageQuery, normalizeTimestamp, -} from "@/api/mappers/"; +} from "@/mappers/"; /** * Service result type diff --git a/apps/indexer/src/api/services/delegation-percentage/index.ts b/apps/api/src/services/delegation-percentage/index.ts similarity index 100% rename from apps/indexer/src/api/services/delegation-percentage/index.ts rename to apps/api/src/services/delegation-percentage/index.ts diff --git a/apps/indexer/src/api/services/delegations/current.ts b/apps/api/src/services/delegations/current.ts similarity index 79% rename from apps/indexer/src/api/services/delegations/current.ts rename to apps/api/src/services/delegations/current.ts index 8bbacadc0..f7340e43d 100644 --- a/apps/indexer/src/api/services/delegations/current.ts +++ b/apps/api/src/services/delegations/current.ts @@ -1,7 +1,10 @@ -import { DBDelegation } from "@/api/mappers"; +import { DBDelegation } from "@/mappers"; import { Address } from "viem"; interface Repository { + +constructor(private readonly db: Drizzle) {} + getDelegations(address: Address): Promise; } diff --git a/apps/indexer/src/api/services/delegations/historical.ts b/apps/api/src/services/delegations/historical.ts similarity index 91% rename from apps/indexer/src/api/services/delegations/historical.ts rename to apps/api/src/services/delegations/historical.ts index dcdae728b..d0458ab1a 100644 --- a/apps/indexer/src/api/services/delegations/historical.ts +++ b/apps/api/src/services/delegations/historical.ts @@ -1,7 +1,10 @@ -import { DBDelegation } from "@/api/mappers"; +import { DBDelegation } from "@/mappers"; import { Address } from "viem"; interface Repository { + +constructor(private readonly db: Drizzle) {} + getHistoricalDelegations( address: Address, orderDirection: "asc" | "desc", diff --git a/apps/indexer/src/api/services/delegations/index.ts b/apps/api/src/services/delegations/index.ts similarity index 100% rename from apps/indexer/src/api/services/delegations/index.ts rename to apps/api/src/services/delegations/index.ts diff --git a/apps/indexer/src/api/services/dune/index.ts b/apps/api/src/services/dune/index.ts similarity index 100% rename from apps/indexer/src/api/services/dune/index.ts rename to apps/api/src/services/dune/index.ts diff --git a/apps/indexer/src/api/services/dune/service.ts b/apps/api/src/services/dune/service.ts similarity index 100% rename from apps/indexer/src/api/services/dune/service.ts rename to apps/api/src/services/dune/service.ts diff --git a/apps/indexer/src/api/services/index.ts b/apps/api/src/services/index.ts similarity index 100% rename from apps/indexer/src/api/services/index.ts rename to apps/api/src/services/index.ts diff --git a/apps/indexer/src/api/services/last-update/index.ts b/apps/api/src/services/last-update/index.ts similarity index 78% rename from apps/indexer/src/api/services/last-update/index.ts rename to apps/api/src/services/last-update/index.ts index 02a894033..6316b069f 100644 --- a/apps/indexer/src/api/services/last-update/index.ts +++ b/apps/api/src/services/last-update/index.ts @@ -1,5 +1,5 @@ -import { ChartType } from "@/api/mappers/"; -import { LastUpdateRepository } from "@/api/repositories/"; +import { ChartType } from "@/mappers/"; +import { LastUpdateRepository } from "@/repositories/"; export class LastUpdateService { constructor(private readonly repository: LastUpdateRepository) {} diff --git a/apps/indexer/src/api/services/nft-price/index.ts b/apps/api/src/services/nft-price/index.ts similarity index 95% rename from apps/indexer/src/api/services/nft-price/index.ts rename to apps/api/src/services/nft-price/index.ts index e73c13b94..06f0ad2ff 100644 --- a/apps/indexer/src/api/services/nft-price/index.ts +++ b/apps/api/src/services/nft-price/index.ts @@ -1,8 +1,8 @@ import { formatEther } from "viem"; import axios, { AxiosInstance } from "axios"; -import { TokenHistoricalPriceResponse } from "@/api/mappers"; -import { PriceProvider } from "@/api/services/treasury/types"; +import { TokenHistoricalPriceResponse } from "@/mappers"; +import { PriceProvider } from "@/services/treasury/types"; import { forwardFill, createDailyTimeline } from "@/lib/time-series"; import { truncateTimestampToMidnight, @@ -10,6 +10,9 @@ import { } from "@/lib/date-helpers"; interface Repository { + +constructor(private readonly db: Drizzle) {} + getHistoricalNFTPrice( limit: number, offset: number, diff --git a/apps/indexer/src/api/services/proposals-activity/index.ts b/apps/api/src/services/proposals-activity/index.ts similarity index 99% rename from apps/indexer/src/api/services/proposals-activity/index.ts rename to apps/api/src/services/proposals-activity/index.ts index 4de6b0a7a..e6732f50f 100644 --- a/apps/indexer/src/api/services/proposals-activity/index.ts +++ b/apps/api/src/services/proposals-activity/index.ts @@ -7,9 +7,9 @@ import { OrderByField, OrderDirection, VoteFilter, -} from "@/api/repositories/"; +} from "@/repositories/"; import { DAOClient } from "@/interfaces/client"; -import { DBProposal } from "@/api/mappers"; +import { DBProposal } from "@/mappers"; const FINAL_PROPOSAL_STATUSES = ["EXECUTED", "DEFEATED", "CANCELED", "EXPIRED"]; diff --git a/apps/indexer/src/api/services/proposals/index.ts b/apps/api/src/services/proposals/index.ts similarity index 98% rename from apps/indexer/src/api/services/proposals/index.ts rename to apps/api/src/services/proposals/index.ts index b9569f4bf..71614eff5 100644 --- a/apps/indexer/src/api/services/proposals/index.ts +++ b/apps/api/src/services/proposals/index.ts @@ -5,13 +5,16 @@ import { VotesResponse, DBVote, VotesMapper, -} from "@/api/mappers"; +} from "@/mappers"; import { DAOClient } from "@/interfaces/client"; import { ProposalStatus } from "@/lib/constants"; import { DaysEnum } from "@/lib/enums"; import { Address } from "viem"; interface ProposalsRepository { + +constructor(private readonly db: Drizzle) {} + getProposals( skip: number, limit: number, diff --git a/apps/indexer/src/api/services/token-metrics/index.ts b/apps/api/src/services/token-metrics/index.ts similarity index 97% rename from apps/indexer/src/api/services/token-metrics/index.ts rename to apps/api/src/services/token-metrics/index.ts index b3332fe2e..98de1cb9b 100644 --- a/apps/indexer/src/api/services/token-metrics/index.ts +++ b/apps/api/src/services/token-metrics/index.ts @@ -28,8 +28,8 @@ import { normalizeMapTimestamps, getEffectiveStartDate, } from "@/lib/date-helpers"; -import { DaoMetricsDayBucketRepository } from "@/api/repositories/daoMetricsDayBucket"; -import { TokenMetricItem } from "@/api/mappers/token-metrics"; +import { DaoMetricsDayBucketRepository } from "@/repositories/daoMetricsDayBucket"; +import { TokenMetricItem } from "@/mappers/token-metrics"; import { MetricTypesEnum } from "@/lib/constants"; interface MetricData { diff --git a/apps/indexer/src/api/services/token/index.ts b/apps/api/src/services/token/index.ts similarity index 100% rename from apps/indexer/src/api/services/token/index.ts rename to apps/api/src/services/token/index.ts diff --git a/apps/indexer/src/api/services/token/token.ts b/apps/api/src/services/token/token.ts similarity index 83% rename from apps/indexer/src/api/services/token/token.ts rename to apps/api/src/services/token/token.ts index 4eb008b5b..5cd14f359 100644 --- a/apps/indexer/src/api/services/token/token.ts +++ b/apps/api/src/services/token/token.ts @@ -1,7 +1,10 @@ -import { DBToken } from "@/api/mappers"; +import { DBToken } from "@/mappers"; import { DaoIdEnum } from "@/lib/enums"; interface TokenRepository { + +constructor(private readonly db: Drizzle) {} + getTokenPropertiesByName( tokenId: DaoIdEnum, ): Promise; diff --git a/apps/indexer/src/api/services/transactions/index.ts b/apps/api/src/services/transactions/index.ts similarity index 92% rename from apps/indexer/src/api/services/transactions/index.ts rename to apps/api/src/services/transactions/index.ts index ab7ddf300..1e54937d2 100644 --- a/apps/indexer/src/api/services/transactions/index.ts +++ b/apps/api/src/services/transactions/index.ts @@ -3,9 +3,12 @@ import { TransactionsResponse, TransactionMapper, DBTransaction, -} from "@/api/mappers/"; +} from "@/mappers/"; interface TransactionsRepository { + +constructor(private readonly db: Drizzle) {} + getFilteredAggregateTransactions( req: TransactionsRequest, ): Promise; diff --git a/apps/indexer/src/api/services/transfers/index.ts b/apps/api/src/services/transfers/index.ts similarity index 91% rename from apps/indexer/src/api/services/transfers/index.ts rename to apps/api/src/services/transfers/index.ts index 865388bfa..3a2a6220a 100644 --- a/apps/indexer/src/api/services/transfers/index.ts +++ b/apps/api/src/services/transfers/index.ts @@ -3,9 +3,12 @@ import { DBTransfer, TransfersResponse, TransferMapper, -} from "@/api/mappers"; +} from "@/mappers"; interface TransfersRepository { + +constructor(private readonly db: Drizzle) {} + getTransfersCount(req: TransfersRequest): Promise; getTransfers(req: TransfersRequest): Promise; } diff --git a/apps/indexer/src/api/services/treasury/index.ts b/apps/api/src/services/treasury/index.ts similarity index 100% rename from apps/indexer/src/api/services/treasury/index.ts rename to apps/api/src/services/treasury/index.ts diff --git a/apps/indexer/src/api/services/treasury/providers/compound-provider.ts b/apps/api/src/services/treasury/providers/compound-provider.ts similarity index 100% rename from apps/indexer/src/api/services/treasury/providers/compound-provider.ts rename to apps/api/src/services/treasury/providers/compound-provider.ts diff --git a/apps/indexer/src/api/services/treasury/providers/defillama-provider.ts b/apps/api/src/services/treasury/providers/defillama-provider.ts similarity index 100% rename from apps/indexer/src/api/services/treasury/providers/defillama-provider.ts rename to apps/api/src/services/treasury/providers/defillama-provider.ts diff --git a/apps/indexer/src/api/services/treasury/providers/dune-provider.ts b/apps/api/src/services/treasury/providers/dune-provider.ts similarity index 100% rename from apps/indexer/src/api/services/treasury/providers/dune-provider.ts rename to apps/api/src/services/treasury/providers/dune-provider.ts diff --git a/apps/indexer/src/api/services/treasury/providers/index.ts b/apps/api/src/services/treasury/providers/index.ts similarity index 100% rename from apps/indexer/src/api/services/treasury/providers/index.ts rename to apps/api/src/services/treasury/providers/index.ts diff --git a/apps/indexer/src/api/services/treasury/providers/provider-cache.ts b/apps/api/src/services/treasury/providers/provider-cache.ts similarity index 100% rename from apps/indexer/src/api/services/treasury/providers/provider-cache.ts rename to apps/api/src/services/treasury/providers/provider-cache.ts diff --git a/apps/indexer/src/api/services/treasury/providers/treasury-provider.interface.ts b/apps/api/src/services/treasury/providers/treasury-provider.interface.ts similarity index 100% rename from apps/indexer/src/api/services/treasury/providers/treasury-provider.interface.ts rename to apps/api/src/services/treasury/providers/treasury-provider.interface.ts diff --git a/apps/indexer/src/api/services/treasury/treasury-provider-factory.ts b/apps/api/src/services/treasury/treasury-provider-factory.ts similarity index 97% rename from apps/indexer/src/api/services/treasury/treasury-provider-factory.ts rename to apps/api/src/services/treasury/treasury-provider-factory.ts index 5007c33e4..edf815156 100644 --- a/apps/indexer/src/api/services/treasury/treasury-provider-factory.ts +++ b/apps/api/src/services/treasury/treasury-provider-factory.ts @@ -2,7 +2,7 @@ import axios from "axios"; import { DefiLlamaProvider } from "./providers/defillama-provider"; import { DuneProvider } from "./providers/dune-provider"; import { TreasuryService } from "./treasury.service"; -import { TreasuryRepository } from "@/api/repositories/treasury"; +import { TreasuryRepository } from "@/repositories/treasury"; import { PriceProvider } from "./types"; import { CompoundProvider, TreasuryProvider } from "./providers"; diff --git a/apps/indexer/src/api/services/treasury/treasury.service.ts b/apps/api/src/services/treasury/treasury.service.ts similarity index 98% rename from apps/indexer/src/api/services/treasury/treasury.service.ts rename to apps/api/src/services/treasury/treasury.service.ts index 084d6a2f7..7630bc6ab 100644 --- a/apps/indexer/src/api/services/treasury/treasury.service.ts +++ b/apps/api/src/services/treasury/treasury.service.ts @@ -1,7 +1,7 @@ import { formatUnits } from "viem"; import { TreasuryProvider } from "./providers"; import { PriceProvider } from "./types"; -import { TreasuryResponse } from "@/api/mappers/treasury"; +import { TreasuryResponse } from "@/mappers/treasury"; import { TreasuryRepository } from "../../repositories/treasury"; import { forwardFill, createDailyTimeline } from "@/lib/time-series"; import { diff --git a/apps/indexer/src/api/services/treasury/types.ts b/apps/api/src/services/treasury/types.ts similarity index 100% rename from apps/indexer/src/api/services/treasury/types.ts rename to apps/api/src/services/treasury/types.ts diff --git a/apps/indexer/src/api/services/voting-power/index.ts b/apps/api/src/services/voting-power/index.ts similarity index 97% rename from apps/indexer/src/api/services/voting-power/index.ts rename to apps/api/src/services/voting-power/index.ts index 4090dcfa0..8ac9e990e 100644 --- a/apps/indexer/src/api/services/voting-power/index.ts +++ b/apps/api/src/services/voting-power/index.ts @@ -5,9 +5,12 @@ import { DBVotingPowerVariation, AmountFilter, DBAccountPower, -} from "@/api/mappers"; +} from "@/mappers"; interface HistoricalVotingPowerRepository { + +constructor(private readonly db: Drizzle) {} + getHistoricalVotingPowers( skip: number, limit: number, @@ -30,6 +33,9 @@ interface HistoricalVotingPowerRepository { } interface VotingPowersRepository { + +constructor(private readonly db: Drizzle) {} + getVotingPowerVariations( startTimestamp: number | undefined, endTimestamp: number | undefined, diff --git a/apps/indexer/src/api/services/voting-power/voting-power.ts b/apps/api/src/services/voting-power/voting-power.ts similarity index 91% rename from apps/indexer/src/api/services/voting-power/voting-power.ts rename to apps/api/src/services/voting-power/voting-power.ts index 2fe826fe9..1cb407c90 100644 --- a/apps/indexer/src/api/services/voting-power/voting-power.ts +++ b/apps/api/src/services/voting-power/voting-power.ts @@ -1,8 +1,11 @@ import { Address } from "viem"; -import { DBVotingPowerVariation, DBAccountPower } from "@/api/mappers"; +import { DBVotingPowerVariation, DBAccountPower } from "@/mappers"; interface VotingPowerRepository { + +constructor(private readonly db: Drizzle) {} + getVotingPowers( accountId: Address, skip: number, @@ -17,6 +20,9 @@ interface VotingPowerRepository { } interface VotingPowerVariationRepository { + +constructor(private readonly db: Drizzle) {} + getVotingPowerChanges( startTimestamp: number, limit: number, diff --git a/apps/api/tsconfig.json b/apps/api/tsconfig.json new file mode 100644 index 000000000..d4a2eb8e0 --- /dev/null +++ b/apps/api/tsconfig.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + // Type checking + "strict": true, + "noUncheckedIndexedAccess": true, + // Interop constraints + "verbatimModuleSyntax": false, + "esModuleInterop": true, + "isolatedModules": true, + "allowSyntheticDefaultImports": true, + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + // Language and environment + "moduleResolution": "bundler", + "module": "ESNext", + "noEmit": true, + "lib": ["ES2022"], + "target": "ES2022", + // Skip type checking for node modules + "skipLibCheck": true, + "paths": { + "@/*": ["./src/*"] + }, + "outDir": "./dist" + }, + "include": ["./**/*.ts"], + "exclude": ["node_modules", "test"] +} diff --git a/apps/indexer/src/api/.gitkeep b/apps/indexer/src/api/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/package.json b/package.json index 5b0bb501a..f39eefd4e 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,8 @@ "prettier": "^3.4.2", "prettier-plugin-tailwindcss": "^0.6.11", "turbo": "^2.3.1", - "typescript": "^5.8.3" + "typescript": "^5.8.3", + "eslint-plugin-import": "^2.32.0" }, "private": true, "workspaces": [ diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 317e86f4f..e89b0a193 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -31,6 +31,9 @@ importers: eslint-config-prettier: specifier: ^9.1.0 version: 9.1.2(eslint@9.39.2(jiti@2.6.1)) + eslint-plugin-import: + specifier: ^2.32.0 + version: 2.32.0(@typescript-eslint/parser@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1)) eslint-plugin-prettier: specifier: ^5.2.1 version: 5.5.4(@types/eslint@9.6.1)(eslint-config-prettier@9.1.2(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1))(prettier@3.7.4) @@ -53,6 +56,70 @@ importers: specifier: ^5.8.3 version: 5.9.3 + apps/api: + dependencies: + "@hono/zod-openapi": + specifier: ^0.19.6 + version: 0.19.10(hono@4.10.7)(zod@3.25.76) + axios: + specifier: ^1.9.0 + version: 1.13.2 + drizzle-kit: + specifier: ^0.31.4 + version: 0.31.7 + drizzle-orm: + specifier: ~0.41.0 + version: 0.41.0(@electric-sql/pglite@0.2.13)(@opentelemetry/api@1.9.0)(@types/pg@8.15.6)(kysely@0.26.3)(pg@8.16.3) + hono: + specifier: ^4.7.10 + version: 4.10.7 + viem: + specifier: ^2.41.2 + version: 2.41.2(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76) + zod: + specifier: ^3.25.3 + version: 3.25.76 + zod-validation-error: + specifier: ^3.4.1 + version: 3.5.4(zod@3.25.76) + devDependencies: + "@types/jest": + specifier: ^29.5.14 + version: 29.5.14 + "@types/node": + specifier: ^20.16.5 + version: 20.19.25 + "@types/pg": + specifier: ^8.15.6 + version: 8.15.6 + dotenv: + specifier: ^16.5.0 + version: 16.6.1 + eslint: + specifier: ^8.53.0 + version: 8.57.1 + eslint-config-prettier: + specifier: ^9.1.0 + version: 9.1.2(eslint@8.57.1) + eslint-plugin-prettier: + specifier: ^5.2.1 + version: 5.5.4(@types/eslint@9.6.1)(eslint-config-prettier@9.1.2(eslint@8.57.1))(eslint@8.57.1)(prettier@3.7.4) + jest: + specifier: ^29.7.0 + version: 29.7.0(@types/node@20.19.25)(ts-node@10.9.2(@types/node@20.19.25)(typescript@5.9.3)) + prettier: + specifier: ^3.5.3 + version: 3.7.4 + ts-jest: + specifier: ^29.4.1 + version: 29.4.6(@babel/core@7.28.5)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.5))(esbuild@0.25.8)(jest-util@29.7.0)(jest@29.7.0(@types/node@20.19.25)(ts-node@10.9.2(@types/node@20.19.25)(typescript@5.9.3)))(typescript@5.9.3) + ts-node: + specifier: ^10.9.2 + version: 10.9.2(@types/node@20.19.25)(typescript@5.9.3) + typescript: + specifier: ^5.8.3 + version: 5.9.3 + apps/api-gateway: dependencies: "@graphql-mesh/config": @@ -444,7 +511,7 @@ importers: version: 4.9.6 forge-std: specifier: github:foundry-rs/forge-std - version: https://codeload.github.com/foundry-rs/forge-std/tar.gz/f61e4dd133379a4536a54ee57a808c9c00019b60 + version: https://codeload.github.com/foundry-rs/forge-std/tar.gz/0e44f85a13976ba7491c6a9ee994b1a7efc3c281 packages: "@adobe/css-tools@4.4.3": @@ -459,12 +526,6 @@ packages: integrity: sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw==, } - "@adraffy/ens-normalize@1.11.0": - resolution: - { - integrity: sha512-/3DDPKHqqIqxUULp8yP4zODUY1i+2xvVWsv8A79xGWdCAG+8sb0hRh0Rk2QyOJUnnbyPUAZYcpBuRe3nS2OIUg==, - } - "@adraffy/ens-normalize@1.11.1": resolution: { @@ -5127,13 +5188,6 @@ packages: } engines: { node: ^14.21.3 || >=16 } - "@noble/curves@1.9.4": - resolution: - { - integrity: sha512-2bKONnuM53lINoDrSmK8qP8W271ms7pygDhZt4SiLOoLwBtoHqeCFi6RG42V8zd3mLHuJFhU/Bmaqo4nX0/kBw==, - } - engines: { node: ^14.21.3 || >=16 } - "@noble/curves@1.9.7": resolution: { @@ -7316,12 +7370,6 @@ packages: integrity: sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==, } - "@types/node@24.10.1": - resolution: - { - integrity: sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==, - } - "@types/pg@8.15.6": resolution: { @@ -11385,10 +11433,10 @@ packages: } engines: { node: ">=14" } - forge-std@https://codeload.github.com/foundry-rs/forge-std/tar.gz/f61e4dd133379a4536a54ee57a808c9c00019b60: + forge-std@https://codeload.github.com/foundry-rs/forge-std/tar.gz/0e44f85a13976ba7491c6a9ee994b1a7efc3c281: resolution: { - tarball: https://codeload.github.com/foundry-rs/forge-std/tar.gz/f61e4dd133379a4536a54ee57a808c9c00019b60, + tarball: https://codeload.github.com/foundry-rs/forge-std/tar.gz/0e44f85a13976ba7491c6a9ee994b1a7efc3c281, } version: 1.14.0 @@ -16005,14 +16053,6 @@ packages: } hasBin: true - semver@7.7.2: - resolution: - { - integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==, - } - engines: { node: ">=10" } - hasBin: true - semver@7.7.3: resolution: { @@ -18370,8 +18410,6 @@ snapshots: "@adraffy/ens-normalize@1.10.1": {} - "@adraffy/ens-normalize@1.11.0": {} - "@adraffy/ens-normalize@1.11.1": {} "@alloc/quick-lru@5.2.0": {} @@ -22574,10 +22612,6 @@ snapshots: dependencies: "@noble/hashes": 1.8.0 - "@noble/curves@1.9.4": - dependencies: - "@noble/hashes": 1.8.0 - "@noble/curves@1.9.7": dependencies: "@noble/hashes": 1.8.0 @@ -23513,7 +23547,7 @@ snapshots: "@scure/bip32@1.7.0": dependencies: - "@noble/curves": 1.9.4 + "@noble/curves": 1.9.7 "@noble/hashes": 1.8.0 "@scure/base": 1.2.6 @@ -23970,7 +24004,7 @@ snapshots: dependencies: "@babel/runtime": 7.28.4 "@noble/curves": 1.9.7 - "@noble/hashes": 1.4.0 + "@noble/hashes": 1.8.0 "@solana/buffer-layout": 4.0.1 "@solana/codecs-numbers": 2.3.0(typescript@5.9.3) agentkeepalive: 4.6.0 @@ -24452,10 +24486,6 @@ snapshots: dependencies: undici-types: 6.19.8 - "@types/node@24.10.1": - dependencies: - undici-types: 7.16.0 - "@types/pg@8.15.6": dependencies: "@types/node": 20.19.25 @@ -24494,7 +24524,7 @@ snapshots: "@types/ws@8.18.1": dependencies: - "@types/node": 24.10.1 + "@types/node": 20.19.25 "@types/yargs-parser@21.0.3": {} @@ -25566,6 +25596,11 @@ snapshots: typescript: 5.9.3 zod: 3.25.76 + abitype@1.2.1(typescript@5.9.3)(zod@3.22.4): + optionalDependencies: + typescript: 5.9.3 + zod: 3.22.4 + abitype@1.2.1(typescript@5.9.3)(zod@3.25.76): optionalDependencies: typescript: 5.9.3 @@ -27788,7 +27823,7 @@ snapshots: cross-spawn: 7.0.6 signal-exit: 4.1.0 - forge-std@https://codeload.github.com/foundry-rs/forge-std/tar.gz/f61e4dd133379a4536a54ee57a808c9c00019b60: + forge-std@https://codeload.github.com/foundry-rs/forge-std/tar.gz/0e44f85a13976ba7491c6a9ee994b1a7efc3c281: {} fork-ts-checker-webpack-plugin@9.1.0(typescript@5.9.3)(webpack@5.103.0): @@ -29701,11 +29736,11 @@ snapshots: ox@0.6.7(typescript@5.9.3)(zod@3.25.76): dependencies: "@adraffy/ens-normalize": 1.11.1 - "@noble/curves": 1.8.1 - "@noble/hashes": 1.7.1 - "@scure/bip32": 1.6.2 - "@scure/bip39": 1.5.4 - abitype: 1.0.8(typescript@5.9.3)(zod@3.25.76) + "@noble/curves": 1.9.7 + "@noble/hashes": 1.8.0 + "@scure/bip32": 1.7.0 + "@scure/bip39": 1.6.0 + abitype: 1.2.1(typescript@5.9.3)(zod@3.25.76) eventemitter3: 5.0.1 optionalDependencies: typescript: 5.9.3 @@ -29743,13 +29778,13 @@ snapshots: ox@0.9.6(typescript@5.9.3)(zod@3.22.4): dependencies: - "@adraffy/ens-normalize": 1.11.0 + "@adraffy/ens-normalize": 1.11.1 "@noble/ciphers": 1.3.0 "@noble/curves": 1.9.1 "@noble/hashes": 1.8.0 "@scure/bip32": 1.7.0 "@scure/bip39": 1.6.0 - abitype: 1.1.0(typescript@5.9.3)(zod@3.22.4) + abitype: 1.2.1(typescript@5.9.3)(zod@3.22.4) eventemitter3: 5.0.1 optionalDependencies: typescript: 5.9.3 @@ -29758,13 +29793,13 @@ snapshots: ox@0.9.6(typescript@5.9.3)(zod@3.25.76): dependencies: - "@adraffy/ens-normalize": 1.11.0 + "@adraffy/ens-normalize": 1.11.1 "@noble/ciphers": 1.3.0 "@noble/curves": 1.9.1 "@noble/hashes": 1.8.0 "@scure/bip32": 1.7.0 "@scure/bip39": 1.6.0 - abitype: 1.1.0(typescript@5.9.3)(zod@3.25.76) + abitype: 1.2.1(typescript@5.9.3)(zod@3.25.76) eventemitter3: 5.0.1 optionalDependencies: typescript: 5.9.3 @@ -30815,8 +30850,6 @@ snapshots: semver@6.3.1: {} - semver@7.7.2: {} - semver@7.7.3: {} sentence-case@3.0.4: @@ -31938,7 +31971,7 @@ snapshots: vite-node@3.2.4(@types/node@20.19.25)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2): dependencies: cac: 6.7.14 - debug: 4.4.1 + debug: 4.4.3 es-module-lexer: 1.7.0 pathe: 2.0.3 vite: 7.0.5(@types/node@20.19.25)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) From c9c6c15094c5d9071a60053303971fbcf5342564 Mon Sep 17 00:00:00 2001 From: lucas picollo Date: Thu, 29 Jan 2026 11:55:45 -0300 Subject: [PATCH 02/16] fix: typechecks --- apps/api/src/clients/comp/index.ts | 2 +- apps/api/src/clients/ens/index.ts | 10 ++--- apps/api/src/clients/governor.base.ts | 22 ++++------ apps/api/src/clients/gtc/index.ts | 10 ++--- apps/api/src/clients/index.ts | 25 +++++++++++ apps/api/src/clients/nouns/index.ts | 10 ++--- apps/api/src/clients/obol/index.ts | 10 ++--- apps/api/src/clients/op/index.ts | 10 ++--- apps/api/src/clients/scr/index.ts | 10 ++--- apps/api/src/clients/uni/index.ts | 10 ++--- apps/api/src/clients/zk/index.ts | 10 ++--- .../governance-activity/controller.ts | 3 -- .../proposals/proposals-activity.ts | 2 +- .../controllers/token/token-distribution.ts | 5 +-- .../src/mappers/account-balance/historical.ts | 2 +- .../mappers/account-balance/interactions.ts | 4 +- .../src/mappers/voting-power/historical.ts | 2 +- .../repositories/daoMetricsDayBucket/index.ts | 4 +- apps/api/src/repositories/drizzle/index.ts | 6 +-- .../api/src/repositories/last-update/index.ts | 6 +-- .../repositories/proposals-activity/index.ts | 42 ++----------------- .../services/account-balance/historical.ts | 3 -- .../src/services/account-balance/listing.ts | 3 -- .../services/account-balance/variations.ts | 6 --- apps/api/src/services/coingecko/index.ts | 3 +- apps/api/src/services/dao/index.ts | 2 +- apps/api/src/services/delegations/current.ts | 3 -- .../src/services/delegations/historical.ts | 3 -- apps/api/src/services/nft-price/index.ts | 3 -- .../src/services/proposals-activity/index.ts | 34 ++++++++++++++- apps/api/src/services/proposals/index.ts | 5 +-- apps/api/src/services/token/token.ts | 3 -- apps/api/src/services/transactions/index.ts | 3 -- apps/api/src/services/transfers/index.ts | 3 -- apps/api/src/services/voting-power/index.ts | 6 --- .../src/services/voting-power/voting-power.ts | 6 --- package.json | 4 +- 37 files changed, 127 insertions(+), 168 deletions(-) diff --git a/apps/api/src/clients/comp/index.ts b/apps/api/src/clients/comp/index.ts index 306d0d551..91bb6ca87 100644 --- a/apps/api/src/clients/comp/index.ts +++ b/apps/api/src/clients/comp/index.ts @@ -8,7 +8,7 @@ import { Transport, } from "viem"; -import { DAOClient } from "@/interfaces/client"; +import { DAOClient } from "@/clients"; import { GovernorBase } from "../governor.base"; import { COMPGovernorAbi } from "./abi"; import { getBlockNumber, readContract } from "viem/actions"; diff --git a/apps/api/src/clients/ens/index.ts b/apps/api/src/clients/ens/index.ts index 065355692..7f116cb39 100644 --- a/apps/api/src/clients/ens/index.ts +++ b/apps/api/src/clients/ens/index.ts @@ -9,15 +9,15 @@ import { } from "viem"; import { getBlockNumber, readContract } from "viem/actions"; -import { DAOClient } from "@/interfaces/client"; +import { DAOClient } from "@/clients"; import { ENSGovernorAbi } from "./abi"; import { GovernorBase } from "../governor.base"; export class ENSClient< - TTransport extends Transport = Transport, - TChain extends Chain = Chain, - TAccount extends Account | undefined = Account | undefined, - > + TTransport extends Transport = Transport, + TChain extends Chain = Chain, + TAccount extends Account | undefined = Account | undefined, +> extends GovernorBase implements DAOClient { diff --git a/apps/api/src/clients/governor.base.ts b/apps/api/src/clients/governor.base.ts index b170848a0..4241a5c12 100644 --- a/apps/api/src/clients/governor.base.ts +++ b/apps/api/src/clients/governor.base.ts @@ -1,6 +1,5 @@ import { Account, Chain, Client, Transport } from "viem"; -import { DBProposal } from "../api/mappers"; import { ProposalStatus } from "../lib/constants"; /** @@ -26,18 +25,15 @@ export abstract class GovernorBase< abstract getQuorum(proposalId: string | null): Promise; - async getProposalStatus( - proposal: Pick< - DBProposal, - | "id" - | "status" - | "startBlock" - | "endBlock" - | "forVotes" - | "againstVotes" - | "abstainVotes" - >, - ): Promise { + async getProposalStatus(proposal: { + id: string; + status: string; + startBlock: number; + endBlock: number; + forVotes: bigint; + againstVotes: bigint; + abstainVotes: bigint; + }): Promise { const currentBlock = await this.getCurrentBlockNumber(); // Skip proposals already finalized via event diff --git a/apps/api/src/clients/gtc/index.ts b/apps/api/src/clients/gtc/index.ts index d7fc3f151..d4d69fbc5 100644 --- a/apps/api/src/clients/gtc/index.ts +++ b/apps/api/src/clients/gtc/index.ts @@ -9,15 +9,15 @@ import { } from "viem"; import { getBlockNumber, readContract } from "viem/actions"; -import { DAOClient } from "@/interfaces/client"; +import { DAOClient } from "@/clients"; import { GovernorAbi } from "./abi/governor"; import { GovernorBase } from "../governor.base"; export class GTCClient< - TTransport extends Transport = Transport, - TChain extends Chain = Chain, - TAccount extends Account | undefined = Account | undefined, - > + TTransport extends Transport = Transport, + TChain extends Chain = Chain, + TAccount extends Account | undefined = Account | undefined, +> extends GovernorBase implements DAOClient { diff --git a/apps/api/src/clients/index.ts b/apps/api/src/clients/index.ts index 86006d04f..4a3282151 100644 --- a/apps/api/src/clients/index.ts +++ b/apps/api/src/clients/index.ts @@ -7,3 +7,28 @@ export * from "./comp"; export * from "./obol"; export * from "./zk"; export * from "./uni"; + +export interface DAOClient { + getDaoId: () => string; + getVotingDelay: () => Promise; + getVotingPeriod: () => Promise; + getTimelockDelay: () => Promise; + getQuorum: (proposalId: string | null) => Promise; + getProposalThreshold: () => Promise; + getCurrentBlockNumber: () => Promise; + getBlockTime: (blockNumber: number) => Promise; + calculateQuorum: (votes: { + forVotes: bigint; + againstVotes: bigint; + abstainVotes: bigint; + }) => bigint; + getProposalStatus: (proposal: { + id: string; + status: string; + startBlock: number; + endBlock: number; + forVotes: bigint; + againstVotes: bigint; + abstainVotes: bigint; + }) => Promise; +} diff --git a/apps/api/src/clients/nouns/index.ts b/apps/api/src/clients/nouns/index.ts index 847eed160..3befd6026 100644 --- a/apps/api/src/clients/nouns/index.ts +++ b/apps/api/src/clients/nouns/index.ts @@ -9,15 +9,15 @@ import { } from "viem"; import { readContract } from "viem/actions"; -import { DAOClient } from "@/interfaces/client"; +import { DAOClient } from "@/clients"; import { GovernorAbi } from "./abi/governor"; import { GovernorBase } from "../governor.base"; export class Client< - TTransport extends Transport = Transport, - TChain extends Chain = Chain, - TAccount extends Account | undefined = Account | undefined, - > + TTransport extends Transport = Transport, + TChain extends Chain = Chain, + TAccount extends Account | undefined = Account | undefined, +> extends GovernorBase implements DAOClient { diff --git a/apps/api/src/clients/obol/index.ts b/apps/api/src/clients/obol/index.ts index 4e54c803e..616fa5b9d 100644 --- a/apps/api/src/clients/obol/index.ts +++ b/apps/api/src/clients/obol/index.ts @@ -9,15 +9,15 @@ import { } from "viem"; import { getBlockNumber, readContract } from "viem/actions"; -import { DAOClient } from "@/interfaces/client"; +import { DAOClient } from "@/clients"; import { ObolGovernorAbi } from "./abi"; import { GovernorBase } from "../governor.base"; export class ObolClient< - TTransport extends Transport = Transport, - TChain extends Chain = Chain, - TAccount extends Account | undefined = Account | undefined, - > + TTransport extends Transport = Transport, + TChain extends Chain = Chain, + TAccount extends Account | undefined = Account | undefined, +> extends GovernorBase implements DAOClient { diff --git a/apps/api/src/clients/op/index.ts b/apps/api/src/clients/op/index.ts index bd95930bf..5a87c78be 100644 --- a/apps/api/src/clients/op/index.ts +++ b/apps/api/src/clients/op/index.ts @@ -9,15 +9,15 @@ import { } from "viem"; import { readContract } from "viem/actions"; -import { DAOClient } from "@/interfaces/client"; +import { DAOClient } from "@/clients"; import { GovernorAbi } from "./abi"; import { GovernorBase } from "../governor.base"; export class OPClient< - TTransport extends Transport = Transport, - TChain extends Chain = Chain, - TAccount extends Account | undefined = Account | undefined, - > + TTransport extends Transport = Transport, + TChain extends Chain = Chain, + TAccount extends Account | undefined = Account | undefined, +> extends GovernorBase implements DAOClient { diff --git a/apps/api/src/clients/scr/index.ts b/apps/api/src/clients/scr/index.ts index aa72d6d5b..41ae0786a 100644 --- a/apps/api/src/clients/scr/index.ts +++ b/apps/api/src/clients/scr/index.ts @@ -10,15 +10,15 @@ import { } from "viem"; import { readContract } from "viem/actions"; -import { DAOClient } from "@/interfaces/client"; +import { DAOClient } from "@/clients"; import { GovernorAbi } from "./abi/governor"; import { GovernorBase } from "../governor.base"; export class SCRClient< - TTransport extends Transport = Transport, - TChain extends Chain = Chain, - TAccount extends Account | undefined = Account | undefined, - > + TTransport extends Transport = Transport, + TChain extends Chain = Chain, + TAccount extends Account | undefined = Account | undefined, +> extends GovernorBase implements DAOClient { diff --git a/apps/api/src/clients/uni/index.ts b/apps/api/src/clients/uni/index.ts index f406bdc62..5a6e8018f 100644 --- a/apps/api/src/clients/uni/index.ts +++ b/apps/api/src/clients/uni/index.ts @@ -9,15 +9,15 @@ import { } from "viem"; import { readContract } from "viem/actions"; -import { DAOClient } from "@/interfaces/client"; +import { DAOClient } from "@/clients"; import { GovernorAbi } from "./abi"; import { GovernorBase } from "../governor.base"; export class UNIClient< - TTransport extends Transport = Transport, - TChain extends Chain = Chain, - TAccount extends Account | undefined = Account | undefined, - > + TTransport extends Transport = Transport, + TChain extends Chain = Chain, + TAccount extends Account | undefined = Account | undefined, +> extends GovernorBase implements DAOClient { diff --git a/apps/api/src/clients/zk/index.ts b/apps/api/src/clients/zk/index.ts index e836f0664..c0e155700 100644 --- a/apps/api/src/clients/zk/index.ts +++ b/apps/api/src/clients/zk/index.ts @@ -8,16 +8,16 @@ import { Transport, } from "viem"; -import { DAOClient } from "@/interfaces/client"; +import { DAOClient } from "@/clients"; import { GovernorBase } from "../governor.base"; import { GovernorAbi } from "./abi"; import { readContract } from "viem/actions"; export class ZKClient< - TTransport extends Transport = Transport, - TChain extends Chain = Chain, - TAccount extends Account | undefined = Account | undefined, - > + TTransport extends Transport = Transport, + TChain extends Chain = Chain, + TAccount extends Account | undefined = Account | undefined, +> extends GovernorBase implements DAOClient { diff --git a/apps/api/src/controllers/governance-activity/controller.ts b/apps/api/src/controllers/governance-activity/controller.ts index 8961d58ce..4d8c94efe 100644 --- a/apps/api/src/controllers/governance-activity/controller.ts +++ b/apps/api/src/controllers/governance-activity/controller.ts @@ -10,9 +10,6 @@ import { import { formatEther } from "viem"; interface GovernanceActivityRepository { - -constructor(private readonly db: Drizzle) {} - getActiveSupply(days: DaysEnum): Promise; getProposalsCompare( days: DaysEnum, diff --git a/apps/api/src/controllers/proposals/proposals-activity.ts b/apps/api/src/controllers/proposals/proposals-activity.ts index 03ce53f04..a651d14fd 100644 --- a/apps/api/src/controllers/proposals/proposals-activity.ts +++ b/apps/api/src/controllers/proposals/proposals-activity.ts @@ -5,7 +5,7 @@ import { DaoIdEnum } from "@/lib/enums"; import { ProposalsActivityService } from "@/services"; import { ProposalsActivityRepository, VoteFilter } from "@/repositories/"; import { CONTRACT_ADDRESSES } from "@/lib/constants"; -import { DAOClient } from "@/interfaces/client"; +import { DAOClient } from "@/clients"; import { ProposalActivityResponseSchema } from "@/mappers"; export function proposalsActivity( diff --git a/apps/api/src/controllers/token/token-distribution.ts b/apps/api/src/controllers/token/token-distribution.ts index d4ab0a90d..5d09725dd 100644 --- a/apps/api/src/controllers/token/token-distribution.ts +++ b/apps/api/src/controllers/token/token-distribution.ts @@ -5,9 +5,6 @@ import { DaysEnum, DaysOpts } from "@/lib/enums"; import { MetricTypesEnum } from "@/lib/constants"; interface TokenDistributionRepository { - -constructor(private readonly db: Drizzle) {} - getSupplyComparison( metricType: string, days: DaysEnum, @@ -138,7 +135,7 @@ export function tokenDistribution( const changeRate = parseInt(oldValue) && (BigInt(currentValue) * parseEther("1")) / BigInt(oldValue) - - parseEther("1"); + parseEther("1"); /* eslint-enable */ return ctx.json( diff --git a/apps/api/src/mappers/account-balance/historical.ts b/apps/api/src/mappers/account-balance/historical.ts index d7e5cb8cc..220d20d99 100644 --- a/apps/api/src/mappers/account-balance/historical.ts +++ b/apps/api/src/mappers/account-balance/historical.ts @@ -4,7 +4,7 @@ import { getAddress, isAddress } from "viem"; import { DBTransfer } from "../transfers"; export type DBHistoricalBalance = typeof balanceHistory.$inferSelect; -export type DBHistoricalBalanceWithRelations = this.dbHistoricalBalance & { +export type DBHistoricalBalanceWithRelations = DBHistoricalBalance & { transfer: DBTransfer; }; diff --git a/apps/api/src/mappers/account-balance/interactions.ts b/apps/api/src/mappers/account-balance/interactions.ts index 318f333ff..31e05407f 100644 --- a/apps/api/src/mappers/account-balance/interactions.ts +++ b/apps/api/src/mappers/account-balance/interactions.ts @@ -7,7 +7,7 @@ export const AccountInteractionsParamsSchema = z.object({ address: z .string() .refine(isAddress, "Invalid address") - .transform((addr) => getAddress(addr)) + .transform((addr) => getAddress(addr)), }); export const AccountInteractionsQuerySchema = z.object({ @@ -66,7 +66,7 @@ export type AccountInteractionsResponse = z.infer< typeof AccountInteractionsResponseSchema >; -export type DBAccountInteraction = this.dbAccountBalanceVariation & { +export type DBAccountInteraction = DBAccountBalanceVariation & { totalVolume: bigint; transferCount: bigint; }; diff --git a/apps/api/src/mappers/voting-power/historical.ts b/apps/api/src/mappers/voting-power/historical.ts index 82466d0cd..d708f18cf 100644 --- a/apps/api/src/mappers/voting-power/historical.ts +++ b/apps/api/src/mappers/voting-power/historical.ts @@ -7,7 +7,7 @@ import { getAddress, isAddress } from "viem"; type DBDelegation = typeof delegation.$inferSelect; export type DBHistoricalVotingPower = typeof votingPowerHistory.$inferSelect; -export type DBHistoricalVotingPowerWithRelations = this.dbHistoricalVotingPower & { +export type DBHistoricalVotingPowerWithRelations = DBHistoricalVotingPower & { delegations: DBDelegation | null; transfers: DBTransfer | null; }; diff --git a/apps/api/src/repositories/daoMetricsDayBucket/index.ts b/apps/api/src/repositories/daoMetricsDayBucket/index.ts index 7e27640c2..5bd811746 100644 --- a/apps/api/src/repositories/daoMetricsDayBucket/index.ts +++ b/apps/api/src/repositories/daoMetricsDayBucket/index.ts @@ -28,7 +28,7 @@ export class DaoMetricsDayBucketRepository { conditions.push(lte(daoMetricsDayBucket.date, BigInt(endDate))); } - return db.query.daoMetricsDayBucket.findMany({ + return this.db.query.daoMetricsDayBucket.findMany({ where: and(...conditions), limit, orderBy: @@ -45,7 +45,7 @@ export class DaoMetricsDayBucketRepository { * @returns The most recent metric row or null if not found */ async getLastMetricBeforeDate(metricType: string, beforeDate: string) { - return db.query.daoMetricsDayBucket.findFirst({ + return this.db.query.daoMetricsDayBucket.findFirst({ where: and( lt(daoMetricsDayBucket.date, BigInt(beforeDate)), eq(daoMetricsDayBucket.metricType, metricType), diff --git a/apps/api/src/repositories/drizzle/index.ts b/apps/api/src/repositories/drizzle/index.ts index 1fbd95e45..6087f0539 100644 --- a/apps/api/src/repositories/drizzle/index.ts +++ b/apps/api/src/repositories/drizzle/index.ts @@ -179,7 +179,7 @@ export class DrizzleRepository { } async getProposalsCount(): Promise { - return db.$count(proposalsOnchain); + return this.db.$count(proposalsOnchain); } async getProposalNonVoters( @@ -261,7 +261,7 @@ export class DrizzleRepository { comparisonTimestamp: number, ): Promise> { const currentPower = this.db.$with("current_power").as( - db + this.db .selectDistinctOn([votingPowerHistory.accountId], { accountId: votingPowerHistory.accountId, votingPower: votingPowerHistory.votingPower, @@ -275,7 +275,7 @@ export class DrizzleRepository { ); const oldPower = this.db.$with("old_power").as( - db + this.db .selectDistinctOn([votingPowerHistory.accountId], { accountId: votingPowerHistory.accountId, votingPower: votingPowerHistory.votingPower, diff --git a/apps/api/src/repositories/last-update/index.ts b/apps/api/src/repositories/last-update/index.ts index 9586c9c06..4ee9244ea 100644 --- a/apps/api/src/repositories/last-update/index.ts +++ b/apps/api/src/repositories/last-update/index.ts @@ -6,15 +6,11 @@ import { ChartType } from "@/mappers/"; import { MetricTypesEnum } from "@/lib/constants"; export interface LastUpdateRepository { - -constructor(private readonly db: Drizzle) {} - getLastUpdate(chart: ChartType): Promise; } export class LastUpdateRepositoryImpl implements LastUpdateRepository { - -constructor(private readonly db: Drizzle) {} + constructor(private readonly db: Drizzle) {} async getLastUpdate(chart: ChartType) { let metricsToCheck: MetricTypesEnum[] = []; diff --git a/apps/api/src/repositories/proposals-activity/index.ts b/apps/api/src/repositories/proposals-activity/index.ts index 48ac87c91..2d83d2b4a 100644 --- a/apps/api/src/repositories/proposals-activity/index.ts +++ b/apps/api/src/repositories/proposals-activity/index.ts @@ -43,43 +43,9 @@ export enum VoteFilter { export type OrderByField = "votingPower" | "voteTiming" | "timestamp"; export type OrderDirection = "asc" | "desc"; -export interface ProposalsActivityRepository { - -constructor(private readonly db: Drizzle) {} - - getFirstVoteTimestamp(address: Address): Promise; - - getProposals( - daoId: DaoIdEnum, - activityStart: number, - votingPeriodSeconds: number, - ): Promise; - - getUserVotes( - address: Address, - daoId: DaoIdEnum, - proposalIds: string[], - ): Promise; - - getProposalsWithVotesAndPagination( - address: Address, - activityStart: number, - votingPeriodSeconds: number, - skip: number, - limit: number, - orderBy: OrderByField, - orderDirection: OrderDirection, - userVoteFilter?: VoteFilter, - ): Promise<{ - proposals: DbProposalWithVote[]; - totalCount: number; - }>; -} - /* eslint-disable */ -export class DrizzleProposalsActivityRepository implements ProposalsActivityRepository { - -constructor(private readonly db: Drizzle) {} +export class DrizzleProposalsActivityRepository { + constructor(private readonly db: Drizzle) {} /* eslint-enable */ @@ -201,7 +167,7 @@ constructor(private readonly db: Drizzle) {} `; const [result, countResult] = await Promise.all([ - db.execute<{ + this.db.execute<{ id: string; dao_id: string; proposer_account_id: string; @@ -222,7 +188,7 @@ constructor(private readonly db: Drizzle) {} reason: string | null; vote_timestamp: string | null; }>(query), - db.execute<{ total_count: string }>(countQuery), + this.db.execute<{ total_count: string }>(countQuery), ]); const totalCount = Number(countResult.rows[0]?.total_count || 0); diff --git a/apps/api/src/services/account-balance/historical.ts b/apps/api/src/services/account-balance/historical.ts index 020887090..69e0d0a6e 100644 --- a/apps/api/src/services/account-balance/historical.ts +++ b/apps/api/src/services/account-balance/historical.ts @@ -3,9 +3,6 @@ import { Address } from "viem"; import { DBHistoricalBalanceWithRelations } from "@/mappers"; interface Repository { - -constructor(private readonly db: Drizzle) {} - getHistoricalBalances( accountId: Address, skip: number, diff --git a/apps/api/src/services/account-balance/listing.ts b/apps/api/src/services/account-balance/listing.ts index 163c775d6..f8a1abd8a 100644 --- a/apps/api/src/services/account-balance/listing.ts +++ b/apps/api/src/services/account-balance/listing.ts @@ -4,9 +4,6 @@ import { DaoIdEnum } from "@/lib/enums"; import { Address } from "viem"; interface AccountBalanceRepository { - -constructor(private readonly db: Drizzle) {} - getAccountBalances( skip: number, limit: number, diff --git a/apps/api/src/services/account-balance/variations.ts b/apps/api/src/services/account-balance/variations.ts index fc0a6cb32..d2b510134 100644 --- a/apps/api/src/services/account-balance/variations.ts +++ b/apps/api/src/services/account-balance/variations.ts @@ -6,9 +6,6 @@ import { import { Address } from "viem"; interface AccountBalanceRepository { - -constructor(private readonly db: Drizzle) {} - getAccountBalanceVariations( fromTimestamp: number | undefined, toTimestamp: number | undefined, @@ -26,9 +23,6 @@ constructor(private readonly db: Drizzle) {} } interface AccountInteractionsRepository { - -constructor(private readonly db: Drizzle) {} - getAccountInteractions( accountId: Address, fromTimestamp: number | undefined, diff --git a/apps/api/src/services/coingecko/index.ts b/apps/api/src/services/coingecko/index.ts index fbf3a904f..d591a1434 100644 --- a/apps/api/src/services/coingecko/index.ts +++ b/apps/api/src/services/coingecko/index.ts @@ -8,7 +8,6 @@ import { CoingeckoIdToAssetPlatformId, CoingeckoTokenIdEnum, } from "./types"; -import { DAYS_IN_YEAR } from "@/lib/constants"; import { DaoIdEnum } from "@/lib/enums"; import { TokenHistoricalPriceResponse } from "@/mappers"; import { PriceProvider } from "@/services/treasury/types"; @@ -53,7 +52,7 @@ export class CoingeckoService implements PriceProvider { } async getHistoricalTokenData( - days: number = DAYS_IN_YEAR, + days: number = 365, ): Promise { const tokenId = CoingeckoTokenIdEnum[this.daoId]; diff --git a/apps/api/src/services/dao/index.ts b/apps/api/src/services/dao/index.ts index 1549fe5e5..b591aee0e 100644 --- a/apps/api/src/services/dao/index.ts +++ b/apps/api/src/services/dao/index.ts @@ -1,4 +1,4 @@ -import { DAOClient } from "@/interfaces/client"; +import { DAOClient } from "@/clients"; import { DaoDataCache } from "@/cache/dao-cache.interface"; import { DaoResponse } from "@/mappers"; diff --git a/apps/api/src/services/delegations/current.ts b/apps/api/src/services/delegations/current.ts index f7340e43d..f387531cd 100644 --- a/apps/api/src/services/delegations/current.ts +++ b/apps/api/src/services/delegations/current.ts @@ -2,9 +2,6 @@ import { DBDelegation } from "@/mappers"; import { Address } from "viem"; interface Repository { - -constructor(private readonly db: Drizzle) {} - getDelegations(address: Address): Promise; } diff --git a/apps/api/src/services/delegations/historical.ts b/apps/api/src/services/delegations/historical.ts index d0458ab1a..fa86e3a05 100644 --- a/apps/api/src/services/delegations/historical.ts +++ b/apps/api/src/services/delegations/historical.ts @@ -2,9 +2,6 @@ import { DBDelegation } from "@/mappers"; import { Address } from "viem"; interface Repository { - -constructor(private readonly db: Drizzle) {} - getHistoricalDelegations( address: Address, orderDirection: "asc" | "desc", diff --git a/apps/api/src/services/nft-price/index.ts b/apps/api/src/services/nft-price/index.ts index 06f0ad2ff..1543021dd 100644 --- a/apps/api/src/services/nft-price/index.ts +++ b/apps/api/src/services/nft-price/index.ts @@ -10,9 +10,6 @@ import { } from "@/lib/date-helpers"; interface Repository { - -constructor(private readonly db: Drizzle) {} - getHistoricalNFTPrice( limit: number, offset: number, diff --git a/apps/api/src/services/proposals-activity/index.ts b/apps/api/src/services/proposals-activity/index.ts index e6732f50f..d39ef8792 100644 --- a/apps/api/src/services/proposals-activity/index.ts +++ b/apps/api/src/services/proposals-activity/index.ts @@ -1,14 +1,14 @@ import { Address } from "viem"; import { DaoIdEnum } from "@/lib/enums"; import { - ProposalsActivityRepository, DbProposal, DbVote, OrderByField, OrderDirection, VoteFilter, + DbProposalWithVote, } from "@/repositories/"; -import { DAOClient } from "@/interfaces/client"; +import { DAOClient } from "@/clients"; import { DBProposal } from "@/mappers"; const FINAL_PROPOSAL_STATUSES = ["EXECUTED", "DEFEATED", "CANCELED", "EXPIRED"]; @@ -62,6 +62,36 @@ export interface DelegateProposalActivity { proposals: ProposalWithUserVote[]; } +export interface ProposalsActivityRepository { + getFirstVoteTimestamp(address: Address): Promise; + + getProposals( + daoId: DaoIdEnum, + activityStart: number, + votingPeriodSeconds: number, + ): Promise; + + getUserVotes( + address: Address, + daoId: DaoIdEnum, + proposalIds: string[], + ): Promise; + + getProposalsWithVotesAndPagination( + address: Address, + activityStart: number, + votingPeriodSeconds: number, + skip: number, + limit: number, + orderBy: OrderByField, + orderDirection: OrderDirection, + userVoteFilter?: VoteFilter, + ): Promise<{ + proposals: DbProposalWithVote[]; + totalCount: number; + }>; +} + export class ProposalsActivityService { constructor( private readonly repository: ProposalsActivityRepository, diff --git a/apps/api/src/services/proposals/index.ts b/apps/api/src/services/proposals/index.ts index 71614eff5..75cc89b72 100644 --- a/apps/api/src/services/proposals/index.ts +++ b/apps/api/src/services/proposals/index.ts @@ -6,15 +6,12 @@ import { DBVote, VotesMapper, } from "@/mappers"; -import { DAOClient } from "@/interfaces/client"; +import { DAOClient } from "@/clients"; import { ProposalStatus } from "@/lib/constants"; import { DaysEnum } from "@/lib/enums"; import { Address } from "viem"; interface ProposalsRepository { - -constructor(private readonly db: Drizzle) {} - getProposals( skip: number, limit: number, diff --git a/apps/api/src/services/token/token.ts b/apps/api/src/services/token/token.ts index 5cd14f359..eba08bb44 100644 --- a/apps/api/src/services/token/token.ts +++ b/apps/api/src/services/token/token.ts @@ -2,9 +2,6 @@ import { DBToken } from "@/mappers"; import { DaoIdEnum } from "@/lib/enums"; interface TokenRepository { - -constructor(private readonly db: Drizzle) {} - getTokenPropertiesByName( tokenId: DaoIdEnum, ): Promise; diff --git a/apps/api/src/services/transactions/index.ts b/apps/api/src/services/transactions/index.ts index 1e54937d2..151af5ddd 100644 --- a/apps/api/src/services/transactions/index.ts +++ b/apps/api/src/services/transactions/index.ts @@ -6,9 +6,6 @@ import { } from "@/mappers/"; interface TransactionsRepository { - -constructor(private readonly db: Drizzle) {} - getFilteredAggregateTransactions( req: TransactionsRequest, ): Promise; diff --git a/apps/api/src/services/transfers/index.ts b/apps/api/src/services/transfers/index.ts index 3a2a6220a..95f30cf1e 100644 --- a/apps/api/src/services/transfers/index.ts +++ b/apps/api/src/services/transfers/index.ts @@ -6,9 +6,6 @@ import { } from "@/mappers"; interface TransfersRepository { - -constructor(private readonly db: Drizzle) {} - getTransfersCount(req: TransfersRequest): Promise; getTransfers(req: TransfersRequest): Promise; } diff --git a/apps/api/src/services/voting-power/index.ts b/apps/api/src/services/voting-power/index.ts index 8ac9e990e..7beb8caf4 100644 --- a/apps/api/src/services/voting-power/index.ts +++ b/apps/api/src/services/voting-power/index.ts @@ -8,9 +8,6 @@ import { } from "@/mappers"; interface HistoricalVotingPowerRepository { - -constructor(private readonly db: Drizzle) {} - getHistoricalVotingPowers( skip: number, limit: number, @@ -33,9 +30,6 @@ constructor(private readonly db: Drizzle) {} } interface VotingPowersRepository { - -constructor(private readonly db: Drizzle) {} - getVotingPowerVariations( startTimestamp: number | undefined, endTimestamp: number | undefined, diff --git a/apps/api/src/services/voting-power/voting-power.ts b/apps/api/src/services/voting-power/voting-power.ts index 1cb407c90..c2dd2d5b7 100644 --- a/apps/api/src/services/voting-power/voting-power.ts +++ b/apps/api/src/services/voting-power/voting-power.ts @@ -3,9 +3,6 @@ import { Address } from "viem"; import { DBVotingPowerVariation, DBAccountPower } from "@/mappers"; interface VotingPowerRepository { - -constructor(private readonly db: Drizzle) {} - getVotingPowers( accountId: Address, skip: number, @@ -20,9 +17,6 @@ constructor(private readonly db: Drizzle) {} } interface VotingPowerVariationRepository { - -constructor(private readonly db: Drizzle) {} - getVotingPowerChanges( startTimestamp: number, limit: number, diff --git a/package.json b/package.json index f39eefd4e..f16e1550e 100644 --- a/package.json +++ b/package.json @@ -6,9 +6,7 @@ "dashboard": "dotenv -- pnpm run --filter=@anticapture/dashboard", "indexer": "dotenv -- pnpm run --filter=@anticapture/indexer", "gateway": "dotenv -- pnpm run --filter=@anticapture/api-gateway", - "petition": "dotenv -- pnpm run --filter=@anticapture/petition", - "indexer-metrics": "dotenv -- pnpm run --filter=@anticapture/indexer-metrics", - "local-node": "dotenv -- pnpm run --filter=@anticapture/local-node", + "api": "dotenv -- pnpm run --filter=@anticapture/api", "client": "dotenv -- pnpm run --filter=@anticapture/graphql-client", "clean": "turbo clean && rm -rf node_modules .turbo .parcel-cache coverage *.log *.tsbuildinfo", "lint": "turbo lint", From 73c57db892a3d1097f2de2d2e872fe7e09e1d3a8 Mon Sep 17 00:00:00 2001 From: lucas picollo Date: Thu, 29 Jan 2026 12:20:32 -0300 Subject: [PATCH 03/16] fix: inject pg client into the repositories --- apps/api/drizzle.config.ts | 2 +- apps/api/src/controllers/last-update/index.ts | 5 ++- .../proposals/proposals-activity.ts | 4 +- .../src/controllers/proposals/proposals.ts | 2 +- .../src/controllers/token-metrics/index.ts | 4 +- apps/api/src/database/schema.ts | 10 ++++- apps/api/src/env.ts | 2 +- apps/api/src/index.ts | 40 +++++++++++-------- apps/api/src/lib/client.ts | 2 +- .../mappers/delegation-percentage/index.ts | 3 ++ .../delegation-percentage.service.test.ts | 38 +++++++----------- .../delegation-percentage.test.ts | 38 +++++++----------- .../delegation-percentage.ts | 25 ++++++++---- 13 files changed, 92 insertions(+), 83 deletions(-) diff --git a/apps/api/drizzle.config.ts b/apps/api/drizzle.config.ts index e38ddbb82..3f2152430 100644 --- a/apps/api/drizzle.config.ts +++ b/apps/api/drizzle.config.ts @@ -1,5 +1,5 @@ import { defineConfig } from "drizzle-kit"; export default defineConfig({ dialect: "postgresql", - schema: "./src/db", + schema: "./src/database/schema.ts", }); diff --git a/apps/api/src/controllers/last-update/index.ts b/apps/api/src/controllers/last-update/index.ts index d8bb0a69d..203b02054 100644 --- a/apps/api/src/controllers/last-update/index.ts +++ b/apps/api/src/controllers/last-update/index.ts @@ -2,9 +2,10 @@ import { OpenAPIHono as Hono, createRoute, z } from "@hono/zod-openapi"; import { ChartType } from "@/mappers/"; import { LastUpdateService } from "@/services"; import { LastUpdateRepositoryImpl } from "@/repositories"; +import { Drizzle } from "@/database"; -export function lastUpdate(app: Hono) { - const repository = new LastUpdateRepositoryImpl(); +export function lastUpdate(app: Hono, db: Drizzle) { + const repository = new LastUpdateRepositoryImpl(db); const service = new LastUpdateService(repository); app.openapi( createRoute({ diff --git a/apps/api/src/controllers/proposals/proposals-activity.ts b/apps/api/src/controllers/proposals/proposals-activity.ts index a651d14fd..a5bb6f3ed 100644 --- a/apps/api/src/controllers/proposals/proposals-activity.ts +++ b/apps/api/src/controllers/proposals/proposals-activity.ts @@ -3,14 +3,14 @@ import { getAddress, isAddress } from "viem"; import { DaoIdEnum } from "@/lib/enums"; import { ProposalsActivityService } from "@/services"; -import { ProposalsActivityRepository, VoteFilter } from "@/repositories/"; +import { DrizzleProposalsActivityRepository, VoteFilter } from "@/repositories/"; import { CONTRACT_ADDRESSES } from "@/lib/constants"; import { DAOClient } from "@/clients"; import { ProposalActivityResponseSchema } from "@/mappers"; export function proposalsActivity( app: Hono, - repository: ProposalsActivityRepository, + repository: DrizzleProposalsActivityRepository, daoId: DaoIdEnum, daoClient: DAOClient, ) { diff --git a/apps/api/src/controllers/proposals/proposals.ts b/apps/api/src/controllers/proposals/proposals.ts index 77e35e455..b7653b244 100644 --- a/apps/api/src/controllers/proposals/proposals.ts +++ b/apps/api/src/controllers/proposals/proposals.ts @@ -12,7 +12,7 @@ import { VotesRequestSchema, VotesResponseSchema, } from "@/mappers"; -import { DAOClient } from "@/interfaces"; +import { DAOClient } from "@/clients"; export function proposals( app: Hono, diff --git a/apps/api/src/controllers/token-metrics/index.ts b/apps/api/src/controllers/token-metrics/index.ts index 6ccdb2e20..ad7b3e305 100644 --- a/apps/api/src/controllers/token-metrics/index.ts +++ b/apps/api/src/controllers/token-metrics/index.ts @@ -5,7 +5,6 @@ import { TokenMetricsResponseSchema, toTokenMetricsApi, } from "@/mappers/token-metrics"; -import { metricTypeArray } from "@/lib/constants"; export function tokenMetrics(app: Hono, service: TokenMetricsService) { app.openapi( @@ -14,8 +13,7 @@ export function tokenMetrics(app: Hono, service: TokenMetricsService) { operationId: "tokenMetrics", path: "/token-metrics", summary: "Get token related metrics", - description: `Returns token related metrics for a single metric type. - Available types: ${metricTypeArray.join(", ")}`, + description: `Returns token related metrics for a single metric type.`, tags: ["metrics"], request: { query: TokenMetricsRequestSchema, diff --git a/apps/api/src/database/schema.ts b/apps/api/src/database/schema.ts index 0ba4f7de3..01fa67514 100644 --- a/apps/api/src/database/schema.ts +++ b/apps/api/src/database/schema.ts @@ -108,8 +108,14 @@ export const delegation = pgTable( (drizzle) => ({ transactionHash: drizzle.text("transaction_hash").notNull(), daoId: drizzle.text("dao_id").notNull(), - delegateAccountId: drizzle.text("delegate_account_id").notNull(), - delegatorAccountId: drizzle.text("delegator_account_id").notNull(), + delegateAccountId: drizzle + .text("delegate_account_id") + .$type
() + .notNull(), + delegatorAccountId: drizzle + .text("delegator_account_id") + .$type
() + .notNull(), delegatedValue: bigint({ mode: "bigint" }).notNull().default(0n), previousDelegate: drizzle.text("previous_delegate"), timestamp: bigint({ mode: "bigint" }).notNull(), diff --git a/apps/api/src/env.ts b/apps/api/src/env.ts index c366e5ea6..8a023bfe5 100644 --- a/apps/api/src/env.ts +++ b/apps/api/src/env.ts @@ -7,7 +7,7 @@ dotenv.config(); const envSchema = z.object({ RPC_URL: z.string(), - DATABASE_URL: z.string().optional(), + DATABASE_URL: z.string(), DAO_ID: z.nativeEnum(DaoIdEnum), CHAIN_ID: z.coerce.number(), diff --git a/apps/api/src/index.ts b/apps/api/src/index.ts index 1da2caa34..ec2111e60 100644 --- a/apps/api/src/index.ts +++ b/apps/api/src/index.ts @@ -1,6 +1,8 @@ import { OpenAPIHono as Hono } from "@hono/zod-openapi"; +import { drizzle } from "drizzle-orm/node-postgres"; import { logger } from "hono/logger"; +import * as schema from "@/database/schema"; import { fromZodError } from "zod-validation-error"; import { createPublicClient, http } from "viem"; @@ -110,6 +112,8 @@ if (!daoClient) { throw new Error(`Client not found for DAO ${env.DAO_ID}`); } +const pgClient = drizzle(env.DATABASE_URL, { schema }); + const daoConfig = CONTRACT_ADDRESSES[env.DAO_ID]; const { blockTime, tokenType } = daoConfig; const optimisticProposalType = @@ -117,23 +121,23 @@ const optimisticProposalType = ? daoConfig.optimisticProposalType : undefined; -const repo = new DrizzleRepository(); -const votingPowerRepo = new VotingPowerRepository(); -const proposalsRepo = new DrizzleProposalsActivityRepository(); -const transactionsRepo = new TransactionsRepository(); -const daoMetricsDayBucketRepo = new DaoMetricsDayBucketRepository(); +const repo = new DrizzleRepository(pgClient); +const votingPowerRepo = new VotingPowerRepository(pgClient); +const proposalsRepo = new DrizzleProposalsActivityRepository(pgClient); +const transactionsRepo = new TransactionsRepository(pgClient); +const daoMetricsDayBucketRepo = new DaoMetricsDayBucketRepository(pgClient); const delegationPercentageService = new DelegationPercentageService( daoMetricsDayBucketRepo, ); const tokenMetricsService = new TokenMetricsService(daoMetricsDayBucketRepo); -const balanceVariationsRepo = new BalanceVariationsRepository(); -const historicalBalancesRepo = new HistoricalBalanceRepository(); -const accountBalanceRepo = new AccountBalanceRepository(); -const accountInteractionRepo = new AccountInteractionsRepository(); +const balanceVariationsRepo = new BalanceVariationsRepository(pgClient); +const historicalBalancesRepo = new HistoricalBalanceRepository(pgClient); +const accountBalanceRepo = new AccountBalanceRepository(pgClient); +const accountInteractionRepo = new AccountInteractionsRepository(pgClient); const transactionsService = new TransactionsService(transactionsRepo); const votingPowerService = new VotingPowerService( env.DAO_ID === DaoIdEnum.NOUNS - ? new NounsVotingPowerRepository() + ? new NounsVotingPowerRepository(pgClient) : votingPowerRepo, votingPowerRepo, ); @@ -148,7 +152,7 @@ const accountBalanceService = new AccountBalanceService(accountBalanceRepo); const tokenPriceClient = env.DAO_ID === DaoIdEnum.NOUNS ? new NFTPriceService( - new NFTPriceRepository(), + new NFTPriceRepository(pgClient), env.COINGECKO_API_URL, env.COINGECKO_API_KEY, ) @@ -160,14 +164,16 @@ const tokenPriceClient = historicalDelegations( app, - new HistoricalDelegationsService(new HistoricalDelegationsRepository()), + new HistoricalDelegationsService( + new HistoricalDelegationsRepository(pgClient), + ), ); // TODO: add support to partial delegations at some point -delegations(app, new DelegationsService(new DelegationsRepository())); +delegations(app, new DelegationsService(new DelegationsRepository(pgClient))); const treasuryService = createTreasuryService( - new TreasuryRepository(), + new TreasuryRepository(pgClient), tokenPriceClient, parseTreasuryProviderConfig( env.TREASURY_DATA_PROVIDER_ID, @@ -182,7 +188,7 @@ tokenHistoricalData(app, tokenPriceClient); token( app, tokenPriceClient, - new TokenService(new TokenRepository()), + new TokenService(new TokenRepository(pgClient)), env.DAO_ID, ); @@ -197,7 +203,7 @@ proposals( ); historicalBalances(app, new HistoricalBalancesService(historicalBalancesRepo)); transactions(app, transactionsService); -lastUpdate(app); +lastUpdate(app, pgClient); delegationPercentage(app, delegationPercentageService); historicalVotingPower(app, votingPowerService); votingPowerVariations(app, votingPowerService); @@ -205,7 +211,7 @@ votingPowers(app, votingPowerService); accountBalanceVariations(app, balanceVariationsService); accountBalances(app, env.DAO_ID, accountBalanceService); accountInteractions(app, balanceVariationsService); -transfers(app, new TransfersService(new TransfersRepository())); +transfers(app, new TransfersService(new TransfersRepository(pgClient))); dao(app, daoService); docs(app); tokenMetrics(app, tokenMetricsService); diff --git a/apps/api/src/lib/client.ts b/apps/api/src/lib/client.ts index 1dabe39c4..5bc7beaa7 100644 --- a/apps/api/src/lib/client.ts +++ b/apps/api/src/lib/client.ts @@ -12,8 +12,8 @@ import { OPClient, GTCClient, Client as NounsClient, + DAOClient, } from "@/clients"; -import { DAOClient } from "@/interfaces"; export function getClient< TTransport extends Transport = Transport, diff --git a/apps/api/src/mappers/delegation-percentage/index.ts b/apps/api/src/mappers/delegation-percentage/index.ts index 31b4ace7e..7443f23b0 100644 --- a/apps/api/src/mappers/delegation-percentage/index.ts +++ b/apps/api/src/mappers/delegation-percentage/index.ts @@ -1,5 +1,8 @@ import { z } from "zod"; import { SECONDS_IN_DAY } from "@/lib/enums"; +import { daoMetricsDayBucket } from "@/database"; + +export type DBTokenMetric = typeof daoMetricsDayBucket.$inferSelect; // === ZOD SCHEMAS === diff --git a/apps/api/src/services/delegation-percentage/delegation-percentage.service.test.ts b/apps/api/src/services/delegation-percentage/delegation-percentage.service.test.ts index bfeb6cf79..cecf85ada 100644 --- a/apps/api/src/services/delegation-percentage/delegation-percentage.service.test.ts +++ b/apps/api/src/services/delegation-percentage/delegation-percentage.service.test.ts @@ -1,25 +1,7 @@ import { DelegationPercentageService } from "./delegation-percentage"; import { DaoMetricsDayBucketRepository } from "@/repositories/"; import { MetricTypesEnum } from "@/lib/constants"; - -/** - * Type representing a DAO metric row from the database - * Used for type-safe mocking in tests - */ -export type DaoMetricRow = { - date: bigint; - daoId: string; - tokenId: string; - metricType: string; - open: bigint; - close: bigint; - low: bigint; - high: bigint; - average: bigint; - volume: bigint; - count: number; - lastUpdate: bigint; -}; +import { DBTokenMetric } from "@/mappers/delegation-percentage"; /** * Mock Factory Pattern for type-safe test data @@ -27,8 +9,8 @@ export type DaoMetricRow = { * Only requires specifying fields relevant to each test case */ const createMockRow = ( - overwrites: Partial = {}, -): DaoMetricRow => ({ + overwrites: Partial = {}, +): DBTokenMetric => ({ date: 0n, daoId: "uniswap", tokenId: "uni", @@ -46,13 +28,23 @@ const createMockRow = ( describe("DelegationPercentageService", () => { let service: DelegationPercentageService; - let mockRepository: jest.Mocked; + let mockRepository: jest.Mocked< + Pick< + DaoMetricsDayBucketRepository, + "getMetricsByDateRange" | "getLastMetricBeforeDate" + > + >; beforeEach(() => { mockRepository = { getMetricsByDateRange: jest.fn(), getLastMetricBeforeDate: jest.fn(), - } as jest.Mocked; + } as jest.Mocked< + Pick< + DaoMetricsDayBucketRepository, + "getMetricsByDateRange" | "getLastMetricBeforeDate" + > + >; service = new DelegationPercentageService(mockRepository); }); diff --git a/apps/api/src/services/delegation-percentage/delegation-percentage.test.ts b/apps/api/src/services/delegation-percentage/delegation-percentage.test.ts index bfeb6cf79..cecf85ada 100644 --- a/apps/api/src/services/delegation-percentage/delegation-percentage.test.ts +++ b/apps/api/src/services/delegation-percentage/delegation-percentage.test.ts @@ -1,25 +1,7 @@ import { DelegationPercentageService } from "./delegation-percentage"; import { DaoMetricsDayBucketRepository } from "@/repositories/"; import { MetricTypesEnum } from "@/lib/constants"; - -/** - * Type representing a DAO metric row from the database - * Used for type-safe mocking in tests - */ -export type DaoMetricRow = { - date: bigint; - daoId: string; - tokenId: string; - metricType: string; - open: bigint; - close: bigint; - low: bigint; - high: bigint; - average: bigint; - volume: bigint; - count: number; - lastUpdate: bigint; -}; +import { DBTokenMetric } from "@/mappers/delegation-percentage"; /** * Mock Factory Pattern for type-safe test data @@ -27,8 +9,8 @@ export type DaoMetricRow = { * Only requires specifying fields relevant to each test case */ const createMockRow = ( - overwrites: Partial = {}, -): DaoMetricRow => ({ + overwrites: Partial = {}, +): DBTokenMetric => ({ date: 0n, daoId: "uniswap", tokenId: "uni", @@ -46,13 +28,23 @@ const createMockRow = ( describe("DelegationPercentageService", () => { let service: DelegationPercentageService; - let mockRepository: jest.Mocked; + let mockRepository: jest.Mocked< + Pick< + DaoMetricsDayBucketRepository, + "getMetricsByDateRange" | "getLastMetricBeforeDate" + > + >; beforeEach(() => { mockRepository = { getMetricsByDateRange: jest.fn(), getLastMetricBeforeDate: jest.fn(), - } as jest.Mocked; + } as jest.Mocked< + Pick< + DaoMetricsDayBucketRepository, + "getMetricsByDateRange" | "getLastMetricBeforeDate" + > + >; service = new DelegationPercentageService(mockRepository); }); diff --git a/apps/api/src/services/delegation-percentage/delegation-percentage.ts b/apps/api/src/services/delegation-percentage/delegation-percentage.ts index 2cb33f4ef..ea0f2d0c4 100644 --- a/apps/api/src/services/delegation-percentage/delegation-percentage.ts +++ b/apps/api/src/services/delegation-percentage/delegation-percentage.ts @@ -30,8 +30,8 @@ import { MetricTypesEnum } from "@/lib/constants"; import { forwardFill, generateOrderedTimeline } from "@/lib/time-series"; import { applyCursorPagination } from "@/lib/query-helpers"; import { getEffectiveStartDate } from "@/lib/date-helpers"; -import { DaoMetricsDayBucketRepository } from "@/repositories/"; import { + DBTokenMetric, DelegationPercentageItem, DelegationPercentageQuery, normalizeTimestamp, @@ -56,8 +56,23 @@ interface DateData { tokenId?: string; } +interface DelegationPercentageRepository { + getMetricsByDateRange(filters: { + metricTypes: string[]; + startDate?: string; + endDate?: string; + orderDirection: "asc" | "desc"; + limit: number; + }): Promise; + + getLastMetricBeforeDate( + metricType: string, + beforeDate: string, + ): Promise; +} + export class DelegationPercentageService { - constructor(private readonly repository: DaoMetricsDayBucketRepository) {} + constructor(private readonly repository: DelegationPercentageRepository) {} /** * Main method to get delegation percentage data with forward-fill and pagination @@ -190,11 +205,7 @@ export class DelegationPercentageService { * Organizes database rows into a map by date * Separates DELEGATED_SUPPLY and TOTAL_SUPPLY metrics */ - private organizeDateMap( - rows: Awaited< - ReturnType - >, - ): Map { + private organizeDateMap(rows: DBTokenMetric[]): Map { const dateMap = new Map(); rows.forEach((row) => { From 819945ec289532b39f2b8d648e86706b041014bc Mon Sep 17 00:00:00 2001 From: lucas picollo Date: Thu, 29 Jan 2026 12:56:32 -0300 Subject: [PATCH 04/16] fix: add hono server --- apps/api/package.json | 5 +- apps/api/src/index.ts | 11 +- apps/api/tsconfig.json | 4 +- apps/indexer/package.json | 14 +- pnpm-lock.yaml | 295 ++++++++++++++++++++++++++------------ 5 files changed, 224 insertions(+), 105 deletions(-) diff --git a/apps/api/package.json b/apps/api/package.json index 54359ae2b..978f15bf3 100644 --- a/apps/api/package.json +++ b/apps/api/package.json @@ -2,6 +2,7 @@ "name": "@anticapture/api", "version": "1.0.0", "main": "dist/index.js", + "type": "module", "scripts": { "typecheck": "tsc --noEmit", "test": "jest", @@ -10,13 +11,14 @@ "start": "node dist/index.js", "build": "tsc", "build:watch": "tsc --watch", - "dev": "tsc src/index.ts --watch" + "dev": "tsx src/index.ts" }, "keywords": [], "author": "", "license": "ISC", "description": "", "dependencies": { + "@hono/node-server": "^1.19.9", "@hono/zod-openapi": "^0.19.6", "axios": "^1.9.0", "drizzle-kit": "^0.31.4", @@ -38,6 +40,7 @@ "prettier": "^3.5.3", "ts-jest": "^29.4.1", "ts-node": "^10.9.2", + "tsx": "^4.21.0", "typescript": "^5.8.3" } } diff --git a/apps/api/src/index.ts b/apps/api/src/index.ts index ec2111e60..7d041d2e5 100644 --- a/apps/api/src/index.ts +++ b/apps/api/src/index.ts @@ -1,5 +1,6 @@ import { OpenAPIHono as Hono } from "@hono/zod-openapi"; import { drizzle } from "drizzle-orm/node-postgres"; +import { serve } from "@hono/node-server"; import { logger } from "hono/logger"; import * as schema from "@/database/schema"; @@ -216,4 +217,12 @@ dao(app, daoService); docs(app); tokenMetrics(app, tokenMetricsService); -export default app; +serve( + { + fetch: app.fetch, + port: env.PORT, + }, + (info) => { + console.log(`Server running at http://localhost:${info.port}`); + }, +); diff --git a/apps/api/tsconfig.json b/apps/api/tsconfig.json index d4a2eb8e0..8c76842ab 100644 --- a/apps/api/tsconfig.json +++ b/apps/api/tsconfig.json @@ -11,7 +11,6 @@ "allowImportingTsExtensions": true, "resolveJsonModule": true, // Language and environment - "moduleResolution": "bundler", "module": "ESNext", "noEmit": true, "lib": ["ES2022"], @@ -21,7 +20,8 @@ "paths": { "@/*": ["./src/*"] }, - "outDir": "./dist" + "outDir": "./dist", + "moduleResolution": "node" }, "include": ["./**/*.ts"], "exclude": ["node_modules", "test"] diff --git a/apps/indexer/package.json b/apps/indexer/package.json index 6bebce020..c586fd579 100644 --- a/apps/indexer/package.json +++ b/apps/indexer/package.json @@ -5,29 +5,19 @@ "scripts": { "dev": "ponder dev --schema public", "start": "ponder start --views-schema=anticapture --schema=$RAILWAY_DEPLOYMENT_ID", - "serve": "ponder serve --schema=anticapture", "db:list": "ponder db list", "db:prune": "ponder db prune", "lint": "eslint . --ext .ts", "lint:fix": "eslint . --ext .ts --fix", "typecheck": "tsc --noEmit", - "test": "jest", - "test:watch": "jest --watch", "clean": "rm -rf node_modules generated .ponder dump *.tsbuildinfo" }, "dependencies": { - "@hono/zod-openapi": "^0.19.6", - "axios": "^1.9.0", - "drizzle-kit": "^0.31.4", - "drizzle-orm": "~0.41.0", - "hono": "^4.7.10", "ponder": "^0.16.2", "viem": "^2.37.11", - "zod": "^3.25.3", - "zod-validation-error": "^3.4.1" + "zod": "^3.25.3" }, "devDependencies": { - "@types/jest": "^29.5.14", "@types/node": "^20.16.5", "@types/pg": "^8.15.6", "dotenv": "^16.5.0", @@ -35,9 +25,7 @@ "eslint-config-ponder": "^0.5.6", "eslint-config-prettier": "^9.1.0", "eslint-plugin-prettier": "^5.2.1", - "jest": "^29.7.0", "prettier": "^3.5.3", - "ts-jest": "^29.4.1", "ts-node": "^10.9.2", "typescript": "^5.8.3" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e89b0a193..407858081 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -33,7 +33,7 @@ importers: version: 9.1.2(eslint@9.39.2(jiti@2.6.1)) eslint-plugin-import: specifier: ^2.32.0 - version: 2.32.0(@typescript-eslint/parser@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1)) + version: 2.32.0(@typescript-eslint/parser@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.2(jiti@2.6.1)) eslint-plugin-prettier: specifier: ^5.2.1 version: 5.5.4(@types/eslint@9.6.1)(eslint-config-prettier@9.1.2(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1))(prettier@3.7.4) @@ -58,6 +58,9 @@ importers: apps/api: dependencies: + "@hono/node-server": + specifier: ^1.19.9 + version: 1.19.9(hono@4.10.7) "@hono/zod-openapi": specifier: ^0.19.6 version: 0.19.10(hono@4.10.7)(zod@3.25.76) @@ -112,10 +115,13 @@ importers: version: 3.7.4 ts-jest: specifier: ^29.4.1 - version: 29.4.6(@babel/core@7.28.5)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.5))(esbuild@0.25.8)(jest-util@29.7.0)(jest@29.7.0(@types/node@20.19.25)(ts-node@10.9.2(@types/node@20.19.25)(typescript@5.9.3)))(typescript@5.9.3) + version: 29.4.6(@babel/core@7.28.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.0))(esbuild@0.25.8)(jest-util@29.7.0)(jest@29.7.0(@types/node@20.19.25)(ts-node@10.9.2(@types/node@20.19.25)(typescript@5.9.3)))(typescript@5.9.3) ts-node: specifier: ^10.9.2 version: 10.9.2(@types/node@20.19.25)(typescript@5.9.3) + tsx: + specifier: ^4.21.0 + version: 4.21.0 typescript: specifier: ^5.8.3 version: 5.9.3 @@ -127,7 +133,7 @@ importers: version: 0.108.20(graphql@16.12.0) "@graphql-mesh/graphql": specifier: ^0.104.3 - version: 0.104.18(@types/node@20.19.25)(bufferutil@4.0.9)(crossws@0.3.5)(graphql@16.12.0)(utf-8-validate@5.0.10) + version: 0.104.18(@types/node@22.7.5)(bufferutil@4.0.9)(crossws@0.3.5)(graphql@16.12.0)(utf-8-validate@5.0.10) "@graphql-mesh/http": specifier: ^0.106.3 version: 0.106.18(graphql@16.12.0) @@ -161,10 +167,10 @@ importers: version: 29.5.14 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@20.19.25)(ts-node@10.9.2(@types/node@20.19.25)(typescript@5.9.3)) + version: 29.7.0(@types/node@22.7.5) ts-jest: specifier: ^29.4.1 - version: 29.4.6(@babel/core@7.28.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.0))(jest-util@29.7.0)(jest@29.7.0(@types/node@20.19.25)(ts-node@10.9.2(@types/node@20.19.25)(typescript@5.9.3)))(typescript@5.9.3) + version: 29.4.6(@babel/core@7.28.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.0))(jest-util@29.7.0)(jest@29.7.0(@types/node@22.7.5))(typescript@5.9.3) tsx: specifier: ^4.19.4 version: 4.21.0 @@ -179,7 +185,7 @@ importers: version: link:../../packages/graphql-client "@apollo/client": specifier: ^3.13.8 - version: 3.14.0(@types/react@19.2.8)(graphql-ws@6.0.6(crossws@0.3.5)(graphql@16.12.0)(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10)))(graphql@16.12.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + version: 3.14.0(@types/react@19.2.8)(graphql-ws@6.0.6(crossws@0.3.5)(graphql@16.12.0)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)))(graphql@16.12.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) "@ethersproject/providers": specifier: ^5.8.0 version: 5.8.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) @@ -215,7 +221,7 @@ importers: version: 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) "@rainbow-me/rainbowkit": specifier: ^2.2.0 - version: 2.2.9(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3)(viem@2.41.2(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76))(wagmi@2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.2.8)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(viem@2.41.2(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76))(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76)) + version: 2.2.9(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3)(viem@2.41.2(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76))(wagmi@2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.2.8)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(viem@2.41.2(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76))(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76)) "@snapshot-labs/snapshot.js": specifier: ^0.12.62 version: 0.12.65(bufferutil@4.0.9)(utf-8-validate@5.0.10) @@ -299,7 +305,7 @@ importers: version: 2.41.2(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76) wagmi: specifier: ^2.12.25 - version: 2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.2.8)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(viem@2.41.2(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76))(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76) + version: 2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.2.8)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(viem@2.41.2(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76))(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76) zod: specifier: ^3.25.76 version: 3.25.76 @@ -363,7 +369,7 @@ importers: version: 10.2.0(eslint@9.39.2(jiti@2.6.1))(storybook@10.2.0(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.7.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(utf-8-validate@5.0.10))(typescript@5.9.3) jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@20.19.25)(ts-node@10.9.2(@types/node@20.19.25)(typescript@5.9.3)) + version: 29.7.0(@types/node@20.19.25) playwright: specifier: ^1.52.0 version: 1.57.0 @@ -384,7 +390,7 @@ importers: version: 4.1.17 ts-jest: specifier: ^29.2.6 - version: 29.4.6(@babel/core@7.28.5)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.5))(esbuild@0.25.8)(jest-util@29.7.0)(jest@29.7.0(@types/node@20.19.25)(ts-node@10.9.2(@types/node@20.19.25)(typescript@5.9.3)))(typescript@5.9.3) + version: 29.4.6(@babel/core@7.28.5)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.5))(jest-util@29.7.0)(jest@29.7.0(@types/node@20.19.25))(typescript@5.9.3) tw-animate-css: specifier: ^1.3.0 version: 1.4.0 @@ -397,21 +403,6 @@ importers: apps/indexer: dependencies: - "@hono/zod-openapi": - specifier: ^0.19.6 - version: 0.19.10(hono@4.10.7)(zod@3.25.76) - axios: - specifier: ^1.9.0 - version: 1.13.2 - drizzle-kit: - specifier: ^0.31.4 - version: 0.31.7 - drizzle-orm: - specifier: ~0.41.0 - version: 0.41.0(@electric-sql/pglite@0.2.13)(@opentelemetry/api@1.9.0)(@types/pg@8.15.6)(kysely@0.26.3)(pg@8.16.3) - hono: - specifier: ^4.7.10 - version: 4.10.7 ponder: specifier: ^0.16.2 version: 0.16.2(@opentelemetry/api@1.9.0)(@types/node@20.19.25)(@types/pg@8.15.6)(bufferutil@4.0.9)(hono@4.10.7)(lightningcss@1.30.2)(terser@5.44.1)(typescript@5.9.3)(utf-8-validate@5.0.10)(viem@2.41.2(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76) @@ -421,13 +412,7 @@ importers: zod: specifier: ^3.25.3 version: 3.25.76 - zod-validation-error: - specifier: ^3.4.1 - version: 3.5.4(zod@3.25.76) devDependencies: - "@types/jest": - specifier: ^29.5.14 - version: 29.5.14 "@types/node": specifier: ^20.16.5 version: 20.19.25 @@ -449,15 +434,9 @@ importers: eslint-plugin-prettier: specifier: ^5.2.1 version: 5.5.4(@types/eslint@9.6.1)(eslint-config-prettier@9.1.2(eslint@8.57.1))(eslint@8.57.1)(prettier@3.7.4) - jest: - specifier: ^29.7.0 - version: 29.7.0(@types/node@20.19.25)(ts-node@10.9.2(@types/node@20.19.25)(typescript@5.9.3)) prettier: specifier: ^3.5.3 version: 3.7.4 - ts-jest: - specifier: ^29.4.1 - version: 29.4.6(@babel/core@7.28.5)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.5))(esbuild@0.25.8)(jest-util@29.7.0)(jest@29.7.0(@types/node@20.19.25)(ts-node@10.9.2(@types/node@20.19.25)(typescript@5.9.3)))(typescript@5.9.3) ts-node: specifier: ^10.9.2 version: 10.9.2(@types/node@20.19.25)(typescript@5.9.3) @@ -4380,6 +4359,15 @@ packages: peerDependencies: hono: ^4 + "@hono/node-server@1.19.9": + resolution: + { + integrity: sha512-vHL6w3ecZsky+8P5MD+eFfaGTyCeOHUIFYMGpQGbrBTSmNNoxv0if69rEZ5giu36weC5saFuznL411gRX7bJDw==, + } + engines: { node: ">=18.14.1" } + peerDependencies: + hono: ^4 + "@hono/zod-openapi@0.19.10": resolution: { @@ -18419,7 +18407,7 @@ snapshots: "@jridgewell/gen-mapping": 0.3.12 "@jridgewell/trace-mapping": 0.3.29 - "@apollo/client@3.14.0(@types/react@19.2.8)(graphql-ws@6.0.6(crossws@0.3.5)(graphql@16.12.0)(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10)))(graphql@16.12.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)": + "@apollo/client@3.14.0(@types/react@19.2.8)(graphql-ws@6.0.6(crossws@0.3.5)(graphql@16.12.0)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)))(graphql@16.12.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)": dependencies: "@graphql-typed-document-node/core": 3.2.0(graphql@16.12.0) "@wry/caches": 1.0.1 @@ -18436,7 +18424,7 @@ snapshots: tslib: 2.8.1 zen-observable-ts: 1.2.5 optionalDependencies: - graphql-ws: 6.0.6(crossws@0.3.5)(graphql@16.12.0)(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + graphql-ws: 6.0.6(crossws@0.3.5)(graphql@16.12.0)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) react: 19.2.3 react-dom: 19.2.3(react@19.2.3) transitivePeerDependencies: @@ -19705,9 +19693,9 @@ snapshots: "@babel/helper-string-parser": 7.27.1 "@babel/helper-validator-identifier": 7.28.5 - "@base-org/account@2.4.0(@types/react@19.2.8)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(utf-8-validate@5.0.10)(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76)": + "@base-org/account@2.4.0(@types/react@19.2.8)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(utf-8-validate@5.0.10)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76)": dependencies: - "@coinbase/cdp-sdk": 1.38.6(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@5.0.10)(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + "@coinbase/cdp-sdk": 1.38.6(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@5.0.10)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) "@noble/hashes": 1.4.0 clsx: 1.2.1 eventemitter3: 5.0.1 @@ -19744,11 +19732,11 @@ snapshots: - "@chromatic-com/cypress" - "@chromatic-com/playwright" - "@coinbase/cdp-sdk@1.38.6(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@5.0.10)(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))": + "@coinbase/cdp-sdk@1.38.6(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@5.0.10)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))": dependencies: - "@solana-program/system": 0.8.1(@solana/kit@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))) - "@solana-program/token": 0.6.0(@solana/kit@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))) - "@solana/kit": 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + "@solana-program/system": 0.8.1(@solana/kit@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))) + "@solana-program/token": 0.6.0(@solana/kit@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))) + "@solana/kit": 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) "@solana/web3.js": 1.98.4(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10) abitype: 1.0.6(typescript@5.9.3)(zod@3.25.76) axios: 1.13.2 @@ -21139,7 +21127,7 @@ snapshots: - ioredis - supports-color - "@graphql-mesh/graphql@0.104.18(@types/node@20.19.25)(bufferutil@4.0.9)(crossws@0.3.5)(graphql@16.12.0)(utf-8-validate@5.0.10)": + "@graphql-mesh/graphql@0.104.18(@types/node@22.7.5)(bufferutil@4.0.9)(crossws@0.3.5)(graphql@16.12.0)(utf-8-validate@5.0.10)": dependencies: "@graphql-mesh/cross-helpers": 0.4.10(graphql@16.12.0) "@graphql-mesh/store": 0.104.18(graphql@16.12.0) @@ -21147,9 +21135,9 @@ snapshots: "@graphql-mesh/types": 0.104.18(graphql@16.12.0) "@graphql-mesh/utils": 0.104.17(graphql@16.12.0) "@graphql-tools/delegate": 12.0.2(graphql@16.12.0) - "@graphql-tools/federation": 4.2.6(@types/node@20.19.25)(graphql@16.12.0) + "@graphql-tools/federation": 4.2.6(@types/node@22.7.5)(graphql@16.12.0) "@graphql-tools/merge": 9.1.1(graphql@16.12.0) - "@graphql-tools/url-loader": 9.0.5(@types/node@20.19.25)(bufferutil@4.0.9)(crossws@0.3.5)(graphql@16.12.0)(utf-8-validate@5.0.10) + "@graphql-tools/url-loader": 9.0.5(@types/node@22.7.5)(bufferutil@4.0.9)(crossws@0.3.5)(graphql@16.12.0)(utf-8-validate@5.0.10) "@graphql-tools/utils": 10.9.1(graphql@16.12.0) "@whatwg-node/promise-helpers": 1.3.2 graphql: 16.12.0 @@ -21558,7 +21546,7 @@ snapshots: transitivePeerDependencies: - "@types/node" - "@graphql-tools/executor-http@3.0.7(@types/node@20.19.25)(graphql@16.12.0)": + "@graphql-tools/executor-http@3.0.7(@types/node@22.7.5)(graphql@16.12.0)": dependencies: "@graphql-hive/signal": 2.0.0 "@graphql-tools/executor-common": 1.0.5(graphql@16.12.0) @@ -21568,7 +21556,7 @@ snapshots: "@whatwg-node/fetch": 0.10.13 "@whatwg-node/promise-helpers": 1.3.2 graphql: 16.12.0 - meros: 1.3.2(@types/node@20.19.25) + meros: 1.3.2(@types/node@22.7.5) tslib: 2.8.1 transitivePeerDependencies: - "@types/node" @@ -21627,11 +21615,11 @@ snapshots: graphql: 16.8.2 tslib: 2.8.1 - "@graphql-tools/federation@4.2.6(@types/node@20.19.25)(graphql@16.12.0)": + "@graphql-tools/federation@4.2.6(@types/node@22.7.5)(graphql@16.12.0)": dependencies: "@graphql-tools/delegate": 12.0.2(graphql@16.12.0) "@graphql-tools/executor": 1.5.0(graphql@16.12.0) - "@graphql-tools/executor-http": 3.0.7(@types/node@20.19.25)(graphql@16.12.0) + "@graphql-tools/executor-http": 3.0.7(@types/node@22.7.5)(graphql@16.12.0) "@graphql-tools/merge": 9.1.6(graphql@16.12.0) "@graphql-tools/schema": 10.0.30(graphql@16.12.0) "@graphql-tools/stitch": 10.1.6(graphql@16.12.0) @@ -21872,10 +21860,10 @@ snapshots: - uWebSockets.js - utf-8-validate - "@graphql-tools/url-loader@9.0.5(@types/node@20.19.25)(bufferutil@4.0.9)(crossws@0.3.5)(graphql@16.12.0)(utf-8-validate@5.0.10)": + "@graphql-tools/url-loader@9.0.5(@types/node@22.7.5)(bufferutil@4.0.9)(crossws@0.3.5)(graphql@16.12.0)(utf-8-validate@5.0.10)": dependencies: "@graphql-tools/executor-graphql-ws": 3.1.3(bufferutil@4.0.9)(crossws@0.3.5)(graphql@16.12.0)(utf-8-validate@5.0.10) - "@graphql-tools/executor-http": 3.0.7(@types/node@20.19.25)(graphql@16.12.0) + "@graphql-tools/executor-http": 3.0.7(@types/node@22.7.5)(graphql@16.12.0) "@graphql-tools/executor-legacy-ws": 1.1.24(bufferutil@4.0.9)(graphql@16.12.0)(utf-8-validate@5.0.10) "@graphql-tools/utils": 10.11.0(graphql@16.12.0) "@graphql-tools/wrap": 11.1.2(graphql@16.12.0) @@ -21978,6 +21966,10 @@ snapshots: dependencies: hono: 4.10.7 + "@hono/node-server@1.19.9(hono@4.10.7)": + dependencies: + hono: 4.10.7 + "@hono/zod-openapi@0.19.10(hono@4.10.7)(zod@3.25.76)": dependencies: "@asteasolutions/zod-to-openapi": 7.3.4(zod@3.25.76) @@ -23161,7 +23153,7 @@ snapshots: "@radix-ui/rect@1.1.1": {} - "@rainbow-me/rainbowkit@2.2.9(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3)(viem@2.41.2(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76))(wagmi@2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.2.8)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(viem@2.41.2(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76))(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76))": + "@rainbow-me/rainbowkit@2.2.9(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3)(viem@2.41.2(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76))(wagmi@2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.2.8)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(viem@2.41.2(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76))(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76))": dependencies: "@tanstack/react-query": 5.90.11(react@19.2.3) "@vanilla-extract/css": 1.17.3 @@ -23174,7 +23166,7 @@ snapshots: react-remove-scroll: 2.6.2(@types/react@19.2.8)(react@19.2.3) ua-parser-js: 1.0.40 viem: 2.41.2(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76) - wagmi: 2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.2.8)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(viem@2.41.2(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76))(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76) + wagmi: 2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.2.8)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(viem@2.41.2(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76))(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76) transitivePeerDependencies: - "@types/react" - babel-plugin-macros @@ -23607,13 +23599,13 @@ snapshots: "@socket.io/component-emitter@3.1.2": {} - "@solana-program/system@0.8.1(@solana/kit@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10)))": + "@solana-program/system@0.8.1(@solana/kit@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)))": dependencies: - "@solana/kit": 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + "@solana/kit": 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - "@solana-program/token@0.6.0(@solana/kit@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10)))": + "@solana-program/token@0.6.0(@solana/kit@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)))": dependencies: - "@solana/kit": 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + "@solana/kit": 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) "@solana/accounts@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)": dependencies: @@ -23743,7 +23735,7 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - "@solana/kit@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))": + "@solana/kit@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))": dependencies: "@solana/accounts": 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) "@solana/addresses": 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) @@ -23757,11 +23749,11 @@ snapshots: "@solana/rpc": 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) "@solana/rpc-parsed-types": 3.0.3(typescript@5.9.3) "@solana/rpc-spec-types": 3.0.3(typescript@5.9.3) - "@solana/rpc-subscriptions": 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + "@solana/rpc-subscriptions": 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) "@solana/rpc-types": 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) "@solana/signers": 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) "@solana/sysvars": 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) - "@solana/transaction-confirmation": 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + "@solana/transaction-confirmation": 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) "@solana/transaction-messages": 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) "@solana/transactions": 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) typescript: 5.9.3 @@ -23840,14 +23832,14 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - "@solana/rpc-subscriptions-channel-websocket@3.0.3(typescript@5.9.3)(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))": + "@solana/rpc-subscriptions-channel-websocket@3.0.3(typescript@5.9.3)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))": dependencies: "@solana/errors": 3.0.3(typescript@5.9.3) "@solana/functional": 3.0.3(typescript@5.9.3) "@solana/rpc-subscriptions-spec": 3.0.3(typescript@5.9.3) "@solana/subscribable": 3.0.3(typescript@5.9.3) typescript: 5.9.3 - ws: 7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10) + ws: 8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) "@solana/rpc-subscriptions-spec@3.0.3(typescript@5.9.3)": dependencies: @@ -23857,7 +23849,7 @@ snapshots: "@solana/subscribable": 3.0.3(typescript@5.9.3) typescript: 5.9.3 - "@solana/rpc-subscriptions@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))": + "@solana/rpc-subscriptions@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))": dependencies: "@solana/errors": 3.0.3(typescript@5.9.3) "@solana/fast-stable-stringify": 3.0.3(typescript@5.9.3) @@ -23865,7 +23857,7 @@ snapshots: "@solana/promises": 3.0.3(typescript@5.9.3) "@solana/rpc-spec-types": 3.0.3(typescript@5.9.3) "@solana/rpc-subscriptions-api": 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) - "@solana/rpc-subscriptions-channel-websocket": 3.0.3(typescript@5.9.3)(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + "@solana/rpc-subscriptions-channel-websocket": 3.0.3(typescript@5.9.3)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) "@solana/rpc-subscriptions-spec": 3.0.3(typescript@5.9.3) "@solana/rpc-transformers": 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) "@solana/rpc-types": 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) @@ -23950,7 +23942,7 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - "@solana/transaction-confirmation@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))": + "@solana/transaction-confirmation@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))": dependencies: "@solana/addresses": 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) "@solana/codecs-strings": 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) @@ -23958,7 +23950,7 @@ snapshots: "@solana/keys": 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) "@solana/promises": 3.0.3(typescript@5.9.3) "@solana/rpc": 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) - "@solana/rpc-subscriptions": 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + "@solana/rpc-subscriptions": 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) "@solana/rpc-types": 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) "@solana/transaction-messages": 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) "@solana/transactions": 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) @@ -24804,9 +24796,9 @@ snapshots: loupe: 3.1.4 tinyrainbow: 2.0.0 - "@wagmi/connectors@6.2.0(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.2.8)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.2.8)(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.41.2(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76)))(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(utf-8-validate@5.0.10)(viem@2.41.2(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76))(wagmi@2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.2.8)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(viem@2.41.2(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76))(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76))(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76)": + "@wagmi/connectors@6.2.0(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.2.8)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.2.8)(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.41.2(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76)))(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(utf-8-validate@5.0.10)(viem@2.41.2(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76))(wagmi@2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.2.8)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(viem@2.41.2(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76))(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76))(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76)": dependencies: - "@base-org/account": 2.4.0(@types/react@19.2.8)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(utf-8-validate@5.0.10)(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76) + "@base-org/account": 2.4.0(@types/react@19.2.8)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(utf-8-validate@5.0.10)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76) "@coinbase/wallet-sdk": 4.3.6(@types/react@19.2.8)(bufferutil@4.0.9)(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(utf-8-validate@5.0.10)(zod@3.25.76) "@gemini-wallet/core": 0.3.2(viem@2.41.2(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76)) "@metamask/sdk": 0.33.1(bufferutil@4.0.9)(utf-8-validate@5.0.10) @@ -24815,7 +24807,7 @@ snapshots: "@wagmi/core": 2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.2.8)(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.41.2(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76)) "@walletconnect/ethereum-provider": 2.21.1(@types/react@19.2.8)(bufferutil@4.0.9)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76) cbw-sdk: "@coinbase/wallet-sdk@3.9.3" - porto: 0.2.35(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.2.8)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.2.8)(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.41.2(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76)))(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.41.2(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76))(wagmi@2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.2.8)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(viem@2.41.2(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76))(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76)) + porto: 0.2.35(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.2.8)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.2.8)(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.41.2(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76)))(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.41.2(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76))(wagmi@2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.2.8)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(viem@2.41.2(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76))(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76)) viem: 2.41.2(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76) optionalDependencies: typescript: 5.9.3 @@ -26532,6 +26524,21 @@ snapshots: - supports-color - ts-node + create-jest@29.7.0(@types/node@22.7.5): + 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@22.7.5) + jest-util: 29.7.0 + prompts: 2.4.2 + transitivePeerDependencies: + - "@types/node" + - babel-plugin-macros + - supports-color + - ts-node + create-require@1.1.1: {} cross-fetch@3.2.0: @@ -27243,7 +27250,7 @@ snapshots: eslint: 9.39.2(jiti@2.6.1) eslint-import-resolver-node: 0.3.9 eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1)) - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.2(jiti@2.6.1)) eslint-plugin-jsx-a11y: 6.10.2(eslint@9.39.2(jiti@2.6.1)) eslint-plugin-react: 7.37.5(eslint@9.39.2(jiti@2.6.1)) eslint-plugin-react-hooks: 7.0.1(eslint@9.39.2(jiti@2.6.1)) @@ -27290,7 +27297,7 @@ snapshots: tinyglobby: 0.2.15 unrs-resolver: 1.11.1 optionalDependencies: - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.2(jiti@2.6.1)) transitivePeerDependencies: - supports-color @@ -27305,7 +27312,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1)): + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.2(jiti@2.6.1)): dependencies: "@rtsao/scc": 1.1.0 array-includes: 3.1.9 @@ -28082,12 +28089,12 @@ snapshots: dependencies: graphql: 16.12.0 - graphql-ws@6.0.6(crossws@0.3.5)(graphql@16.12.0)(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10)): + graphql-ws@6.0.6(crossws@0.3.5)(graphql@16.12.0)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)): dependencies: graphql: 16.12.0 optionalDependencies: crossws: 0.3.5 - ws: 7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10) + ws: 8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) optional: true graphql-ws@6.0.6(crossws@0.3.5)(graphql@16.12.0)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)): @@ -28688,6 +28695,25 @@ snapshots: - babel-plugin-macros - supports-color + jest-cli@29.7.0(@types/node@20.19.25): + dependencies: + "@jest/core": 29.7.0(ts-node@10.9.2(@types/node@20.19.25)(typescript@5.9.3)) + "@jest/test-result": 29.7.0 + "@jest/types": 29.6.3 + chalk: 4.1.2 + create-jest: 29.7.0(@types/node@20.19.25)(ts-node@10.9.2(@types/node@20.19.25)(typescript@5.9.3)) + exit: 0.1.2 + import-local: 3.2.0 + jest-config: 29.7.0(@types/node@20.19.25)(ts-node@10.9.2(@types/node@20.19.25)(typescript@5.9.3)) + 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.19.25)(ts-node@10.9.2(@types/node@20.19.25)(typescript@5.9.3)): dependencies: "@jest/core": 29.7.0(ts-node@10.9.2(@types/node@20.19.25)(typescript@5.9.3)) @@ -28707,6 +28733,25 @@ snapshots: - supports-color - ts-node + jest-cli@29.7.0(@types/node@22.7.5): + dependencies: + "@jest/core": 29.7.0(ts-node@10.9.2(@types/node@20.19.25)(typescript@5.9.3)) + "@jest/test-result": 29.7.0 + "@jest/types": 29.6.3 + chalk: 4.1.2 + create-jest: 29.7.0(@types/node@22.7.5) + exit: 0.1.2 + import-local: 3.2.0 + jest-config: 29.7.0(@types/node@22.7.5) + 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-config@29.7.0(@types/node@20.19.25)(ts-node@10.9.2(@types/node@20.19.25)(typescript@5.9.3)): dependencies: "@babel/core": 7.28.0 @@ -28738,6 +28783,36 @@ snapshots: - babel-plugin-macros - supports-color + jest-config@29.7.0(@types/node@22.7.5): + dependencies: + "@babel/core": 7.28.0 + "@jest/test-sequencer": 29.7.0 + "@jest/types": 29.6.3 + babel-jest: 29.7.0(@babel/core@7.28.0) + 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": 22.7.5 + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + jest-diff@29.7.0: dependencies: chalk: 4.1.2 @@ -28959,6 +29034,18 @@ snapshots: merge-stream: 2.0.0 supports-color: 8.1.1 + jest@29.7.0(@types/node@20.19.25): + dependencies: + "@jest/core": 29.7.0(ts-node@10.9.2(@types/node@20.19.25)(typescript@5.9.3)) + "@jest/types": 29.6.3 + import-local: 3.2.0 + jest-cli: 29.7.0(@types/node@20.19.25) + transitivePeerDependencies: + - "@types/node" + - babel-plugin-macros + - supports-color + - ts-node + jest@29.7.0(@types/node@20.19.25)(ts-node@10.9.2(@types/node@20.19.25)(typescript@5.9.3)): dependencies: "@jest/core": 29.7.0(ts-node@10.9.2(@types/node@20.19.25)(typescript@5.9.3)) @@ -28971,6 +29058,18 @@ snapshots: - supports-color - ts-node + jest@29.7.0(@types/node@22.7.5): + dependencies: + "@jest/core": 29.7.0(ts-node@10.9.2(@types/node@20.19.25)(typescript@5.9.3)) + "@jest/types": 29.6.3 + import-local: 3.2.0 + jest-cli: 29.7.0(@types/node@22.7.5) + transitivePeerDependencies: + - "@types/node" + - babel-plugin-macros + - supports-color + - ts-node + jiti@1.21.7: {} jiti@2.4.2: {} @@ -29394,9 +29493,9 @@ snapshots: optionalDependencies: "@types/node": 20.19.25 - meros@1.3.2(@types/node@20.19.25): + meros@1.3.2(@types/node@22.7.5): optionalDependencies: - "@types/node": 20.19.25 + "@types/node": 22.7.5 mersenne-twister@1.1.0: {} @@ -30139,7 +30238,7 @@ snapshots: pony-cause@2.1.11: {} - porto@0.2.35(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.2.8)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.2.8)(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.41.2(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76)))(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.41.2(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76))(wagmi@2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.2.8)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(viem@2.41.2(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76))(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76)): + porto@0.2.35(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.2.8)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.2.8)(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.41.2(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76)))(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.41.2(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76))(wagmi@2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.2.8)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(viem@2.41.2(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76))(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76)): dependencies: "@wagmi/core": 2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.2.8)(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.41.2(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76)) hono: 4.10.7 @@ -30153,7 +30252,7 @@ snapshots: "@tanstack/react-query": 5.90.11(react@19.2.3) react: 19.2.3 typescript: 5.9.3 - wagmi: 2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.2.8)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(viem@2.41.2(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76))(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76) + wagmi: 2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.2.8)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(viem@2.41.2(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76))(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76) transitivePeerDependencies: - "@types/react" - immer @@ -31478,7 +31577,7 @@ snapshots: dependencies: tslib: 2.8.1 - ts-jest@29.4.6(@babel/core@7.28.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.0))(jest-util@29.7.0)(jest@29.7.0(@types/node@20.19.25)(ts-node@10.9.2(@types/node@20.19.25)(typescript@5.9.3)))(typescript@5.9.3): + ts-jest@29.4.6(@babel/core@7.28.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.0))(esbuild@0.25.8)(jest-util@29.7.0)(jest@29.7.0(@types/node@20.19.25)(ts-node@10.9.2(@types/node@20.19.25)(typescript@5.9.3)))(typescript@5.9.3): dependencies: bs-logger: 0.2.6 fast-json-stable-stringify: 2.1.0 @@ -31496,14 +31595,35 @@ snapshots: "@jest/transform": 29.7.0 "@jest/types": 29.6.3 babel-jest: 29.7.0(@babel/core@7.28.0) + esbuild: 0.25.8 jest-util: 29.7.0 - ts-jest@29.4.6(@babel/core@7.28.5)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.5))(esbuild@0.25.8)(jest-util@29.7.0)(jest@29.7.0(@types/node@20.19.25)(ts-node@10.9.2(@types/node@20.19.25)(typescript@5.9.3)))(typescript@5.9.3): + ts-jest@29.4.6(@babel/core@7.28.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.0))(jest-util@29.7.0)(jest@29.7.0(@types/node@22.7.5))(typescript@5.9.3): dependencies: bs-logger: 0.2.6 fast-json-stable-stringify: 2.1.0 handlebars: 4.7.8 - jest: 29.7.0(@types/node@20.19.25)(ts-node@10.9.2(@types/node@20.19.25)(typescript@5.9.3)) + jest: 29.7.0(@types/node@22.7.5) + json5: 2.2.3 + lodash.memoize: 4.1.2 + make-error: 1.3.6 + semver: 7.7.3 + type-fest: 4.41.0 + typescript: 5.9.3 + yargs-parser: 21.1.1 + optionalDependencies: + "@babel/core": 7.28.0 + "@jest/transform": 29.7.0 + "@jest/types": 29.6.3 + babel-jest: 29.7.0(@babel/core@7.28.0) + jest-util: 29.7.0 + + ts-jest@29.4.6(@babel/core@7.28.5)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.5))(jest-util@29.7.0)(jest@29.7.0(@types/node@20.19.25))(typescript@5.9.3): + dependencies: + bs-logger: 0.2.6 + fast-json-stable-stringify: 2.1.0 + handlebars: 4.7.8 + jest: 29.7.0(@types/node@20.19.25) json5: 2.2.3 lodash.memoize: 4.1.2 make-error: 1.3.6 @@ -31516,7 +31636,6 @@ snapshots: "@jest/transform": 29.7.0 "@jest/types": 29.6.3 babel-jest: 29.7.0(@babel/core@7.28.5) - esbuild: 0.25.8 jest-util: 29.7.0 ts-log@2.2.7: {} @@ -31580,7 +31699,7 @@ snapshots: tsx@4.21.0: dependencies: esbuild: 0.27.1 - get-tsconfig: 4.10.1 + get-tsconfig: 4.13.0 optionalDependencies: fsevents: 2.3.3 @@ -32072,10 +32191,10 @@ snapshots: vm-browserify@1.1.2: {} - wagmi@2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.2.8)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(viem@2.41.2(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76))(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76): + wagmi@2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.2.8)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(viem@2.41.2(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76))(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76): dependencies: "@tanstack/react-query": 5.90.11(react@19.2.3) - "@wagmi/connectors": 6.2.0(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.2.8)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.2.8)(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.41.2(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76)))(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(utf-8-validate@5.0.10)(viem@2.41.2(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76))(wagmi@2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.2.8)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(viem@2.41.2(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76))(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76))(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76) + "@wagmi/connectors": 6.2.0(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.2.8)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.2.8)(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.41.2(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76)))(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(utf-8-validate@5.0.10)(viem@2.41.2(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76))(wagmi@2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.2.8)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(viem@2.41.2(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76))(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76))(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76) "@wagmi/core": 2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.2.8)(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.41.2(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76)) react: 19.2.3 use-sync-external-store: 1.4.0(react@19.2.3) From 313f8e2cc217a4894d66dc8767667a1cd4f94e1b Mon Sep 17 00:00:00 2001 From: lucas picollo Date: Thu, 29 Jan 2026 12:58:04 -0300 Subject: [PATCH 05/16] chore: move lib tests to api --- apps/{indexer/tests => api/src}/lib/date-helpers.test.ts | 0 apps/{indexer/tests => api/src}/lib/query-helpers.test.ts | 0 apps/{indexer/tests => api/src}/lib/time-series.test.ts | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename apps/{indexer/tests => api/src}/lib/date-helpers.test.ts (100%) rename apps/{indexer/tests => api/src}/lib/query-helpers.test.ts (100%) rename apps/{indexer/tests => api/src}/lib/time-series.test.ts (100%) diff --git a/apps/indexer/tests/lib/date-helpers.test.ts b/apps/api/src/lib/date-helpers.test.ts similarity index 100% rename from apps/indexer/tests/lib/date-helpers.test.ts rename to apps/api/src/lib/date-helpers.test.ts diff --git a/apps/indexer/tests/lib/query-helpers.test.ts b/apps/api/src/lib/query-helpers.test.ts similarity index 100% rename from apps/indexer/tests/lib/query-helpers.test.ts rename to apps/api/src/lib/query-helpers.test.ts diff --git a/apps/indexer/tests/lib/time-series.test.ts b/apps/api/src/lib/time-series.test.ts similarity index 100% rename from apps/indexer/tests/lib/time-series.test.ts rename to apps/api/src/lib/time-series.test.ts From 57164601efe1cc018e8ffe7ac24b91ef360da93e Mon Sep 17 00:00:00 2001 From: lucas picollo Date: Thu, 29 Jan 2026 13:00:00 -0300 Subject: [PATCH 06/16] chore: remove clients from indexer --- apps/indexer/src/indexer/comp/client.ts | 121 --------------------- apps/indexer/src/indexer/ens/client.ts | 117 -------------------- apps/indexer/src/indexer/governor.base.ts | 88 --------------- apps/indexer/src/indexer/gtc/client.ts | 121 --------------------- apps/indexer/src/indexer/nouns/client.ts | 125 ---------------------- apps/indexer/src/indexer/obol/client.ts | 117 -------------------- apps/indexer/src/indexer/scr/client.ts | 115 -------------------- apps/indexer/src/indexer/uni/client.ts | 115 -------------------- apps/indexer/src/indexer/zk/client.ts | 119 -------------------- 9 files changed, 1038 deletions(-) delete mode 100644 apps/indexer/src/indexer/comp/client.ts delete mode 100644 apps/indexer/src/indexer/ens/client.ts delete mode 100644 apps/indexer/src/indexer/governor.base.ts delete mode 100644 apps/indexer/src/indexer/gtc/client.ts delete mode 100644 apps/indexer/src/indexer/nouns/client.ts delete mode 100644 apps/indexer/src/indexer/obol/client.ts delete mode 100644 apps/indexer/src/indexer/scr/client.ts delete mode 100644 apps/indexer/src/indexer/uni/client.ts delete mode 100644 apps/indexer/src/indexer/zk/client.ts diff --git a/apps/indexer/src/indexer/comp/client.ts b/apps/indexer/src/indexer/comp/client.ts deleted file mode 100644 index 9aefa4b0b..000000000 --- a/apps/indexer/src/indexer/comp/client.ts +++ /dev/null @@ -1,121 +0,0 @@ -import { - Account, - Address, - Chain, - Client, - fromHex, - toHex, - Transport, -} from "viem"; - -import { DAOClient } from "@/interfaces/client"; -import { GovernorBase } from "../governor.base"; -import { COMPGovernorAbi } from "./abi"; -import { getBlockNumber, readContract } from "viem/actions"; - -export class COMPClient< - TTransport extends Transport = Transport, - TChain extends Chain = Chain, - TAccount extends Account | undefined = Account | undefined, - > - extends GovernorBase - implements DAOClient -{ - private abi: typeof COMPGovernorAbi; - private address: Address; - - constructor(client: Client, address: Address) { - super(client); - this.address = address; - this.abi = COMPGovernorAbi; - } - - getDaoId(): string { - return "COMP"; - } - - async getQuorum(): Promise { - const blockNumber = await getBlockNumber(this.client); - const targetBlock = blockNumber - 10n; - return readContract(this.client, { - abi: this.abi, - address: this.address, - functionName: "quorum", - args: [targetBlock < 0n ? 0n : targetBlock], - }); - } - - async getProposalThreshold(): Promise { - return readContract(this.client, { - abi: this.abi, - address: this.address, - functionName: "proposalThreshold", - }); - } - - async getVotingDelay(): Promise { - return readContract(this.client, { - abi: this.abi, - address: this.address, - functionName: "votingDelay", - }); - } - - async getVotingPeriod(): Promise { - return readContract(this.client, { - abi: this.abi, - address: this.address, - functionName: "votingPeriod", - }); - } - - async getTimelockDelay(): Promise { - const timelockAddress = await readContract(this.client, { - abi: this.abi, - address: this.address, - functionName: "timelock", - }); - return readContract(this.client, { - abi: [ - { - inputs: [], - name: "delay", - outputs: [ - { - internalType: "uint256", - name: "", - type: "uint256", - }, - ], - stateMutability: "view", - type: "function", - }, - ], - address: timelockAddress, - functionName: "delay", - }); - } - - async getCurrentBlockNumber(): Promise { - const result = await this.client.request({ - method: "eth_blockNumber", - }); - return fromHex(result, "number"); - } - - async getBlockTime(blockNumber: number): Promise { - const block = await this.client.request({ - method: "eth_getBlockByNumber", - params: [toHex(blockNumber), false], - }); - return block?.timestamp ? fromHex(block.timestamp, "number") : null; - } - - calculateQuorum(votes: { - forVotes: bigint; - againstVotes: bigint; - abstainVotes: bigint; - }): bigint { - return votes.forVotes; - } -} diff --git a/apps/indexer/src/indexer/ens/client.ts b/apps/indexer/src/indexer/ens/client.ts deleted file mode 100644 index 065355692..000000000 --- a/apps/indexer/src/indexer/ens/client.ts +++ /dev/null @@ -1,117 +0,0 @@ -import { - Account, - Address, - Chain, - Client, - fromHex, - toHex, - Transport, -} from "viem"; -import { getBlockNumber, readContract } from "viem/actions"; - -import { DAOClient } from "@/interfaces/client"; -import { ENSGovernorAbi } from "./abi"; -import { GovernorBase } from "../governor.base"; - -export class ENSClient< - TTransport extends Transport = Transport, - TChain extends Chain = Chain, - TAccount extends Account | undefined = Account | undefined, - > - extends GovernorBase - implements DAOClient -{ - private abi: typeof ENSGovernorAbi; - private address: Address; - - constructor(client: Client, address: Address) { - super(client); - this.address = address; - this.abi = ENSGovernorAbi; - } - - getDaoId(): string { - return "ENS"; - } - - async getQuorum(): Promise { - const blockNumber = await getBlockNumber(this.client); - const targetBlock = blockNumber - 10n; - return readContract(this.client, { - abi: this.abi, - address: this.address, - functionName: "quorum", - args: [targetBlock < 0n ? 0n : targetBlock], - }); - } - - async getProposalThreshold(): Promise { - return readContract(this.client, { - abi: this.abi, - address: this.address, - functionName: "proposalThreshold", - }); - } - - async getVotingDelay(): Promise { - return readContract(this.client, { - abi: this.abi, - address: this.address, - functionName: "votingDelay", - }); - } - - async getVotingPeriod(): Promise { - return readContract(this.client, { - abi: this.abi, - address: this.address, - functionName: "votingPeriod", - }); - } - - async getTimelockDelay(): Promise { - const timelockAddress = await readContract(this.client, { - abi: this.abi, - address: this.address, - functionName: "timelock", - }); - return readContract(this.client, { - abi: [ - { - constant: true, - inputs: [], - outputs: [{ internalType: "uint256", name: "", type: "uint256" }], - payable: false, - stateMutability: "view", - type: "function", - name: "getMinDelay", - }, - ], - address: timelockAddress, - functionName: "getMinDelay", - }); - } - - async getCurrentBlockNumber(): Promise { - const result = await this.client.request({ - method: "eth_blockNumber", - }); - return fromHex(result, "number"); - } - - async getBlockTime(blockNumber: number): Promise { - const block = await this.client.request({ - method: "eth_getBlockByNumber", - params: [toHex(blockNumber), false], - }); - return block?.timestamp ? fromHex(block.timestamp, "number") : null; - } - - calculateQuorum(votes: { - forVotes: bigint; - againstVotes: bigint; - abstainVotes: bigint; - }): bigint { - return votes.forVotes + votes.abstainVotes; - } -} diff --git a/apps/indexer/src/indexer/governor.base.ts b/apps/indexer/src/indexer/governor.base.ts deleted file mode 100644 index b170848a0..000000000 --- a/apps/indexer/src/indexer/governor.base.ts +++ /dev/null @@ -1,88 +0,0 @@ -import { Account, Chain, Client, Transport } from "viem"; - -import { DBProposal } from "../api/mappers"; -import { ProposalStatus } from "../lib/constants"; - -/** - * Base implementation for EVM Compound-based governance contracts. - * Provides common functionality for proposal status calculation - * not handled by the indexing process. - */ - -export abstract class GovernorBase< - TTransport extends Transport = Transport, - TChain extends Chain = Chain, - TAccount extends Account | undefined = Account | undefined, -> { - constructor(protected client: Client) {} - - abstract calculateQuorum(votes: { - forVotes: bigint; - againstVotes: bigint; - abstainVotes: bigint; - }): bigint; - - abstract getCurrentBlockNumber(): Promise; - - abstract getQuorum(proposalId: string | null): Promise; - - async getProposalStatus( - proposal: Pick< - DBProposal, - | "id" - | "status" - | "startBlock" - | "endBlock" - | "forVotes" - | "againstVotes" - | "abstainVotes" - >, - ): Promise { - const currentBlock = await this.getCurrentBlockNumber(); - - // Skip proposals already finalized via event - if ( - [ - ProposalStatus.CANCELED, - ProposalStatus.QUEUED, - ProposalStatus.EXECUTED, - ].includes(proposal.status as ProposalStatus) - ) { - return proposal.status; - } - - if (currentBlock < proposal.startBlock) { - return ProposalStatus.PENDING; - } - - if ( - currentBlock >= proposal.startBlock && - currentBlock < proposal.endBlock - ) { - return ProposalStatus.ACTIVE; - } - - // After voting period ends - if (currentBlock >= proposal.endBlock) { - const proposalQuorum = this.calculateQuorum({ - forVotes: proposal.forVotes, - againstVotes: proposal.againstVotes, - abstainVotes: proposal.abstainVotes, - }); - - const quorum = await this.getQuorum(proposal.id); - const voteSum = - proposal.forVotes + proposal.againstVotes + proposal.abstainVotes; - - const hasMajority = proposal.forVotes > proposal.againstVotes; - if (voteSum > quorum && !hasMajority) return ProposalStatus.DEFEATED; - - const hasQuorum = proposalQuorum >= quorum; - if (!hasQuorum) return ProposalStatus.NO_QUORUM; - - return ProposalStatus.SUCCEEDED; - } - - return proposal.status; - } -} diff --git a/apps/indexer/src/indexer/gtc/client.ts b/apps/indexer/src/indexer/gtc/client.ts deleted file mode 100644 index d7fc3f151..000000000 --- a/apps/indexer/src/indexer/gtc/client.ts +++ /dev/null @@ -1,121 +0,0 @@ -import { - Account, - Address, - Chain, - Client, - fromHex, - toHex, - Transport, -} from "viem"; -import { getBlockNumber, readContract } from "viem/actions"; - -import { DAOClient } from "@/interfaces/client"; -import { GovernorAbi } from "./abi/governor"; -import { GovernorBase } from "../governor.base"; - -export class GTCClient< - TTransport extends Transport = Transport, - TChain extends Chain = Chain, - TAccount extends Account | undefined = Account | undefined, - > - extends GovernorBase - implements DAOClient -{ - private abi: typeof GovernorAbi; - private address: Address; - - constructor(client: Client, address: Address) { - super(client); - this.address = address; - this.abi = GovernorAbi; - } - - getDaoId(): string { - return "GTC"; - } - - async getQuorum(): Promise { - const blockNumber = await getBlockNumber(this.client); - const targetBlock = blockNumber - 10n; - return readContract(this.client, { - abi: this.abi, - address: this.address, - functionName: "quorum", - args: [targetBlock < 0n ? 0n : targetBlock], - }); - } - - async getProposalThreshold(): Promise { - return readContract(this.client, { - abi: this.abi, - address: this.address, - functionName: "proposalThreshold", - }); - } - - async getVotingDelay(): Promise { - return readContract(this.client, { - abi: this.abi, - address: this.address, - functionName: "votingDelay", - }); - } - - async getVotingPeriod(): Promise { - return readContract(this.client, { - abi: this.abi, - address: this.address, - functionName: "votingPeriod", - }); - } - - async getTimelockDelay(): Promise { - const timelockAddress = await readContract(this.client, { - abi: this.abi, - address: this.address, - functionName: "timelock", - }); - return readContract(this.client, { - abi: [ - { - inputs: [], - name: "delay", - outputs: [ - { - internalType: "uint256", - name: "", - type: "uint256", - }, - ], - stateMutability: "view", - type: "function", - }, - ], - address: timelockAddress, - functionName: "delay", - }); - } - - async getCurrentBlockNumber(): Promise { - const result = await this.client.request({ - method: "eth_blockNumber", - }); - return fromHex(result, "number"); - } - - async getBlockTime(blockNumber: number): Promise { - const block = await this.client.request({ - method: "eth_getBlockByNumber", - params: [toHex(blockNumber), false], - }); - return block?.timestamp ? fromHex(block.timestamp, "number") : null; - } - - calculateQuorum(votes: { - forVotes: bigint; - againstVotes: bigint; - abstainVotes: bigint; - }): bigint { - return votes.forVotes + votes.abstainVotes; - } -} diff --git a/apps/indexer/src/indexer/nouns/client.ts b/apps/indexer/src/indexer/nouns/client.ts deleted file mode 100644 index 847eed160..000000000 --- a/apps/indexer/src/indexer/nouns/client.ts +++ /dev/null @@ -1,125 +0,0 @@ -import { - Account, - Address, - Chain, - Client as vClient, - fromHex, - toHex, - Transport, -} from "viem"; -import { readContract } from "viem/actions"; - -import { DAOClient } from "@/interfaces/client"; -import { GovernorAbi } from "./abi/governor"; -import { GovernorBase } from "../governor.base"; - -export class Client< - TTransport extends Transport = Transport, - TChain extends Chain = Chain, - TAccount extends Account | undefined = Account | undefined, - > - extends GovernorBase - implements DAOClient -{ - private abi: typeof GovernorAbi; - private address: Address; - - constructor(client: vClient, address: Address) { - super(client); - this.address = address; - this.abi = GovernorAbi; - } - - getDaoId(): string { - return "NOUNS"; - } - - async getQuorum(): Promise { - const lastProposalId = await readContract(this.client, { - abi: this.abi, - address: this.address, - functionName: "proposalCount", - }); - - return await readContract(this.client, { - abi: this.abi, - address: this.address, - functionName: "quorumVotes", - args: [lastProposalId], - }); - } - - async getProposalThreshold(): Promise { - return readContract(this.client, { - abi: this.abi, - address: this.address, - functionName: "proposalThreshold", - }); - } - - async getVotingDelay(): Promise { - return readContract(this.client, { - abi: this.abi, - address: this.address, - functionName: "votingDelay", - }); - } - - async getVotingPeriod(): Promise { - return readContract(this.client, { - abi: this.abi, - address: this.address, - functionName: "votingPeriod", - }); - } - - async getTimelockDelay(): Promise { - const timelockAddress = await readContract(this.client, { - abi: this.abi, - address: this.address, - functionName: "timelock", - }); - return readContract(this.client, { - abi: [ - { - inputs: [], - name: "delay", - outputs: [ - { - internalType: "uint256", - name: "", - type: "uint256", - }, - ], - stateMutability: "view", - type: "function", - }, - ], - address: timelockAddress, - functionName: "delay", - }); - } - - async getCurrentBlockNumber(): Promise { - const result = await this.client.request({ - method: "eth_blockNumber", - }); - return fromHex(result, "number"); - } - - async getBlockTime(blockNumber: number): Promise { - const block = await this.client.request({ - method: "eth_getBlockByNumber", - params: [toHex(blockNumber), false], - }); - return block?.timestamp ? fromHex(block.timestamp, "number") : null; - } - - calculateQuorum(votes: { - forVotes: bigint; - againstVotes: bigint; - abstainVotes: bigint; - }): bigint { - return votes.forVotes + votes.abstainVotes; - } -} diff --git a/apps/indexer/src/indexer/obol/client.ts b/apps/indexer/src/indexer/obol/client.ts deleted file mode 100644 index 4e54c803e..000000000 --- a/apps/indexer/src/indexer/obol/client.ts +++ /dev/null @@ -1,117 +0,0 @@ -import { - Account, - Address, - Chain, - Client, - fromHex, - toHex, - Transport, -} from "viem"; -import { getBlockNumber, readContract } from "viem/actions"; - -import { DAOClient } from "@/interfaces/client"; -import { ObolGovernorAbi } from "./abi"; -import { GovernorBase } from "../governor.base"; - -export class ObolClient< - TTransport extends Transport = Transport, - TChain extends Chain = Chain, - TAccount extends Account | undefined = Account | undefined, - > - extends GovernorBase - implements DAOClient -{ - private abi: typeof ObolGovernorAbi; - private address: Address; - - constructor(client: Client, address: Address) { - super(client); - this.address = address; - this.abi = ObolGovernorAbi; - } - - getDaoId(): string { - return "OBOL"; - } - - async getQuorum(): Promise { - const blockNumber = await getBlockNumber(this.client); - const targetBlock = blockNumber - 10n; - return readContract(this.client, { - abi: this.abi, - address: this.address, - functionName: "quorum", - args: [targetBlock < 0n ? 0n : targetBlock], - }); - } - - async getProposalThreshold(): Promise { - return readContract(this.client, { - abi: this.abi, - address: this.address, - functionName: "proposalThreshold", - }); - } - - async getVotingDelay(): Promise { - return readContract(this.client, { - abi: this.abi, - address: this.address, - functionName: "votingDelay", - }); - } - - async getVotingPeriod(): Promise { - return readContract(this.client, { - abi: this.abi, - address: this.address, - functionName: "votingPeriod", - }); - } - - async getTimelockDelay(): Promise { - const timelockAddress = await readContract(this.client, { - abi: this.abi, - address: this.address, - functionName: "timelock", - }); - return readContract(this.client, { - abi: [ - { - constant: true, - inputs: [], - outputs: [{ internalType: "uint256", name: "", type: "uint256" }], - payable: false, - stateMutability: "view", - type: "function", - name: "getMinDelay", - }, - ], - address: timelockAddress, - functionName: "getMinDelay", - }); - } - - async getCurrentBlockNumber(): Promise { - const result = await this.client.request({ - method: "eth_blockNumber", - }); - return fromHex(result, "number"); - } - - async getBlockTime(blockNumber: number): Promise { - const block = await this.client.request({ - method: "eth_getBlockByNumber", - params: [toHex(blockNumber), false], - }); - return block?.timestamp ? fromHex(block.timestamp, "number") : null; - } - - calculateQuorum(votes: { - forVotes: bigint; - againstVotes: bigint; - abstainVotes: bigint; - }): bigint { - return votes.forVotes + votes.abstainVotes; - } -} diff --git a/apps/indexer/src/indexer/scr/client.ts b/apps/indexer/src/indexer/scr/client.ts deleted file mode 100644 index aa72d6d5b..000000000 --- a/apps/indexer/src/indexer/scr/client.ts +++ /dev/null @@ -1,115 +0,0 @@ -import { - Account, - Address, - Chain, - Client, - fromHex, - parseEther, - toHex, - Transport, -} from "viem"; -import { readContract } from "viem/actions"; - -import { DAOClient } from "@/interfaces/client"; -import { GovernorAbi } from "./abi/governor"; -import { GovernorBase } from "../governor.base"; - -export class SCRClient< - TTransport extends Transport = Transport, - TChain extends Chain = Chain, - TAccount extends Account | undefined = Account | undefined, - > - extends GovernorBase - implements DAOClient -{ - private abi: typeof GovernorAbi; - private address: Address; - - constructor(client: Client, address: Address) { - super(client); - this.address = address; - this.abi = GovernorAbi; - } - - getDaoId(): string { - return "SCR"; - } - - async getQuorum(_: string | null): Promise { - return parseEther("2100000"); // 2.1M $SCR (0.21% Total Supply) - } - - async getProposalThreshold(): Promise { - return readContract(this.client, { - abi: this.abi, - address: this.address, - functionName: "proposalThreshold", - }); - } - - async getVotingDelay(): Promise { - return readContract(this.client, { - abi: this.abi, - address: this.address, - functionName: "votingDelay", - }); - } - - async getVotingPeriod(): Promise { - return readContract(this.client, { - abi: this.abi, - address: this.address, - functionName: "votingPeriod", - }); - } - - async getTimelockDelay(): Promise { - const timelockAddress = await readContract(this.client, { - abi: this.abi, - address: this.address, - functionName: "timelock", - }); - return readContract(this.client, { - abi: [ - { - inputs: [], - name: "getMinDelay", - outputs: [ - { - internalType: "uint256", - name: "duration", - type: "uint256", - }, - ], - stateMutability: "view", - type: "function", - }, - ], - address: timelockAddress, - functionName: "getMinDelay", - }); - } - - async getCurrentBlockNumber(): Promise { - const result = await this.client.request({ - method: "eth_blockNumber", - }); - return fromHex(result, "number"); - } - - async getBlockTime(blockNumber: number): Promise { - const block = await this.client.request({ - method: "eth_getBlockByNumber", - params: [toHex(blockNumber), false], - }); - return block?.timestamp ? fromHex(block.timestamp, "number") : null; - } - - calculateQuorum(votes: { - forVotes: bigint; - againstVotes: bigint; - abstainVotes: bigint; - }): bigint { - return votes.forVotes + votes.abstainVotes + votes.againstVotes; - } -} diff --git a/apps/indexer/src/indexer/uni/client.ts b/apps/indexer/src/indexer/uni/client.ts deleted file mode 100644 index f406bdc62..000000000 --- a/apps/indexer/src/indexer/uni/client.ts +++ /dev/null @@ -1,115 +0,0 @@ -import { - Account, - Address, - Chain, - Client, - fromHex, - toHex, - Transport, -} from "viem"; -import { readContract } from "viem/actions"; - -import { DAOClient } from "@/interfaces/client"; -import { GovernorAbi } from "./abi"; -import { GovernorBase } from "../governor.base"; - -export class UNIClient< - TTransport extends Transport = Transport, - TChain extends Chain = Chain, - TAccount extends Account | undefined = Account | undefined, - > - extends GovernorBase - implements DAOClient -{ - private abi: typeof GovernorAbi; - private address: Address; - - constructor(client: Client, address: Address) { - super(client); - this.address = address; - this.abi = GovernorAbi; - } - - getDaoId(): string { - return "UNI"; - } - - async getQuorum(): Promise { - return readContract(this.client, { - abi: this.abi, - address: this.address, - functionName: "quorumVotes", - args: [], - }); - } - - async getProposalThreshold(): Promise { - return readContract(this.client, { - abi: this.abi, - address: this.address, - functionName: "proposalThreshold", - }); - } - - async getVotingDelay(): Promise { - return readContract(this.client, { - abi: this.abi, - address: this.address, - functionName: "votingDelay", - }); - } - - async getVotingPeriod(): Promise { - return readContract(this.client, { - abi: this.abi, - address: this.address, - functionName: "votingPeriod", - }); - } - - async getTimelockDelay(): Promise { - const timelockAddress = await readContract(this.client, { - abi: this.abi, - address: this.address, - functionName: "timelock", - }); - return readContract(this.client, { - abi: [ - { - constant: true, - inputs: [], - outputs: [{ internalType: "uint256", name: "", type: "uint256" }], - payable: false, - stateMutability: "view", - type: "function", - name: "delay", - }, - ], - address: timelockAddress, - functionName: "delay", - }); - } - - async getCurrentBlockNumber(): Promise { - const result = await this.client.request({ - method: "eth_blockNumber", - }); - return fromHex(result, "number"); - } - - async getBlockTime(blockNumber: number): Promise { - const block = await this.client.request({ - method: "eth_getBlockByNumber", - params: [toHex(blockNumber), false], - }); - return block?.timestamp ? fromHex(block.timestamp, "number") : null; - } - - calculateQuorum(votes: { - forVotes: bigint; - againstVotes: bigint; - abstainVotes: bigint; - }): bigint { - return votes.forVotes; - } -} diff --git a/apps/indexer/src/indexer/zk/client.ts b/apps/indexer/src/indexer/zk/client.ts deleted file mode 100644 index e836f0664..000000000 --- a/apps/indexer/src/indexer/zk/client.ts +++ /dev/null @@ -1,119 +0,0 @@ -import { - Account, - Address, - Chain, - Client, - fromHex, - toHex, - Transport, -} from "viem"; - -import { DAOClient } from "@/interfaces/client"; -import { GovernorBase } from "../governor.base"; -import { GovernorAbi } from "./abi"; -import { readContract } from "viem/actions"; - -export class ZKClient< - TTransport extends Transport = Transport, - TChain extends Chain = Chain, - TAccount extends Account | undefined = Account | undefined, - > - extends GovernorBase - implements DAOClient -{ - private abi: typeof GovernorAbi; - private address: Address; - - constructor(client: Client, address: Address) { - super(client); - this.address = address; - this.abi = GovernorAbi; - } - - getDaoId(): string { - return "ZK"; - } - - async getQuorum(): Promise { - return readContract(this.client, { - abi: this.abi, - address: this.address, - functionName: "quorum", - args: [BigInt(Math.floor(Date.now() / 1000))], - }); - } - - async getProposalThreshold(): Promise { - return readContract(this.client, { - abi: this.abi, - address: this.address, - functionName: "proposalThreshold", - }); - } - - async getVotingDelay(): Promise { - return readContract(this.client, { - abi: this.abi, - address: this.address, - functionName: "votingDelay", - }); - } - - async getVotingPeriod(): Promise { - return readContract(this.client, { - abi: this.abi, - address: this.address, - functionName: "votingPeriod", - }); - } - - async getTimelockDelay(): Promise { - const timelockAddress = await readContract(this.client, { - abi: this.abi, - address: this.address, - functionName: "timelock", - }); - return readContract(this.client, { - abi: [ - { - inputs: [], - name: "getMinDelay", - outputs: [ - { - internalType: "uint256", - name: "", - type: "uint256", - }, - ], - stateMutability: "view", - type: "function", - }, - ], - address: timelockAddress, - functionName: "getMinDelay", - }); - } - - async getCurrentBlockNumber(): Promise { - const result = await this.client.request({ - method: "eth_blockNumber", - }); - return fromHex(result, "number"); - } - - async getBlockTime(blockNumber: number): Promise { - const block = await this.client.request({ - method: "eth_getBlockByNumber", - params: [toHex(blockNumber), false], - }); - return block?.timestamp ? fromHex(block.timestamp, "number") : null; - } - - calculateQuorum(votes: { - forVotes: bigint; - againstVotes: bigint; - abstainVotes: bigint; - }): bigint { - return votes.forVotes; - } -} From bb15573a6669d2ee3ec3d94fa73e93600b646ac4 Mon Sep 17 00:00:00 2001 From: lucas picollo Date: Thu, 29 Jan 2026 13:03:47 -0300 Subject: [PATCH 07/16] chore: remove clients from indexer --- apps/indexer/drizzle.config.ts | 10 --- apps/indexer/jest.config.js | 8 -- apps/indexer/src/indexer/comp/index.ts | 1 - apps/indexer/src/indexer/ens/index.ts | 2 +- apps/indexer/src/indexer/gtc/index.ts | 2 +- apps/indexer/src/indexer/nouns/index.ts | 2 +- apps/indexer/src/indexer/obol/index.ts | 2 +- apps/indexer/src/indexer/op/client.ts | 97 ------------------------- apps/indexer/src/indexer/op/index.ts | 2 +- apps/indexer/src/indexer/scr/index.ts | 1 - apps/indexer/src/indexer/uni/index.ts | 2 +- apps/indexer/src/indexer/zk/index.ts | 1 - apps/indexer/src/interfaces/client.ts | 29 -------- apps/indexer/src/interfaces/index.ts | 1 - apps/indexer/src/lib/client.ts | 68 ----------------- 15 files changed, 6 insertions(+), 222 deletions(-) delete mode 100644 apps/indexer/drizzle.config.ts delete mode 100644 apps/indexer/jest.config.js delete mode 100644 apps/indexer/src/indexer/op/client.ts delete mode 100644 apps/indexer/src/interfaces/client.ts delete mode 100644 apps/indexer/src/interfaces/index.ts delete mode 100644 apps/indexer/src/lib/client.ts diff --git a/apps/indexer/drizzle.config.ts b/apps/indexer/drizzle.config.ts deleted file mode 100644 index 55c1da10d..000000000 --- a/apps/indexer/drizzle.config.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { defineConfig } from "drizzle-kit"; - -export default defineConfig({ - out: "./src/offchain/migrations", - schema: "./src/offchain/offchain.schema.ts", - dialect: "postgresql", - dbCredentials: { - url: process.env.DATABASE_URL || "", - }, -}); diff --git a/apps/indexer/jest.config.js b/apps/indexer/jest.config.js deleted file mode 100644 index ba20b9b7c..000000000 --- a/apps/indexer/jest.config.js +++ /dev/null @@ -1,8 +0,0 @@ -module.exports = { - preset: "ts-jest", - testEnvironment: "node", - testMatch: ["**/*.test.ts"], - moduleNameMapper: { - "^@/(.*)$": "/src/$1", - }, -}; diff --git a/apps/indexer/src/indexer/comp/index.ts b/apps/indexer/src/indexer/comp/index.ts index d4486d14c..8349a814f 100644 --- a/apps/indexer/src/indexer/comp/index.ts +++ b/apps/indexer/src/indexer/comp/index.ts @@ -1,4 +1,3 @@ export * from "./abi"; export * from "./erc20"; export * from "./governor"; -export * from "./client"; diff --git a/apps/indexer/src/indexer/ens/index.ts b/apps/indexer/src/indexer/ens/index.ts index b9cbb4f18..324693e85 100644 --- a/apps/indexer/src/indexer/ens/index.ts +++ b/apps/indexer/src/indexer/ens/index.ts @@ -1,4 +1,4 @@ export * from "./abi"; -export * from "./client"; + export * from "./governor"; export * from "./erc20"; diff --git a/apps/indexer/src/indexer/gtc/index.ts b/apps/indexer/src/indexer/gtc/index.ts index b9cbb4f18..324693e85 100644 --- a/apps/indexer/src/indexer/gtc/index.ts +++ b/apps/indexer/src/indexer/gtc/index.ts @@ -1,4 +1,4 @@ export * from "./abi"; -export * from "./client"; + export * from "./governor"; export * from "./erc20"; diff --git a/apps/indexer/src/indexer/nouns/index.ts b/apps/indexer/src/indexer/nouns/index.ts index 41db0ce92..3a4e8df64 100644 --- a/apps/indexer/src/indexer/nouns/index.ts +++ b/apps/indexer/src/indexer/nouns/index.ts @@ -1,4 +1,4 @@ export * from "./abi"; -export * from "./client"; + export * from "./governor"; export * from "./token"; diff --git a/apps/indexer/src/indexer/obol/index.ts b/apps/indexer/src/indexer/obol/index.ts index b9cbb4f18..324693e85 100644 --- a/apps/indexer/src/indexer/obol/index.ts +++ b/apps/indexer/src/indexer/obol/index.ts @@ -1,4 +1,4 @@ export * from "./abi"; -export * from "./client"; + export * from "./governor"; export * from "./erc20"; diff --git a/apps/indexer/src/indexer/op/client.ts b/apps/indexer/src/indexer/op/client.ts deleted file mode 100644 index bd95930bf..000000000 --- a/apps/indexer/src/indexer/op/client.ts +++ /dev/null @@ -1,97 +0,0 @@ -import { - Account, - Address, - Chain, - Client, - fromHex, - toHex, - Transport, -} from "viem"; -import { readContract } from "viem/actions"; - -import { DAOClient } from "@/interfaces/client"; -import { GovernorAbi } from "./abi"; -import { GovernorBase } from "../governor.base"; - -export class OPClient< - TTransport extends Transport = Transport, - TChain extends Chain = Chain, - TAccount extends Account | undefined = Account | undefined, - > - extends GovernorBase - implements DAOClient -{ - private abi: typeof GovernorAbi; - private address: Address; - - constructor(client: Client, address: Address) { - super(client); - this.address = address; - this.abi = GovernorAbi; - } - - getDaoId(): string { - return "OP"; - } - - async getQuorum(proposalId: string | null): Promise { - if (!proposalId) return 0n; - return readContract(this.client, { - abi: this.abi, - address: this.address, - functionName: "quorum", - args: [BigInt(proposalId)], - }); - } - - async getProposalThreshold(): Promise { - return readContract(this.client, { - abi: this.abi, - address: this.address, - functionName: "proposalThreshold", - }); - } - - async getVotingDelay(): Promise { - return readContract(this.client, { - abi: this.abi, - address: this.address, - functionName: "votingDelay", - }); - } - - async getVotingPeriod(): Promise { - return readContract(this.client, { - abi: this.abi, - address: this.address, - functionName: "votingPeriod", - }); - } - - async getTimelockDelay(): Promise { - return 0n; - } - - async getCurrentBlockNumber(): Promise { - const result = await this.client.request({ - method: "eth_blockNumber", - }); - return fromHex(result, "number"); - } - - async getBlockTime(blockNumber: number): Promise { - const block = await this.client.request({ - method: "eth_getBlockByNumber", - params: [toHex(blockNumber), false], - }); - return block?.timestamp ? fromHex(block.timestamp, "number") : null; - } - - calculateQuorum(votes: { - forVotes: bigint; - againstVotes: bigint; - abstainVotes: bigint; - }): bigint { - return votes.forVotes + votes.againstVotes + votes.abstainVotes; - } -} diff --git a/apps/indexer/src/indexer/op/index.ts b/apps/indexer/src/indexer/op/index.ts index b9cbb4f18..324693e85 100644 --- a/apps/indexer/src/indexer/op/index.ts +++ b/apps/indexer/src/indexer/op/index.ts @@ -1,4 +1,4 @@ export * from "./abi"; -export * from "./client"; + export * from "./governor"; export * from "./erc20"; diff --git a/apps/indexer/src/indexer/scr/index.ts b/apps/indexer/src/indexer/scr/index.ts index bf1e9cbc1..f602654d8 100644 --- a/apps/indexer/src/indexer/scr/index.ts +++ b/apps/indexer/src/indexer/scr/index.ts @@ -1,4 +1,3 @@ export * from "./erc20"; export * from "./abi"; export * from "./governor"; -export * from "./client"; diff --git a/apps/indexer/src/indexer/uni/index.ts b/apps/indexer/src/indexer/uni/index.ts index b9cbb4f18..324693e85 100644 --- a/apps/indexer/src/indexer/uni/index.ts +++ b/apps/indexer/src/indexer/uni/index.ts @@ -1,4 +1,4 @@ export * from "./abi"; -export * from "./client"; + export * from "./governor"; export * from "./erc20"; diff --git a/apps/indexer/src/indexer/zk/index.ts b/apps/indexer/src/indexer/zk/index.ts index d4486d14c..8349a814f 100644 --- a/apps/indexer/src/indexer/zk/index.ts +++ b/apps/indexer/src/indexer/zk/index.ts @@ -1,4 +1,3 @@ export * from "./abi"; export * from "./erc20"; export * from "./governor"; -export * from "./client"; diff --git a/apps/indexer/src/interfaces/client.ts b/apps/indexer/src/interfaces/client.ts deleted file mode 100644 index 32d27b0f2..000000000 --- a/apps/indexer/src/interfaces/client.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { DBProposal } from "@/api/mappers"; - -export interface DAOClient { - getDaoId: () => string; - getVotingDelay: () => Promise; - getVotingPeriod: () => Promise; - getTimelockDelay: () => Promise; - getQuorum: (proposalId: string | null) => Promise; - getProposalThreshold: () => Promise; - getCurrentBlockNumber: () => Promise; - getBlockTime: (blockNumber: number) => Promise; - calculateQuorum: (votes: { - forVotes: bigint; - againstVotes: bigint; - abstainVotes: bigint; - }) => bigint; - getProposalStatus: ( - proposal: Pick< - DBProposal, - | "id" - | "status" - | "startBlock" - | "endBlock" - | "forVotes" - | "againstVotes" - | "abstainVotes" - >, - ) => Promise; -} diff --git a/apps/indexer/src/interfaces/index.ts b/apps/indexer/src/interfaces/index.ts deleted file mode 100644 index 5ec76921e..000000000 --- a/apps/indexer/src/interfaces/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./client"; diff --git a/apps/indexer/src/lib/client.ts b/apps/indexer/src/lib/client.ts deleted file mode 100644 index a2070d4bf..000000000 --- a/apps/indexer/src/lib/client.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { Chain, Account, Transport, Client } from "viem"; - -import { DaoIdEnum } from "./enums"; -import { CONTRACT_ADDRESSES } from "./constants"; -import { UNIClient } from "@/indexer/uni/client"; -import { ENSClient } from "@/indexer/ens/client"; -import { OPClient } from "@/indexer/op"; -import { DAOClient } from "@/interfaces/client"; -import { GTCClient } from "@/indexer/gtc/client"; -import { Client as NounsClient } from "@/indexer/nouns/client"; -import { SCRClient } from "@/indexer/scr"; -import { COMPClient } from "@/indexer/comp"; -import { ObolClient } from "@/indexer/obol/client"; -import { ZKClient } from "@/indexer/zk"; - -export function getClient< - TTransport extends Transport = Transport, - TChain extends Chain = Chain, - TAccount extends Account | undefined = Account | undefined, ->( - daoId: DaoIdEnum, - client: Client, -): DAOClient | null { - switch (daoId) { - case DaoIdEnum.ENS: { - const { governor } = CONTRACT_ADDRESSES[daoId]; - return new ENSClient(client, governor.address); - } - case DaoIdEnum.UNI: { - const { governor } = CONTRACT_ADDRESSES[daoId]; - return new UNIClient(client, governor.address); - } - case DaoIdEnum.OP: { - const { governor } = CONTRACT_ADDRESSES[daoId]; - return new OPClient(client, governor.address); - } - case DaoIdEnum.TEST: { - const { governor } = CONTRACT_ADDRESSES[daoId]; - return new ENSClient(client, governor.address); - } - case DaoIdEnum.GTC: { - const { governor } = CONTRACT_ADDRESSES[daoId]; - return new GTCClient(client, governor.address); - } - case DaoIdEnum.NOUNS: { - const { governor } = CONTRACT_ADDRESSES[daoId]; - return new NounsClient(client, governor.address); - } - case DaoIdEnum.SCR: { - const { governor } = CONTRACT_ADDRESSES[daoId]; - return new SCRClient(client, governor.address); - } - case DaoIdEnum.COMP: { - const { governor } = CONTRACT_ADDRESSES[daoId]; - return new COMPClient(client, governor.address); - } - case DaoIdEnum.OBOL: { - const { governor } = CONTRACT_ADDRESSES[daoId]; - return new ObolClient(client, governor.address); - } - case DaoIdEnum.ZK: { - const { governor } = CONTRACT_ADDRESSES[daoId]; - return new ZKClient(client, governor.address); - } - default: - return null; - } -} From b693cd257533c3f72daae8d6d5128fcfcd8ba6e2 Mon Sep 17 00:00:00 2001 From: lucas picollo Date: Thu, 29 Jan 2026 13:46:35 -0300 Subject: [PATCH 08/16] chore: build api with tsup --- apps/api/package.json | 4 +- apps/api/src/clients/zk/abi/index.ts | 4 +- apps/api/tsconfig.json | 6 - apps/api/tsup.config.ts | 13 ++ pnpm-lock.yaml | 196 ++++++++++++++++++++++++++- 5 files changed, 207 insertions(+), 16 deletions(-) create mode 100644 apps/api/tsup.config.ts diff --git a/apps/api/package.json b/apps/api/package.json index 978f15bf3..8a5b1763a 100644 --- a/apps/api/package.json +++ b/apps/api/package.json @@ -9,7 +9,7 @@ "test:watch": "jest --watch", "clean": "rm -rf node_modules *.tsbuildinfo dist", "start": "node dist/index.js", - "build": "tsc", + "build": "tsup", "build:watch": "tsc --watch", "dev": "tsx src/index.ts" }, @@ -39,7 +39,7 @@ "jest": "^29.7.0", "prettier": "^3.5.3", "ts-jest": "^29.4.1", - "ts-node": "^10.9.2", + "tsup": "^8.5.1", "tsx": "^4.21.0", "typescript": "^5.8.3" } diff --git a/apps/api/src/clients/zk/abi/index.ts b/apps/api/src/clients/zk/abi/index.ts index d49549a68..42f08dce0 100644 --- a/apps/api/src/clients/zk/abi/index.ts +++ b/apps/api/src/clients/zk/abi/index.ts @@ -1,2 +1,2 @@ -export * from "./token.ts"; -export * from "./governor.ts"; +export * from "./token"; +export * from "./governor"; diff --git a/apps/api/tsconfig.json b/apps/api/tsconfig.json index 8c76842ab..9306ab311 100644 --- a/apps/api/tsconfig.json +++ b/apps/api/tsconfig.json @@ -1,21 +1,15 @@ { "compilerOptions": { - // Type checking "strict": true, "noUncheckedIndexedAccess": true, - // Interop constraints "verbatimModuleSyntax": false, "esModuleInterop": true, "isolatedModules": true, "allowSyntheticDefaultImports": true, - "allowImportingTsExtensions": true, "resolveJsonModule": true, - // Language and environment "module": "ESNext", - "noEmit": true, "lib": ["ES2022"], "target": "ES2022", - // Skip type checking for node modules "skipLibCheck": true, "paths": { "@/*": ["./src/*"] diff --git a/apps/api/tsup.config.ts b/apps/api/tsup.config.ts new file mode 100644 index 000000000..041729575 --- /dev/null +++ b/apps/api/tsup.config.ts @@ -0,0 +1,13 @@ +import { defineConfig } from "tsup"; + +export default defineConfig({ + entry: ["src/index.ts"], + format: ["esm"], + target: "es2022", + outDir: "dist", + clean: true, + external: [ + /^[a-z]/i, // Bare imports like 'dotenv', 'hono' + /^@[a-z]/i, // Scoped packages like '@hono/node-server' + ], +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 407858081..046bfd5c9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -116,9 +116,9 @@ importers: ts-jest: specifier: ^29.4.1 version: 29.4.6(@babel/core@7.28.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.0))(esbuild@0.25.8)(jest-util@29.7.0)(jest@29.7.0(@types/node@20.19.25)(ts-node@10.9.2(@types/node@20.19.25)(typescript@5.9.3)))(typescript@5.9.3) - ts-node: - specifier: ^10.9.2 - version: 10.9.2(@types/node@20.19.25)(typescript@5.9.3) + tsup: + specifier: ^8.5.1 + version: 8.5.1(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2) tsx: specifier: ^4.21.0 version: 4.21.0 @@ -9027,6 +9027,15 @@ packages: } engines: { node: ">=18" } + bundle-require@5.1.0: + resolution: + { + integrity: sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA==, + } + engines: { node: ^12.20.0 || ^14.13.1 || >=16.0.0 } + peerDependencies: + esbuild: ">=0.18" + cac@6.7.14: resolution: { @@ -9451,6 +9460,19 @@ packages: } engines: { node: ">=18" } + confbox@0.1.8: + resolution: + { + integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==, + } + + consola@3.4.2: + resolution: + { + integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==, + } + engines: { node: ^14.18.0 || >=16.10.0 } + console-browserify@1.2.0: resolution: { @@ -11369,6 +11391,12 @@ packages: } engines: { node: ">=18" } + fix-dts-default-cjs-exports@1.0.1: + resolution: + { + integrity: sha512-pVIECanWFC61Hzl2+oOCtoJ3F17kglZC/6N94eRWycFgBH35hHx0Li604ZIzhseh97mf2p0cv7vVrOZGoqhlEg==, + } + flat-cache@3.2.0: resolution: { @@ -12963,6 +12991,13 @@ packages: integrity: sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ==, } + joycon@3.1.1: + resolution: + { + integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==, + } + engines: { node: ">=10" } + js-sha3@0.8.0: resolution: { @@ -13324,6 +13359,13 @@ packages: } engines: { node: ">= 12.0.0" } + lilconfig@3.1.3: + resolution: + { + integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==, + } + engines: { node: ">=14" } + lines-and-columns@1.2.4: resolution: { @@ -13375,6 +13417,13 @@ packages: integrity: sha512-DGVsqsOIHBww2DqnuZzW7QsuCdahp50ojuDaBPC7jUDRpYoH0z7kHBBYZewRzer75FwtrkmkKk7iOAwSaWdBmw==, } + load-tsconfig@0.2.5: + resolution: + { + integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==, + } + engines: { node: ^12.20.0 || ^14.13.1 || >=16.0.0 } + loader-runner@4.3.1: resolution: { @@ -13918,6 +13967,12 @@ packages: engines: { node: ">=10" } hasBin: true + mlly@1.8.0: + resolution: + { + integrity: sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==, + } + modern-ahocorasick@1.1.0: resolution: { @@ -14829,6 +14884,12 @@ packages: } engines: { node: ">=14.16" } + pkg-types@1.3.1: + resolution: + { + integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==, + } + playwright-core@1.57.0: resolution: { @@ -14923,6 +14984,27 @@ packages: } engines: { node: ">= 0.4" } + postcss-load-config@6.0.1: + resolution: + { + integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==, + } + engines: { node: ">= 18" } + peerDependencies: + jiti: ">=1.21.0" + postcss: ">=8.0.9" + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + jiti: + optional: true + postcss: + optional: true + tsx: + optional: true + yaml: + optional: true + postcss-loader@8.1.1: resolution: { @@ -16288,6 +16370,13 @@ packages: } engines: { node: ">= 8" } + source-map@0.7.6: + resolution: + { + integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==, + } + engines: { node: ">= 12" } + split-on-first@1.1.0: resolution: { @@ -17149,6 +17238,28 @@ packages: integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==, } + tsup@8.5.1: + resolution: + { + integrity: sha512-xtgkqwdhpKWr3tKPmCkvYmS9xnQK3m3XgxZHwSUjvfTjp7YfXe5tT3GgWi0F2N+ZSMsOeWeZFh7ZZFg5iPhing==, + } + engines: { node: ">=18" } + hasBin: true + peerDependencies: + "@microsoft/api-extractor": ^7.36.0 + "@swc/core": ^1 + postcss: ^8.4.12 + typescript: ">=4.5.0" + peerDependenciesMeta: + "@microsoft/api-extractor": + optional: true + "@swc/core": + optional: true + postcss: + optional: true + typescript: + optional: true + tsx@4.21.0: resolution: { @@ -18404,8 +18515,8 @@ snapshots: "@ampproject/remapping@2.3.0": dependencies: - "@jridgewell/gen-mapping": 0.3.12 - "@jridgewell/trace-mapping": 0.3.29 + "@jridgewell/gen-mapping": 0.3.13 + "@jridgewell/trace-mapping": 0.3.31 "@apollo/client@3.14.0(@types/react@19.2.8)(graphql-ws@6.0.6(crossws@0.3.5)(graphql@16.12.0)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)))(graphql@16.12.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)": dependencies: @@ -26181,6 +26292,11 @@ snapshots: dependencies: run-applescript: 7.1.0 + bundle-require@5.1.0(esbuild@0.27.1): + dependencies: + esbuild: 0.27.1 + load-tsconfig: 0.2.5 + cac@6.7.14: {} call-bind-apply-helpers@1.0.2: @@ -26410,6 +26526,10 @@ snapshots: semver: 7.7.3 uint8array-extras: 0.3.0 + confbox@0.1.8: {} + + consola@3.4.2: {} + console-browserify@1.2.0: {} constant-case@3.0.4: @@ -27804,6 +27924,12 @@ snapshots: path-exists: 5.0.0 unicorn-magic: 0.1.0 + fix-dts-default-cjs-exports@1.0.1: + dependencies: + magic-string: 0.30.21 + mlly: 1.8.0 + rollup: 4.45.1 + flat-cache@3.2.0: dependencies: flatted: 3.3.3 @@ -29080,6 +29206,8 @@ snapshots: jose@6.1.3: {} + joycon@3.1.1: {} + js-sha3@0.8.0: {} js-tokens@4.0.0: {} @@ -29259,6 +29387,8 @@ snapshots: lightningcss-win32-arm64-msvc: 1.30.2 lightningcss-win32-x64-msvc: 1.30.2 + lilconfig@3.1.3: {} + lines-and-columns@1.2.4: {} lint-staged@16.2.7: @@ -29307,6 +29437,8 @@ snapshots: lit-element: 4.2.1 lit-html: 3.3.1 + load-tsconfig@0.2.5: {} + loader-runner@4.3.1: {} loader-utils@2.0.4: @@ -29551,6 +29683,13 @@ snapshots: mkdirp@3.0.1: {} + mlly@1.8.0: + dependencies: + acorn: 8.15.0 + pathe: 2.0.3 + pkg-types: 1.3.1 + ufo: 1.6.1 + modern-ahocorasick@1.1.0: {} ms@2.1.2: {} @@ -30142,6 +30281,12 @@ snapshots: dependencies: find-up: 6.3.0 + pkg-types@1.3.1: + dependencies: + confbox: 0.1.8 + mlly: 1.8.0 + pathe: 2.0.3 + playwright-core@1.57.0: {} playwright@1.57.0: @@ -30260,6 +30405,15 @@ snapshots: possible-typed-array-names@1.1.0: {} + postcss-load-config@6.0.1(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(yaml@2.8.2): + dependencies: + lilconfig: 3.1.3 + optionalDependencies: + jiti: 2.6.1 + postcss: 8.5.6 + tsx: 4.21.0 + yaml: 2.8.2 + postcss-loader@8.1.1(postcss@8.5.6)(typescript@5.9.3)(webpack@5.103.0): dependencies: cosmiconfig: 9.0.0(typescript@5.9.3) @@ -31139,6 +31293,8 @@ snapshots: source-map@0.7.4: {} + source-map@0.7.6: {} + split-on-first@1.1.0: {} split2@4.2.0: {} @@ -31696,6 +31852,34 @@ snapshots: tslib@2.8.1: {} + tsup@8.5.1(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2): + dependencies: + bundle-require: 5.1.0(esbuild@0.27.1) + cac: 6.7.14 + chokidar: 4.0.3 + consola: 3.4.2 + debug: 4.4.3 + esbuild: 0.27.1 + fix-dts-default-cjs-exports: 1.0.1 + joycon: 3.1.1 + picocolors: 1.1.1 + postcss-load-config: 6.0.1(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(yaml@2.8.2) + resolve-from: 5.0.0 + rollup: 4.45.1 + source-map: 0.7.6 + sucrase: 3.35.1 + tinyexec: 0.3.2 + tinyglobby: 0.2.15 + tree-kill: 1.2.2 + optionalDependencies: + postcss: 8.5.6 + typescript: 5.9.3 + transitivePeerDependencies: + - jiti + - supports-color + - tsx + - yaml + tsx@4.21.0: dependencies: esbuild: 0.27.1 @@ -32137,7 +32321,7 @@ snapshots: picomatch: 4.0.3 postcss: 8.5.6 rollup: 4.45.1 - tinyglobby: 0.2.14 + tinyglobby: 0.2.15 optionalDependencies: "@types/node": 20.19.25 fsevents: 2.3.3 From 94a364e190d469b844a2f34d39df2ca9cf35f1cb Mon Sep 17 00:00:00 2001 From: lucas picollo Date: Thu, 29 Jan 2026 13:49:49 -0300 Subject: [PATCH 09/16] chore: add pg to api --- apps/api/package.json | 1 + pnpm-lock.yaml | 213 +++++++++++++++++++++++++++++++++--------- 2 files changed, 170 insertions(+), 44 deletions(-) diff --git a/apps/api/package.json b/apps/api/package.json index 8a5b1763a..aec49ea62 100644 --- a/apps/api/package.json +++ b/apps/api/package.json @@ -24,6 +24,7 @@ "drizzle-kit": "^0.31.4", "drizzle-orm": "~0.41.0", "hono": "^4.7.10", + "pg": "^8.17.2", "viem": "^2.41.2", "zod": "^3.25.3", "zod-validation-error": "^3.4.1" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 046bfd5c9..0ba72af51 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -72,10 +72,13 @@ importers: version: 0.31.7 drizzle-orm: specifier: ~0.41.0 - version: 0.41.0(@electric-sql/pglite@0.2.13)(@opentelemetry/api@1.9.0)(@types/pg@8.15.6)(kysely@0.26.3)(pg@8.16.3) + version: 0.41.0(@electric-sql/pglite@0.2.13)(@opentelemetry/api@1.9.0)(@types/pg@8.15.6)(kysely@0.26.3)(pg@8.17.2) hono: specifier: ^4.7.10 version: 4.10.7 + pg: + specifier: ^8.17.2 + version: 8.17.2 viem: specifier: ^2.41.2 version: 2.41.2(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76) @@ -167,10 +170,10 @@ importers: version: 29.5.14 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@22.7.5) + version: 29.7.0(@types/node@22.7.5)(ts-node@10.9.2(@types/node@22.7.5)(typescript@5.9.3)) ts-jest: specifier: ^29.4.1 - version: 29.4.6(@babel/core@7.28.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.0))(jest-util@29.7.0)(jest@29.7.0(@types/node@22.7.5))(typescript@5.9.3) + version: 29.4.6(@babel/core@7.28.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.0))(jest-util@29.7.0)(jest@29.7.0(@types/node@22.7.5)(ts-node@10.9.2(@types/node@22.7.5)(typescript@5.9.3)))(typescript@5.9.3) tsx: specifier: ^4.19.4 version: 4.21.0 @@ -369,7 +372,7 @@ importers: version: 10.2.0(eslint@9.39.2(jiti@2.6.1))(storybook@10.2.0(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.7.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(utf-8-validate@5.0.10))(typescript@5.9.3) jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@20.19.25) + version: 29.7.0(@types/node@20.19.25)(ts-node@10.9.2(@types/node@20.19.25)(typescript@5.9.3)) playwright: specifier: ^1.52.0 version: 1.57.0 @@ -390,7 +393,7 @@ importers: version: 4.1.17 ts-jest: specifier: ^29.2.6 - version: 29.4.6(@babel/core@7.28.5)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.5))(jest-util@29.7.0)(jest@29.7.0(@types/node@20.19.25))(typescript@5.9.3) + version: 29.4.6(@babel/core@7.28.5)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.5))(jest-util@29.7.0)(jest@29.7.0(@types/node@20.19.25)(ts-node@10.9.2(@types/node@20.19.25)(typescript@5.9.3)))(typescript@5.9.3) tw-animate-css: specifier: ^1.3.0 version: 1.4.0 @@ -14719,6 +14722,18 @@ packages: integrity: sha512-YgCtzMH0ptvZJslLM1ffsY4EuGaU0cx4XSdXLRFae8bPP4dS5xL1tNB3k2o/N64cHJpwU7dxKli/nZ2lUa5fLg==, } + pg-cloudflare@1.3.0: + resolution: + { + integrity: sha512-6lswVVSztmHiRtD6I8hw4qP/nDm1EJbKMRhf3HCYaqud7frGysPv7FYJ5noZQdhQtN2xJnimfMtvQq21pdbzyQ==, + } + + pg-connection-string@2.10.1: + resolution: + { + integrity: sha512-iNzslsoeSH2/gmDDKiyMqF64DATUCWj3YJ0wP14kqcsf2TUklwimd+66yYojKwZCA7h2yRNLGug71hCBA2a4sw==, + } + pg-connection-string@2.9.1: resolution: { @@ -14746,12 +14761,26 @@ packages: peerDependencies: pg: ">=8.0" + pg-pool@3.11.0: + resolution: + { + integrity: sha512-MJYfvHwtGp870aeusDh+hg9apvOe2zmpZJpyt+BMtzUWlVqbhFmMK6bOBXLBUPd7iRtIF9fZplDc7KrPN3PN7w==, + } + peerDependencies: + pg: ">=8.0" + pg-protocol@1.10.3: resolution: { integrity: sha512-6DIBgBQaTKDJyxnXaLiLR8wBpQQcGWuAESkRBX/t6OwA8YsqP+iVSiond2EDy6Y/dsGk8rh/jtax3js5NeV7JQ==, } + pg-protocol@1.11.0: + resolution: + { + integrity: sha512-pfsxk2M9M3BuGgDOfuy37VNRRX3jmKgMjcvAcWqNDpZSf4cUmv8HSOl5ViRQFsfARFn0KuUQTgLxVMbNq5NW3g==, + } + pg-query-emscripten@5.1.0: resolution: { @@ -14777,6 +14806,18 @@ packages: pg-native: optional: true + pg@8.17.2: + resolution: + { + integrity: sha512-vjbKdiBJRqzcYw1fNU5KuHyYvdJ1qpcQg1CeBrHFqV1pWgHeVR6j/+kX0E1AAXfyuLUGY1ICrN2ELKA/z2HWzw==, + } + engines: { node: ">= 16.0.0" } + peerDependencies: + pg-native: ">=3.0.1" + peerDependenciesMeta: + pg-native: + optional: true + pgpass@1.0.5: resolution: { @@ -22286,6 +22327,41 @@ snapshots: - supports-color - ts-node + "@jest/core@29.7.0(ts-node@10.9.2(@types/node@22.7.5)(typescript@5.9.3))": + 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.19.25 + 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.19.25)(ts-node@10.9.2(@types/node@22.7.5)(typescript@5.9.3)) + 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/environment@29.7.0": dependencies: "@jest/fake-timers": 29.7.0 @@ -26644,13 +26720,13 @@ snapshots: - supports-color - ts-node - create-jest@29.7.0(@types/node@22.7.5): + create-jest@29.7.0(@types/node@22.7.5)(ts-node@10.9.2(@types/node@22.7.5)(typescript@5.9.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@22.7.5) + jest-config: 29.7.0(@types/node@22.7.5)(ts-node@10.9.2(@types/node@22.7.5)(typescript@5.9.3)) jest-util: 29.7.0 prompts: 2.4.2 transitivePeerDependencies: @@ -27034,6 +27110,14 @@ snapshots: kysely: 0.26.3 pg: 8.16.3 + drizzle-orm@0.41.0(@electric-sql/pglite@0.2.13)(@opentelemetry/api@1.9.0)(@types/pg@8.15.6)(kysely@0.26.3)(pg@8.17.2): + optionalDependencies: + "@electric-sql/pglite": 0.2.13 + "@opentelemetry/api": 1.9.0 + "@types/pg": 8.15.6 + kysely: 0.26.3 + pg: 8.17.2 + dset@3.1.4: {} dunder-proto@1.0.1: @@ -28821,7 +28905,7 @@ snapshots: - babel-plugin-macros - supports-color - jest-cli@29.7.0(@types/node@20.19.25): + jest-cli@29.7.0(@types/node@20.19.25)(ts-node@10.9.2(@types/node@20.19.25)(typescript@5.9.3)): dependencies: "@jest/core": 29.7.0(ts-node@10.9.2(@types/node@20.19.25)(typescript@5.9.3)) "@jest/test-result": 29.7.0 @@ -28840,16 +28924,16 @@ snapshots: - supports-color - ts-node - jest-cli@29.7.0(@types/node@20.19.25)(ts-node@10.9.2(@types/node@20.19.25)(typescript@5.9.3)): + jest-cli@29.7.0(@types/node@22.7.5)(ts-node@10.9.2(@types/node@22.7.5)(typescript@5.9.3)): dependencies: - "@jest/core": 29.7.0(ts-node@10.9.2(@types/node@20.19.25)(typescript@5.9.3)) + "@jest/core": 29.7.0(ts-node@10.9.2(@types/node@22.7.5)(typescript@5.9.3)) "@jest/test-result": 29.7.0 "@jest/types": 29.6.3 chalk: 4.1.2 - create-jest: 29.7.0(@types/node@20.19.25)(ts-node@10.9.2(@types/node@20.19.25)(typescript@5.9.3)) + create-jest: 29.7.0(@types/node@22.7.5)(ts-node@10.9.2(@types/node@22.7.5)(typescript@5.9.3)) exit: 0.1.2 import-local: 3.2.0 - jest-config: 29.7.0(@types/node@20.19.25)(ts-node@10.9.2(@types/node@20.19.25)(typescript@5.9.3)) + jest-config: 29.7.0(@types/node@22.7.5)(ts-node@10.9.2(@types/node@22.7.5)(typescript@5.9.3)) jest-util: 29.7.0 jest-validate: 29.7.0 yargs: 17.7.2 @@ -28859,26 +28943,38 @@ snapshots: - supports-color - ts-node - jest-cli@29.7.0(@types/node@22.7.5): + jest-config@29.7.0(@types/node@20.19.25)(ts-node@10.9.2(@types/node@20.19.25)(typescript@5.9.3)): dependencies: - "@jest/core": 29.7.0(ts-node@10.9.2(@types/node@20.19.25)(typescript@5.9.3)) - "@jest/test-result": 29.7.0 + "@babel/core": 7.28.0 + "@jest/test-sequencer": 29.7.0 "@jest/types": 29.6.3 + babel-jest: 29.7.0(@babel/core@7.28.0) chalk: 4.1.2 - create-jest: 29.7.0(@types/node@22.7.5) - exit: 0.1.2 - import-local: 3.2.0 - jest-config: 29.7.0(@types/node@22.7.5) + 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 - yargs: 17.7.2 + 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.19.25 + ts-node: 10.9.2(@types/node@20.19.25)(typescript@5.9.3) transitivePeerDependencies: - - "@types/node" - babel-plugin-macros - supports-color - - ts-node - jest-config@29.7.0(@types/node@20.19.25)(ts-node@10.9.2(@types/node@20.19.25)(typescript@5.9.3)): + jest-config@29.7.0(@types/node@20.19.25)(ts-node@10.9.2(@types/node@22.7.5)(typescript@5.9.3)): dependencies: "@babel/core": 7.28.0 "@jest/test-sequencer": 29.7.0 @@ -28904,12 +29000,12 @@ snapshots: strip-json-comments: 3.1.1 optionalDependencies: "@types/node": 20.19.25 - ts-node: 10.9.2(@types/node@20.19.25)(typescript@5.9.3) + ts-node: 10.9.2(@types/node@22.7.5)(typescript@5.9.3) transitivePeerDependencies: - babel-plugin-macros - supports-color - jest-config@29.7.0(@types/node@22.7.5): + jest-config@29.7.0(@types/node@22.7.5)(ts-node@10.9.2(@types/node@22.7.5)(typescript@5.9.3)): dependencies: "@babel/core": 7.28.0 "@jest/test-sequencer": 29.7.0 @@ -28935,6 +29031,7 @@ snapshots: strip-json-comments: 3.1.1 optionalDependencies: "@types/node": 22.7.5 + ts-node: 10.9.2(@types/node@22.7.5)(typescript@5.9.3) transitivePeerDependencies: - babel-plugin-macros - supports-color @@ -29160,18 +29257,6 @@ snapshots: merge-stream: 2.0.0 supports-color: 8.1.1 - jest@29.7.0(@types/node@20.19.25): - dependencies: - "@jest/core": 29.7.0(ts-node@10.9.2(@types/node@20.19.25)(typescript@5.9.3)) - "@jest/types": 29.6.3 - import-local: 3.2.0 - jest-cli: 29.7.0(@types/node@20.19.25) - transitivePeerDependencies: - - "@types/node" - - babel-plugin-macros - - supports-color - - ts-node - jest@29.7.0(@types/node@20.19.25)(ts-node@10.9.2(@types/node@20.19.25)(typescript@5.9.3)): dependencies: "@jest/core": 29.7.0(ts-node@10.9.2(@types/node@20.19.25)(typescript@5.9.3)) @@ -29184,12 +29269,12 @@ snapshots: - supports-color - ts-node - jest@29.7.0(@types/node@22.7.5): + jest@29.7.0(@types/node@22.7.5)(ts-node@10.9.2(@types/node@22.7.5)(typescript@5.9.3)): dependencies: - "@jest/core": 29.7.0(ts-node@10.9.2(@types/node@20.19.25)(typescript@5.9.3)) + "@jest/core": 29.7.0(ts-node@10.9.2(@types/node@22.7.5)(typescript@5.9.3)) "@jest/types": 29.6.3 import-local: 3.2.0 - jest-cli: 29.7.0(@types/node@22.7.5) + jest-cli: 29.7.0(@types/node@22.7.5)(ts-node@10.9.2(@types/node@22.7.5)(typescript@5.9.3)) transitivePeerDependencies: - "@types/node" - babel-plugin-macros @@ -30179,6 +30264,11 @@ snapshots: pg-cloudflare@1.2.7: optional: true + pg-cloudflare@1.3.0: + optional: true + + pg-connection-string@2.10.1: {} + pg-connection-string@2.9.1: {} pg-copy-streams@6.0.6: @@ -30191,8 +30281,14 @@ snapshots: dependencies: pg: 8.16.3 + pg-pool@3.11.0(pg@8.17.2): + dependencies: + pg: 8.17.2 + pg-protocol@1.10.3: {} + pg-protocol@1.11.0: {} + pg-query-emscripten@5.1.0: {} pg-types@2.2.0: @@ -30213,6 +30309,16 @@ snapshots: optionalDependencies: pg-cloudflare: 1.2.7 + pg@8.17.2: + dependencies: + pg-connection-string: 2.10.1 + pg-pool: 3.11.0(pg@8.17.2) + pg-protocol: 1.11.0 + pg-types: 2.2.0 + pgpass: 1.0.5 + optionalDependencies: + pg-cloudflare: 1.3.0 + pgpass@1.0.5: dependencies: split2: 4.2.0 @@ -31754,12 +31860,12 @@ snapshots: esbuild: 0.25.8 jest-util: 29.7.0 - ts-jest@29.4.6(@babel/core@7.28.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.0))(jest-util@29.7.0)(jest@29.7.0(@types/node@22.7.5))(typescript@5.9.3): + ts-jest@29.4.6(@babel/core@7.28.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.0))(jest-util@29.7.0)(jest@29.7.0(@types/node@22.7.5)(ts-node@10.9.2(@types/node@22.7.5)(typescript@5.9.3)))(typescript@5.9.3): dependencies: bs-logger: 0.2.6 fast-json-stable-stringify: 2.1.0 handlebars: 4.7.8 - jest: 29.7.0(@types/node@22.7.5) + jest: 29.7.0(@types/node@22.7.5)(ts-node@10.9.2(@types/node@22.7.5)(typescript@5.9.3)) json5: 2.2.3 lodash.memoize: 4.1.2 make-error: 1.3.6 @@ -31774,12 +31880,12 @@ snapshots: babel-jest: 29.7.0(@babel/core@7.28.0) jest-util: 29.7.0 - ts-jest@29.4.6(@babel/core@7.28.5)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.5))(jest-util@29.7.0)(jest@29.7.0(@types/node@20.19.25))(typescript@5.9.3): + ts-jest@29.4.6(@babel/core@7.28.5)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.5))(jest-util@29.7.0)(jest@29.7.0(@types/node@20.19.25)(ts-node@10.9.2(@types/node@20.19.25)(typescript@5.9.3)))(typescript@5.9.3): dependencies: bs-logger: 0.2.6 fast-json-stable-stringify: 2.1.0 handlebars: 4.7.8 - jest: 29.7.0(@types/node@20.19.25) + jest: 29.7.0(@types/node@20.19.25)(ts-node@10.9.2(@types/node@20.19.25)(typescript@5.9.3)) json5: 2.2.3 lodash.memoize: 4.1.2 make-error: 1.3.6 @@ -31816,6 +31922,25 @@ snapshots: v8-compile-cache-lib: 3.0.1 yn: 3.1.1 + ts-node@10.9.2(@types/node@22.7.5)(typescript@5.9.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": 22.7.5 + 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.9.3 + v8-compile-cache-lib: 3.0.1 + yn: 3.1.1 + optional: true + tsconfck@3.1.6(typescript@5.9.3): optionalDependencies: typescript: 5.9.3 From c6dd48ade157d56296e4c5486b54dddee40fc785 Mon Sep 17 00:00:00 2001 From: lucas picollo Date: Thu, 29 Jan 2026 15:11:37 -0300 Subject: [PATCH 10/16] fix: connect api to db on a specific schema --- apps/api/drizzle.config.ts | 5 ----- apps/api/src/env.ts | 4 +++- apps/api/src/index.ts | 2 +- 3 files changed, 4 insertions(+), 7 deletions(-) delete mode 100644 apps/api/drizzle.config.ts diff --git a/apps/api/drizzle.config.ts b/apps/api/drizzle.config.ts deleted file mode 100644 index 3f2152430..000000000 --- a/apps/api/drizzle.config.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { defineConfig } from "drizzle-kit"; -export default defineConfig({ - dialect: "postgresql", - schema: "./src/database/schema.ts", -}); diff --git a/apps/api/src/env.ts b/apps/api/src/env.ts index 8a023bfe5..393683766 100644 --- a/apps/api/src/env.ts +++ b/apps/api/src/env.ts @@ -7,7 +7,9 @@ dotenv.config(); const envSchema = z.object({ RPC_URL: z.string(), - DATABASE_URL: z.string(), + DATABASE_URL: z + .string() + .transform((val) => `${val}?options=-c%20search_path%3Danticapture`), DAO_ID: z.nativeEnum(DaoIdEnum), CHAIN_ID: z.coerce.number(), diff --git a/apps/api/src/index.ts b/apps/api/src/index.ts index 7d041d2e5..f02c0fe8d 100644 --- a/apps/api/src/index.ts +++ b/apps/api/src/index.ts @@ -113,7 +113,7 @@ if (!daoClient) { throw new Error(`Client not found for DAO ${env.DAO_ID}`); } -const pgClient = drizzle(env.DATABASE_URL, { schema }); +const pgClient = drizzle(env.DATABASE_URL, { schema, casing: "snake_case" }); const daoConfig = CONTRACT_ADDRESSES[env.DAO_ID]; const { blockTime, tokenType } = daoConfig; From 085bbab744b2b66e9c425d9a4ee97fbe3323360b Mon Sep 17 00:00:00 2001 From: lucas picollo Date: Thu, 29 Jan 2026 15:12:05 -0300 Subject: [PATCH 11/16] chore: api debug config with watch --- .vscode/launch.json | 8 ++++---- apps/api/package.json | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 32d0266c6..910d2e473 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -23,16 +23,16 @@ { "type": "node", "request": "launch", - "name": "indexer", + "name": "api", "skipFiles": ["/**"], "runtimeExecutable": "pnpm", - "runtimeArgs": ["run", "serve", "--config", "config/ens.config.ts"], + "runtimeArgs": ["run", "dev:watch"], "env": { "TS_NODE_PROJECT": "${workspaceFolder}/tsconfig.json", - "ENV_FILE": "${workspaceFolder}/apps/indexer/.env" + "ENV_FILE": "${workspaceFolder}/apps/api/.env" }, "outFiles": ["${workspaceFolder}/**/*.js", "!**/node_modules/**"], - "cwd": "${workspaceFolder}/apps/indexer" + "cwd": "${workspaceFolder}/apps/api" } ] } diff --git a/apps/api/package.json b/apps/api/package.json index aec49ea62..36af10504 100644 --- a/apps/api/package.json +++ b/apps/api/package.json @@ -11,7 +11,8 @@ "start": "node dist/index.js", "build": "tsup", "build:watch": "tsc --watch", - "dev": "tsx src/index.ts" + "dev": "tsx src/index.ts", + "dev:watch": "tsx watch src/index.ts" }, "keywords": [], "author": "", From 35762c5b14788c1b1163dab21e8cb78b5a273542 Mon Sep 17 00:00:00 2001 From: lucas picollo Date: Thu, 29 Jan 2026 15:37:14 -0300 Subject: [PATCH 12/16] fix: metricType as camel case --- apps/api/src/database/schema.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/api/src/database/schema.ts b/apps/api/src/database/schema.ts index 01fa67514..63ecf1cde 100644 --- a/apps/api/src/database/schema.ts +++ b/apps/api/src/database/schema.ts @@ -224,7 +224,7 @@ export const daoMetricsDayBucket = pgTable( date: bigint({ mode: "bigint" }).notNull(), daoId: drizzle.text("dao_id").notNull(), tokenId: drizzle.text("token_id").notNull(), - metricType: metricType().notNull(), + metricType: metricType("metricType").notNull(), open: bigint({ mode: "bigint" }).notNull(), close: bigint({ mode: "bigint" }).notNull(), low: bigint({ mode: "bigint" }).notNull(), From 333b2e16d9240f26aed3dfc08ff4d48fcfcad643 Mon Sep 17 00:00:00 2001 From: lucas picollo Date: Tue, 3 Feb 2026 15:02:10 -0300 Subject: [PATCH 13/16] chore: add relation between proposal and votes on the db --- apps/api/src/database/schema.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/apps/api/src/database/schema.ts b/apps/api/src/database/schema.ts index 63ecf1cde..356f696c7 100644 --- a/apps/api/src/database/schema.ts +++ b/apps/api/src/database/schema.ts @@ -5,6 +5,7 @@ import { pgEnum, primaryKey, } from "drizzle-orm/pg-core"; +import { relations } from "drizzle-orm"; import { Address, zeroAddress } from "viem"; import { MetricTypesArray } from "@/lib/constants"; @@ -216,6 +217,13 @@ export const proposalsOnchain = pgTable( (table) => [index().on(table.proposerAccountId)], ); +export const votesOnchainRelations = relations(votesOnchain, ({ one }) => ({ + proposal: one(proposalsOnchain, { + fields: [votesOnchain.proposalId], + references: [proposalsOnchain.id], + }), +})); + export const metricType = pgEnum("metricType", MetricTypesArray); export const daoMetricsDayBucket = pgTable( From 66d928601b4a22811fa3637aecd3ca47d660b7c2 Mon Sep 17 00:00:00 2001 From: lucas picollo Date: Tue, 3 Feb 2026 15:05:40 -0300 Subject: [PATCH 14/16] fix: remove pgTable deprecated signature --- apps/api/src/database/schema.ts | 72 ++++++++++++++++----------------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/apps/api/src/database/schema.ts b/apps/api/src/database/schema.ts index 356f696c7..309de651c 100644 --- a/apps/api/src/database/schema.ts +++ b/apps/api/src/database/schema.ts @@ -36,12 +36,12 @@ export const accountBalance = pgTable( // This field represents for who the account is delegating their voting power to delegate: drizzle.text().default(zeroAddress).notNull(), }), - (table) => ({ - pk: primaryKey({ + (table) => [ + primaryKey({ columns: [table.accountId, table.tokenId], }), - accountBalanceDelegateIdx: index().on(table.delegate), - }), + index().on(table.delegate), + ], ); export const accountPower = pgTable( @@ -58,12 +58,12 @@ export const accountPower = pgTable( .default(BigInt(0)) .notNull(), }), - (table) => ({ - pk: primaryKey({ + (table) => [ + primaryKey({ columns: [table.accountId], }), - lastVoteTimestamp: index().on(table.lastVoteTimestamp), - }), + index().on(table.lastVoteTimestamp), + ], ); export const votingPowerHistory = pgTable( @@ -78,11 +78,11 @@ export const votingPowerHistory = pgTable( timestamp: bigint({ mode: "bigint" }).notNull(), logIndex: drizzle.integer("log_index").notNull(), }), - (table) => ({ - pk: primaryKey({ + (table) => [ + primaryKey({ columns: [table.transactionHash, table.accountId, table.logIndex], }), - }), + ], ); export const balanceHistory = pgTable( @@ -97,11 +97,11 @@ export const balanceHistory = pgTable( timestamp: bigint({ mode: "bigint" }).notNull(), logIndex: drizzle.integer("log_index").notNull(), }), - (table) => ({ - pk: primaryKey({ + (table) => [ + primaryKey({ columns: [table.transactionHash, table.accountId, table.logIndex], }), - }), + ], ); export const delegation = pgTable( @@ -126,20 +126,20 @@ export const delegation = pgTable( isLending: drizzle.boolean().notNull().default(false), isTotal: drizzle.boolean().notNull().default(false), }), - (table) => ({ - pk: primaryKey({ + (table) => [ + primaryKey({ columns: [ table.transactionHash, table.delegatorAccountId, table.delegateAccountId, ], }), - delegationTransactionHashIdx: index().on(table.transactionHash), - delegationTimestampIdx: index().on(table.timestamp), - delegationDelegatorAccountIdIdx: index().on(table.delegatorAccountId), - delegationDelegateAccountIdIdx: index().on(table.delegateAccountId), - delegationDelegatedValueIdx: index().on(table.delegatedValue), - }), + index().on(table.transactionHash), + index().on(table.timestamp), + index().on(table.delegatorAccountId), + index().on(table.delegateAccountId), + index().on(table.delegatedValue), + ], ); export const transfer = pgTable( @@ -158,16 +158,16 @@ export const transfer = pgTable( isLending: drizzle.boolean().notNull().default(false), isTotal: drizzle.boolean().notNull().default(false), }), - (table) => ({ - pk: primaryKey({ + (table) => [ + primaryKey({ columns: [table.transactionHash, table.fromAccountId, table.toAccountId], }), - transferTransactionHashIdx: index().on(table.transactionHash), - transferTimestampIdx: index().on(table.timestamp), - transferFromAccountIdIdx: index().on(table.fromAccountId), - transferToAccountIdIdx: index().on(table.toAccountId), - transferAmountIdx: index().on(table.amount), - }), + index().on(table.transactionHash), + index().on(table.timestamp), + index().on(table.fromAccountId), + index().on(table.toAccountId), + index().on(table.amount), + ], ); export const votesOnchain = pgTable( @@ -182,11 +182,11 @@ export const votesOnchain = pgTable( reason: drizzle.text(), timestamp: bigint({ mode: "bigint" }).notNull(), }), - (table) => ({ - pk: primaryKey({ + (table) => [ + primaryKey({ columns: [table.voterAccountId, table.proposalId], }), - }), + ], ); export const proposalsOnchain = pgTable( @@ -242,11 +242,11 @@ export const daoMetricsDayBucket = pgTable( count: drizzle.integer().notNull(), lastUpdate: bigint({ mode: "bigint" }).notNull(), }), - (table) => ({ - pk: primaryKey({ + (table) => [ + primaryKey({ columns: [table.date, table.tokenId, table.metricType], }), - }), + ], ); export const transaction = pgTable("transaction", (drizzle) => ({ From 772cc306403be4b92799f29d2584fdda6780b40a Mon Sep 17 00:00:00 2001 From: lucas picollo Date: Tue, 3 Feb 2026 15:21:23 -0300 Subject: [PATCH 15/16] chore: remove graphql schema from gateway --- apps/api-gateway/meshrc.ts | 44 +------------------------------------- 1 file changed, 1 insertion(+), 43 deletions(-) diff --git a/apps/api-gateway/meshrc.ts b/apps/api-gateway/meshrc.ts index 7ff6ac703..86ec60cba 100644 --- a/apps/api-gateway/meshrc.ts +++ b/apps/api-gateway/meshrc.ts @@ -20,49 +20,7 @@ export default processConfig( const daoName = key.replace("DAO_API_", ""); return [ { - name: `graphql_${daoName}`, - handler: { - graphql: { - endpoint: value, - }, - }, - transforms: [ - { - filterSchema: { - filters: [ - "Query.!{accountBalances}", - "Query.!{accountBalance}", - "Query.!{accountPowers}", - "Query.!{accountPower}", - "Query.!{accounts}", - "Query.!{account}", - "Query.!{balanceHistorys}", - "Query.!{balanceHistory}", - "Query.!{daoMetricsDayBucket}", - "Query.!{daoMetricsDayBuckets}", - "Query.!{delegation}", - "Query.!{delegations}", - "Query.!{proposalsOnchains}", - "Query.!{proposalsOnchain}", - "Query.!{tokenPrices}", - "Query.!{tokenPrice}", - "Query.!{tokens}", - "Query.!{token}", - "Query.!{transactions}", - "Query.!{transaction}", - "Query.!{transfers}", - "Query.!{transfer}", - "Query.!{votesOnchain}", - "Query.!{votingPowerHistory}", - // "Query.!{votesOnchains}", TODO: Leave endpoint active for now as it is still used by the [notification bot](https://github.com/blockful/notification-system/blob/main/packages/anticapture-client/queries/votes.graphql) - // 'Query.!{votingPowerHistorys}' TODO: Leave endpoint active for now as it is still used by the notification bot - ], - }, - }, - ], - }, - { - name: `rest_${daoName}`, + name: daoName, handler: { openapi: { source: `${value}/docs`, From bb8087fa21a3bbc1ecd5f162ffdc071195c53212 Mon Sep 17 00:00:00 2001 From: lucas picollo Date: Tue, 3 Feb 2026 15:26:42 -0300 Subject: [PATCH 16/16] chore: update gateway schema --- apps/api-gateway/schema.graphql | 1252 +------------------------------ 1 file changed, 13 insertions(+), 1239 deletions(-) diff --git a/apps/api-gateway/schema.graphql b/apps/api-gateway/schema.graphql index e7278d0f7..ae321a639 100644 --- a/apps/api-gateway/schema.graphql +++ b/apps/api-gateway/schema.graphql @@ -11,10 +11,6 @@ directive @httpOperation(subgraph: String, path: String, operationSpecificHeader directive @transport(subgraph: String, kind: String, location: String, headers: [[String]], queryStringOptions: ObjMap, queryParams: [[String]]) repeatable on SCHEMA type Query { - votingPowerHistorys(where: votingPowerHistoryFilter, orderBy: String, orderDirection: String, before: String, after: String, limit: Int): votingPowerHistoryPage! - votesOnchains(where: votesOnchainFilter, orderBy: String, orderDirection: String, before: String, after: String, limit: Int): votesOnchainPage! - _meta: Meta - """ Get historical delegations for an account, with optional filtering and sorting """ @@ -174,10 +170,7 @@ type Query { """Returns current governance parameters for this DAO""" dao: dao_200_response - """ - Returns token related metrics for a single metric type. - Available types: TOTAL_SUPPLY, DELEGATED_SUPPLY, CEX_SUPPLY, DEX_SUPPLY, LENDING_SUPPLY, CIRCULATING_SUPPLY, TREASURY - """ + """Returns token related metrics for a single metric type.""" tokenMetrics(metricType: queryInput_tokenMetrics_metricType!, startDate: Float, endDate: Float, orderDirection: queryInput_tokenMetrics_orderDirection = asc, limit: NonNegativeInt = 365, skip: NonNegativeInt): tokenMetrics_200_response """ @@ -218,1237 +211,6 @@ type Query { daos: DAOList! } -""" -The `JSON` scalar type represents JSON values as specified by [ECMA-404](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf). -""" -scalar JSON @specifiedBy(url: "http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf") - -scalar BigInt - -type PageInfo { - hasNextPage: Boolean! - hasPreviousPage: Boolean! - startCursor: String - endCursor: String - endDate: String - startDate: String -} - -type Meta { - status: JSON -} - -type token { - id: String! - name: String - decimals: Int! - totalSupply: BigInt! - delegatedSupply: BigInt! - cexSupply: BigInt! - dexSupply: BigInt! - lendingSupply: BigInt! - circulatingSupply: BigInt! - treasury: BigInt! -} - -type tokenPage { - items: [token!]! - pageInfo: PageInfo! - totalCount: Int! -} - -input tokenFilter { - AND: [tokenFilter] - OR: [tokenFilter] - id: String - id_not: String - id_in: [String] - id_not_in: [String] - id_contains: String - id_not_contains: String - id_starts_with: String - id_ends_with: String - id_not_starts_with: String - id_not_ends_with: String - name: String - name_not: String - name_in: [String] - name_not_in: [String] - name_contains: String - name_not_contains: String - name_starts_with: String - name_ends_with: String - name_not_starts_with: String - name_not_ends_with: String - decimals: Int - decimals_not: Int - decimals_in: [Int] - decimals_not_in: [Int] - decimals_gt: Int - decimals_lt: Int - decimals_gte: Int - decimals_lte: Int - totalSupply: BigInt - totalSupply_not: BigInt - totalSupply_in: [BigInt] - totalSupply_not_in: [BigInt] - totalSupply_gt: BigInt - totalSupply_lt: BigInt - totalSupply_gte: BigInt - totalSupply_lte: BigInt - delegatedSupply: BigInt - delegatedSupply_not: BigInt - delegatedSupply_in: [BigInt] - delegatedSupply_not_in: [BigInt] - delegatedSupply_gt: BigInt - delegatedSupply_lt: BigInt - delegatedSupply_gte: BigInt - delegatedSupply_lte: BigInt - cexSupply: BigInt - cexSupply_not: BigInt - cexSupply_in: [BigInt] - cexSupply_not_in: [BigInt] - cexSupply_gt: BigInt - cexSupply_lt: BigInt - cexSupply_gte: BigInt - cexSupply_lte: BigInt - dexSupply: BigInt - dexSupply_not: BigInt - dexSupply_in: [BigInt] - dexSupply_not_in: [BigInt] - dexSupply_gt: BigInt - dexSupply_lt: BigInt - dexSupply_gte: BigInt - dexSupply_lte: BigInt - lendingSupply: BigInt - lendingSupply_not: BigInt - lendingSupply_in: [BigInt] - lendingSupply_not_in: [BigInt] - lendingSupply_gt: BigInt - lendingSupply_lt: BigInt - lendingSupply_gte: BigInt - lendingSupply_lte: BigInt - circulatingSupply: BigInt - circulatingSupply_not: BigInt - circulatingSupply_in: [BigInt] - circulatingSupply_not_in: [BigInt] - circulatingSupply_gt: BigInt - circulatingSupply_lt: BigInt - circulatingSupply_gte: BigInt - circulatingSupply_lte: BigInt - treasury: BigInt - treasury_not: BigInt - treasury_in: [BigInt] - treasury_not_in: [BigInt] - treasury_gt: BigInt - treasury_lt: BigInt - treasury_gte: BigInt - treasury_lte: BigInt -} - -type account { - id: String! - balances(where: accountBalanceFilter, orderBy: String, orderDirection: String, before: String, after: String, limit: Int): accountBalancePage - powers(where: accountPowerFilter, orderBy: String, orderDirection: String, before: String, after: String, limit: Int): accountPowerPage - delegationsFrom(where: delegationFilter, orderBy: String, orderDirection: String, before: String, after: String, limit: Int): delegationPage - delegationsTo(where: delegationFilter, orderBy: String, orderDirection: String, before: String, after: String, limit: Int): delegationPage - sentTransfers(where: transferFilter, orderBy: String, orderDirection: String, before: String, after: String, limit: Int): transferPage - receivedTransfers(where: transferFilter, orderBy: String, orderDirection: String, before: String, after: String, limit: Int): transferPage - proposals(where: proposalsOnchainFilter, orderBy: String, orderDirection: String, before: String, after: String, limit: Int): proposalsOnchainPage - votes(where: votesOnchainFilter, orderBy: String, orderDirection: String, before: String, after: String, limit: Int): votesOnchainPage - delegatedFromBalances(where: accountBalanceFilter, orderBy: String, orderDirection: String, before: String, after: String, limit: Int): accountBalancePage -} - -type accountBalancePage { - items: [accountBalance!]! - pageInfo: PageInfo! - totalCount: Int! -} - -type accountBalance { - accountId: String! - tokenId: String! - balance: BigInt! - delegate: String! - delegatePower: accountPower - account: account - delegateAccount: account - delegatedTo: accountPower - token: token -} - -type accountPower { - accountId: String! - daoId: String! - votingPower: BigInt! - votesCount: Int! - proposalsCount: Int! - delegationsCount: Int! - lastVoteTimestamp: BigInt! - account: account -} - -input accountBalanceFilter { - AND: [accountBalanceFilter] - OR: [accountBalanceFilter] - accountId: String - accountId_not: String - accountId_in: [String] - accountId_not_in: [String] - accountId_contains: String - accountId_not_contains: String - accountId_starts_with: String - accountId_ends_with: String - accountId_not_starts_with: String - accountId_not_ends_with: String - tokenId: String - tokenId_not: String - tokenId_in: [String] - tokenId_not_in: [String] - tokenId_contains: String - tokenId_not_contains: String - tokenId_starts_with: String - tokenId_ends_with: String - tokenId_not_starts_with: String - tokenId_not_ends_with: String - balance: BigInt - balance_not: BigInt - balance_in: [BigInt] - balance_not_in: [BigInt] - balance_gt: BigInt - balance_lt: BigInt - balance_gte: BigInt - balance_lte: BigInt - delegate: String - delegate_not: String - delegate_in: [String] - delegate_not_in: [String] - delegate_contains: String - delegate_not_contains: String - delegate_starts_with: String - delegate_ends_with: String - delegate_not_starts_with: String - delegate_not_ends_with: String -} - -type accountPowerPage { - items: [accountPower!]! - pageInfo: PageInfo! - totalCount: Int! -} - -input accountPowerFilter { - AND: [accountPowerFilter] - OR: [accountPowerFilter] - accountId: String - accountId_not: String - accountId_in: [String] - accountId_not_in: [String] - accountId_contains: String - accountId_not_contains: String - accountId_starts_with: String - accountId_ends_with: String - accountId_not_starts_with: String - accountId_not_ends_with: String - daoId: String - daoId_not: String - daoId_in: [String] - daoId_not_in: [String] - daoId_contains: String - daoId_not_contains: String - daoId_starts_with: String - daoId_ends_with: String - daoId_not_starts_with: String - daoId_not_ends_with: String - votingPower: BigInt - votingPower_not: BigInt - votingPower_in: [BigInt] - votingPower_not_in: [BigInt] - votingPower_gt: BigInt - votingPower_lt: BigInt - votingPower_gte: BigInt - votingPower_lte: BigInt - votesCount: Int - votesCount_not: Int - votesCount_in: [Int] - votesCount_not_in: [Int] - votesCount_gt: Int - votesCount_lt: Int - votesCount_gte: Int - votesCount_lte: Int - proposalsCount: Int - proposalsCount_not: Int - proposalsCount_in: [Int] - proposalsCount_not_in: [Int] - proposalsCount_gt: Int - proposalsCount_lt: Int - proposalsCount_gte: Int - proposalsCount_lte: Int - delegationsCount: Int - delegationsCount_not: Int - delegationsCount_in: [Int] - delegationsCount_not_in: [Int] - delegationsCount_gt: Int - delegationsCount_lt: Int - delegationsCount_gte: Int - delegationsCount_lte: Int - lastVoteTimestamp: BigInt - lastVoteTimestamp_not: BigInt - lastVoteTimestamp_in: [BigInt] - lastVoteTimestamp_not_in: [BigInt] - lastVoteTimestamp_gt: BigInt - lastVoteTimestamp_lt: BigInt - lastVoteTimestamp_gte: BigInt - lastVoteTimestamp_lte: BigInt -} - -type delegationPage { - items: [delegation!]! - pageInfo: PageInfo! - totalCount: Int! -} - -type delegation { - transactionHash: String! - daoId: String! - delegateAccountId: String! - delegatorAccountId: String! - delegatedValue: BigInt! - previousDelegate: String - timestamp: BigInt! - logIndex: Int! - isCex: Boolean! - isDex: Boolean! - isLending: Boolean! - isTotal: Boolean! - delegate: account - delegator: account - transaction: transaction -} - -type transaction { - transactionHash: String! - fromAddress: String - toAddress: String - isCex: Boolean! - isDex: Boolean! - isLending: Boolean! - isTotal: Boolean! - timestamp: BigInt! - transfers(where: transferFilter, orderBy: String, orderDirection: String, before: String, after: String, limit: Int): transferPage - delegations(where: delegationFilter, orderBy: String, orderDirection: String, before: String, after: String, limit: Int): delegationPage -} - -type transferPage { - items: [transfer!]! - pageInfo: PageInfo! - totalCount: Int! -} - -type transfer { - transactionHash: String! - daoId: String! - tokenId: String! - amount: BigInt! - fromAccountId: String! - toAccountId: String! - timestamp: BigInt! - logIndex: Int! - isCex: Boolean! - isDex: Boolean! - isLending: Boolean! - isTotal: Boolean! - from: account - to: account - token: token - transaction: transaction -} - -input transferFilter { - AND: [transferFilter] - OR: [transferFilter] - transactionHash: String - transactionHash_not: String - transactionHash_in: [String] - transactionHash_not_in: [String] - transactionHash_contains: String - transactionHash_not_contains: String - transactionHash_starts_with: String - transactionHash_ends_with: String - transactionHash_not_starts_with: String - transactionHash_not_ends_with: String - daoId: String - daoId_not: String - daoId_in: [String] - daoId_not_in: [String] - daoId_contains: String - daoId_not_contains: String - daoId_starts_with: String - daoId_ends_with: String - daoId_not_starts_with: String - daoId_not_ends_with: String - tokenId: String - tokenId_not: String - tokenId_in: [String] - tokenId_not_in: [String] - tokenId_contains: String - tokenId_not_contains: String - tokenId_starts_with: String - tokenId_ends_with: String - tokenId_not_starts_with: String - tokenId_not_ends_with: String - amount: BigInt - amount_not: BigInt - amount_in: [BigInt] - amount_not_in: [BigInt] - amount_gt: BigInt - amount_lt: BigInt - amount_gte: BigInt - amount_lte: BigInt - fromAccountId: String - fromAccountId_not: String - fromAccountId_in: [String] - fromAccountId_not_in: [String] - fromAccountId_contains: String - fromAccountId_not_contains: String - fromAccountId_starts_with: String - fromAccountId_ends_with: String - fromAccountId_not_starts_with: String - fromAccountId_not_ends_with: String - toAccountId: String - toAccountId_not: String - toAccountId_in: [String] - toAccountId_not_in: [String] - toAccountId_contains: String - toAccountId_not_contains: String - toAccountId_starts_with: String - toAccountId_ends_with: String - toAccountId_not_starts_with: String - toAccountId_not_ends_with: String - timestamp: BigInt - timestamp_not: BigInt - timestamp_in: [BigInt] - timestamp_not_in: [BigInt] - timestamp_gt: BigInt - timestamp_lt: BigInt - timestamp_gte: BigInt - timestamp_lte: BigInt - logIndex: Int - logIndex_not: Int - logIndex_in: [Int] - logIndex_not_in: [Int] - logIndex_gt: Int - logIndex_lt: Int - logIndex_gte: Int - logIndex_lte: Int - isCex: Boolean - isCex_not: Boolean - isCex_in: [Boolean] - isCex_not_in: [Boolean] - isDex: Boolean - isDex_not: Boolean - isDex_in: [Boolean] - isDex_not_in: [Boolean] - isLending: Boolean - isLending_not: Boolean - isLending_in: [Boolean] - isLending_not_in: [Boolean] - isTotal: Boolean - isTotal_not: Boolean - isTotal_in: [Boolean] - isTotal_not_in: [Boolean] -} - -input delegationFilter { - AND: [delegationFilter] - OR: [delegationFilter] - transactionHash: String - transactionHash_not: String - transactionHash_in: [String] - transactionHash_not_in: [String] - transactionHash_contains: String - transactionHash_not_contains: String - transactionHash_starts_with: String - transactionHash_ends_with: String - transactionHash_not_starts_with: String - transactionHash_not_ends_with: String - daoId: String - daoId_not: String - daoId_in: [String] - daoId_not_in: [String] - daoId_contains: String - daoId_not_contains: String - daoId_starts_with: String - daoId_ends_with: String - daoId_not_starts_with: String - daoId_not_ends_with: String - delegateAccountId: String - delegateAccountId_not: String - delegateAccountId_in: [String] - delegateAccountId_not_in: [String] - delegateAccountId_contains: String - delegateAccountId_not_contains: String - delegateAccountId_starts_with: String - delegateAccountId_ends_with: String - delegateAccountId_not_starts_with: String - delegateAccountId_not_ends_with: String - delegatorAccountId: String - delegatorAccountId_not: String - delegatorAccountId_in: [String] - delegatorAccountId_not_in: [String] - delegatorAccountId_contains: String - delegatorAccountId_not_contains: String - delegatorAccountId_starts_with: String - delegatorAccountId_ends_with: String - delegatorAccountId_not_starts_with: String - delegatorAccountId_not_ends_with: String - delegatedValue: BigInt - delegatedValue_not: BigInt - delegatedValue_in: [BigInt] - delegatedValue_not_in: [BigInt] - delegatedValue_gt: BigInt - delegatedValue_lt: BigInt - delegatedValue_gte: BigInt - delegatedValue_lte: BigInt - previousDelegate: String - previousDelegate_not: String - previousDelegate_in: [String] - previousDelegate_not_in: [String] - previousDelegate_contains: String - previousDelegate_not_contains: String - previousDelegate_starts_with: String - previousDelegate_ends_with: String - previousDelegate_not_starts_with: String - previousDelegate_not_ends_with: String - timestamp: BigInt - timestamp_not: BigInt - timestamp_in: [BigInt] - timestamp_not_in: [BigInt] - timestamp_gt: BigInt - timestamp_lt: BigInt - timestamp_gte: BigInt - timestamp_lte: BigInt - logIndex: Int - logIndex_not: Int - logIndex_in: [Int] - logIndex_not_in: [Int] - logIndex_gt: Int - logIndex_lt: Int - logIndex_gte: Int - logIndex_lte: Int - isCex: Boolean - isCex_not: Boolean - isCex_in: [Boolean] - isCex_not_in: [Boolean] - isDex: Boolean - isDex_not: Boolean - isDex_in: [Boolean] - isDex_not_in: [Boolean] - isLending: Boolean - isLending_not: Boolean - isLending_in: [Boolean] - isLending_not_in: [Boolean] - isTotal: Boolean - isTotal_not: Boolean - isTotal_in: [Boolean] - isTotal_not_in: [Boolean] -} - -type proposalsOnchainPage { - items: [proposalsOnchain!]! - pageInfo: PageInfo! - totalCount: Int! -} - -type proposalsOnchain { - id: String! - txHash: String! - daoId: String! - proposerAccountId: String! - targets: JSON! - values: JSON! - signatures: JSON! - calldatas: JSON! - startBlock: Int! - endBlock: Int! - description: String! - timestamp: BigInt! - endTimestamp: BigInt! - status: String! - forVotes: BigInt! - againstVotes: BigInt! - abstainVotes: BigInt! - proposalType: Int - votes(where: votesOnchainFilter, orderBy: String, orderDirection: String, before: String, after: String, limit: Int): votesOnchainPage - proposer: account -} - -type votesOnchainPage { - items: [votesOnchain!]! - pageInfo: PageInfo! - totalCount: Int! -} - -type votesOnchain { - txHash: String! - daoId: String! - voterAccountId: String! - proposalId: String! - support: String! - votingPower: BigInt! - reason: String - timestamp: BigInt! - proposal: proposalsOnchain - voter: account -} - -input votesOnchainFilter { - AND: [votesOnchainFilter] - OR: [votesOnchainFilter] - txHash: String - txHash_not: String - txHash_in: [String] - txHash_not_in: [String] - txHash_contains: String - txHash_not_contains: String - txHash_starts_with: String - txHash_ends_with: String - txHash_not_starts_with: String - txHash_not_ends_with: String - daoId: String - daoId_not: String - daoId_in: [String] - daoId_not_in: [String] - daoId_contains: String - daoId_not_contains: String - daoId_starts_with: String - daoId_ends_with: String - daoId_not_starts_with: String - daoId_not_ends_with: String - voterAccountId: String - voterAccountId_not: String - voterAccountId_in: [String] - voterAccountId_not_in: [String] - voterAccountId_contains: String - voterAccountId_not_contains: String - voterAccountId_starts_with: String - voterAccountId_ends_with: String - voterAccountId_not_starts_with: String - voterAccountId_not_ends_with: String - proposalId: String - proposalId_not: String - proposalId_in: [String] - proposalId_not_in: [String] - proposalId_contains: String - proposalId_not_contains: String - proposalId_starts_with: String - proposalId_ends_with: String - proposalId_not_starts_with: String - proposalId_not_ends_with: String - support: String - support_not: String - support_in: [String] - support_not_in: [String] - support_contains: String - support_not_contains: String - support_starts_with: String - support_ends_with: String - support_not_starts_with: String - support_not_ends_with: String - votingPower: BigInt - votingPower_not: BigInt - votingPower_in: [BigInt] - votingPower_not_in: [BigInt] - votingPower_gt: BigInt - votingPower_lt: BigInt - votingPower_gte: BigInt - votingPower_lte: BigInt - reason: String - reason_not: String - reason_in: [String] - reason_not_in: [String] - reason_contains: String - reason_not_contains: String - reason_starts_with: String - reason_ends_with: String - reason_not_starts_with: String - reason_not_ends_with: String - timestamp: BigInt - timestamp_not: BigInt - timestamp_in: [BigInt] - timestamp_not_in: [BigInt] - timestamp_gt: BigInt - timestamp_lt: BigInt - timestamp_gte: BigInt - timestamp_lte: BigInt -} - -input proposalsOnchainFilter { - AND: [proposalsOnchainFilter] - OR: [proposalsOnchainFilter] - id: String - id_not: String - id_in: [String] - id_not_in: [String] - id_contains: String - id_not_contains: String - id_starts_with: String - id_ends_with: String - id_not_starts_with: String - id_not_ends_with: String - txHash: String - txHash_not: String - txHash_in: [String] - txHash_not_in: [String] - txHash_contains: String - txHash_not_contains: String - txHash_starts_with: String - txHash_ends_with: String - txHash_not_starts_with: String - txHash_not_ends_with: String - daoId: String - daoId_not: String - daoId_in: [String] - daoId_not_in: [String] - daoId_contains: String - daoId_not_contains: String - daoId_starts_with: String - daoId_ends_with: String - daoId_not_starts_with: String - daoId_not_ends_with: String - proposerAccountId: String - proposerAccountId_not: String - proposerAccountId_in: [String] - proposerAccountId_not_in: [String] - proposerAccountId_contains: String - proposerAccountId_not_contains: String - proposerAccountId_starts_with: String - proposerAccountId_ends_with: String - proposerAccountId_not_starts_with: String - proposerAccountId_not_ends_with: String - startBlock: Int - startBlock_not: Int - startBlock_in: [Int] - startBlock_not_in: [Int] - startBlock_gt: Int - startBlock_lt: Int - startBlock_gte: Int - startBlock_lte: Int - endBlock: Int - endBlock_not: Int - endBlock_in: [Int] - endBlock_not_in: [Int] - endBlock_gt: Int - endBlock_lt: Int - endBlock_gte: Int - endBlock_lte: Int - description: String - description_not: String - description_in: [String] - description_not_in: [String] - description_contains: String - description_not_contains: String - description_starts_with: String - description_ends_with: String - description_not_starts_with: String - description_not_ends_with: String - timestamp: BigInt - timestamp_not: BigInt - timestamp_in: [BigInt] - timestamp_not_in: [BigInt] - timestamp_gt: BigInt - timestamp_lt: BigInt - timestamp_gte: BigInt - timestamp_lte: BigInt - endTimestamp: BigInt - endTimestamp_not: BigInt - endTimestamp_in: [BigInt] - endTimestamp_not_in: [BigInt] - endTimestamp_gt: BigInt - endTimestamp_lt: BigInt - endTimestamp_gte: BigInt - endTimestamp_lte: BigInt - status: String - status_not: String - status_in: [String] - status_not_in: [String] - status_contains: String - status_not_contains: String - status_starts_with: String - status_ends_with: String - status_not_starts_with: String - status_not_ends_with: String - forVotes: BigInt - forVotes_not: BigInt - forVotes_in: [BigInt] - forVotes_not_in: [BigInt] - forVotes_gt: BigInt - forVotes_lt: BigInt - forVotes_gte: BigInt - forVotes_lte: BigInt - againstVotes: BigInt - againstVotes_not: BigInt - againstVotes_in: [BigInt] - againstVotes_not_in: [BigInt] - againstVotes_gt: BigInt - againstVotes_lt: BigInt - againstVotes_gte: BigInt - againstVotes_lte: BigInt - abstainVotes: BigInt - abstainVotes_not: BigInt - abstainVotes_in: [BigInt] - abstainVotes_not_in: [BigInt] - abstainVotes_gt: BigInt - abstainVotes_lt: BigInt - abstainVotes_gte: BigInt - abstainVotes_lte: BigInt - proposalType: Int - proposalType_not: Int - proposalType_in: [Int] - proposalType_not_in: [Int] - proposalType_gt: Int - proposalType_lt: Int - proposalType_gte: Int - proposalType_lte: Int -} - -type accountPage { - items: [account!]! - pageInfo: PageInfo! - totalCount: Int! -} - -input accountFilter { - AND: [accountFilter] - OR: [accountFilter] - id: String - id_not: String - id_in: [String] - id_not_in: [String] - id_contains: String - id_not_contains: String - id_starts_with: String - id_ends_with: String - id_not_starts_with: String - id_not_ends_with: String -} - -type votingPowerHistory { - transactionHash: String! - daoId: String! - accountId: String! - votingPower: BigInt! - delta: BigInt! - deltaMod: BigInt! - timestamp: BigInt! - logIndex: Int! - transfer: transfer - delegation: delegation - account: account -} - -type votingPowerHistoryPage { - items: [votingPowerHistory!]! - pageInfo: PageInfo! - totalCount: Int! -} - -input votingPowerHistoryFilter { - AND: [votingPowerHistoryFilter] - OR: [votingPowerHistoryFilter] - transactionHash: String - transactionHash_not: String - transactionHash_in: [String] - transactionHash_not_in: [String] - transactionHash_contains: String - transactionHash_not_contains: String - transactionHash_starts_with: String - transactionHash_ends_with: String - transactionHash_not_starts_with: String - transactionHash_not_ends_with: String - daoId: String - daoId_not: String - daoId_in: [String] - daoId_not_in: [String] - daoId_contains: String - daoId_not_contains: String - daoId_starts_with: String - daoId_ends_with: String - daoId_not_starts_with: String - daoId_not_ends_with: String - accountId: String - accountId_not: String - accountId_in: [String] - accountId_not_in: [String] - accountId_contains: String - accountId_not_contains: String - accountId_starts_with: String - accountId_ends_with: String - accountId_not_starts_with: String - accountId_not_ends_with: String - votingPower: BigInt - votingPower_not: BigInt - votingPower_in: [BigInt] - votingPower_not_in: [BigInt] - votingPower_gt: BigInt - votingPower_lt: BigInt - votingPower_gte: BigInt - votingPower_lte: BigInt - delta: BigInt - delta_not: BigInt - delta_in: [BigInt] - delta_not_in: [BigInt] - delta_gt: BigInt - delta_lt: BigInt - delta_gte: BigInt - delta_lte: BigInt - deltaMod: BigInt - deltaMod_not: BigInt - deltaMod_in: [BigInt] - deltaMod_not_in: [BigInt] - deltaMod_gt: BigInt - deltaMod_lt: BigInt - deltaMod_gte: BigInt - deltaMod_lte: BigInt - timestamp: BigInt - timestamp_not: BigInt - timestamp_in: [BigInt] - timestamp_not_in: [BigInt] - timestamp_gt: BigInt - timestamp_lt: BigInt - timestamp_gte: BigInt - timestamp_lte: BigInt - logIndex: Int - logIndex_not: Int - logIndex_in: [Int] - logIndex_not_in: [Int] - logIndex_gt: Int - logIndex_lt: Int - logIndex_gte: Int - logIndex_lte: Int -} - -type balanceHistory { - transactionHash: String! - daoId: String! - accountId: String! - balance: BigInt! - delta: BigInt! - deltaMod: BigInt! - timestamp: BigInt! - logIndex: Int! -} - -type balanceHistoryPage { - items: [balanceHistory!]! - pageInfo: PageInfo! - totalCount: Int! -} - -input balanceHistoryFilter { - AND: [balanceHistoryFilter] - OR: [balanceHistoryFilter] - transactionHash: String - transactionHash_not: String - transactionHash_in: [String] - transactionHash_not_in: [String] - transactionHash_contains: String - transactionHash_not_contains: String - transactionHash_starts_with: String - transactionHash_ends_with: String - transactionHash_not_starts_with: String - transactionHash_not_ends_with: String - daoId: String - daoId_not: String - daoId_in: [String] - daoId_not_in: [String] - daoId_contains: String - daoId_not_contains: String - daoId_starts_with: String - daoId_ends_with: String - daoId_not_starts_with: String - daoId_not_ends_with: String - accountId: String - accountId_not: String - accountId_in: [String] - accountId_not_in: [String] - accountId_contains: String - accountId_not_contains: String - accountId_starts_with: String - accountId_ends_with: String - accountId_not_starts_with: String - accountId_not_ends_with: String - balance: BigInt - balance_not: BigInt - balance_in: [BigInt] - balance_not_in: [BigInt] - balance_gt: BigInt - balance_lt: BigInt - balance_gte: BigInt - balance_lte: BigInt - delta: BigInt - delta_not: BigInt - delta_in: [BigInt] - delta_not_in: [BigInt] - delta_gt: BigInt - delta_lt: BigInt - delta_gte: BigInt - delta_lte: BigInt - deltaMod: BigInt - deltaMod_not: BigInt - deltaMod_in: [BigInt] - deltaMod_not_in: [BigInt] - deltaMod_gt: BigInt - deltaMod_lt: BigInt - deltaMod_gte: BigInt - deltaMod_lte: BigInt - timestamp: BigInt - timestamp_not: BigInt - timestamp_in: [BigInt] - timestamp_not_in: [BigInt] - timestamp_gt: BigInt - timestamp_lt: BigInt - timestamp_gte: BigInt - timestamp_lte: BigInt - logIndex: Int - logIndex_not: Int - logIndex_in: [Int] - logIndex_not_in: [Int] - logIndex_gt: Int - logIndex_lt: Int - logIndex_gte: Int - logIndex_lte: Int -} - -type daoMetricsDayBucket { - date: BigInt! - daoId: String! - tokenId: String! - metricType: metricType! - open: BigInt! - close: BigInt! - low: BigInt! - high: BigInt! - average: BigInt! - volume: BigInt! - count: Int! - lastUpdate: BigInt! -} - -enum metricType { - TOTAL_SUPPLY - DELEGATED_SUPPLY - CEX_SUPPLY - DEX_SUPPLY - LENDING_SUPPLY - CIRCULATING_SUPPLY - TREASURY -} - -type daoMetricsDayBucketPage { - items: [daoMetricsDayBucket!]! - pageInfo: PageInfo! - totalCount: Int! -} - -input daoMetricsDayBucketFilter { - AND: [daoMetricsDayBucketFilter] - OR: [daoMetricsDayBucketFilter] - date: BigInt - date_not: BigInt - date_in: [BigInt] - date_not_in: [BigInt] - date_gt: BigInt - date_lt: BigInt - date_gte: BigInt - date_lte: BigInt - daoId: String - daoId_not: String - daoId_in: [String] - daoId_not_in: [String] - daoId_contains: String - daoId_not_contains: String - daoId_starts_with: String - daoId_ends_with: String - daoId_not_starts_with: String - daoId_not_ends_with: String - tokenId: String - tokenId_not: String - tokenId_in: [String] - tokenId_not_in: [String] - tokenId_contains: String - tokenId_not_contains: String - tokenId_starts_with: String - tokenId_ends_with: String - tokenId_not_starts_with: String - tokenId_not_ends_with: String - metricType: metricType - metricType_not: metricType - metricType_in: [metricType] - metricType_not_in: [metricType] - open: BigInt - open_not: BigInt - open_in: [BigInt] - open_not_in: [BigInt] - open_gt: BigInt - open_lt: BigInt - open_gte: BigInt - open_lte: BigInt - close: BigInt - close_not: BigInt - close_in: [BigInt] - close_not_in: [BigInt] - close_gt: BigInt - close_lt: BigInt - close_gte: BigInt - close_lte: BigInt - low: BigInt - low_not: BigInt - low_in: [BigInt] - low_not_in: [BigInt] - low_gt: BigInt - low_lt: BigInt - low_gte: BigInt - low_lte: BigInt - high: BigInt - high_not: BigInt - high_in: [BigInt] - high_not_in: [BigInt] - high_gt: BigInt - high_lt: BigInt - high_gte: BigInt - high_lte: BigInt - average: BigInt - average_not: BigInt - average_in: [BigInt] - average_not_in: [BigInt] - average_gt: BigInt - average_lt: BigInt - average_gte: BigInt - average_lte: BigInt - volume: BigInt - volume_not: BigInt - volume_in: [BigInt] - volume_not_in: [BigInt] - volume_gt: BigInt - volume_lt: BigInt - volume_gte: BigInt - volume_lte: BigInt - count: Int - count_not: Int - count_in: [Int] - count_not_in: [Int] - count_gt: Int - count_lt: Int - count_gte: Int - count_lte: Int - lastUpdate: BigInt - lastUpdate_not: BigInt - lastUpdate_in: [BigInt] - lastUpdate_not_in: [BigInt] - lastUpdate_gt: BigInt - lastUpdate_lt: BigInt - lastUpdate_gte: BigInt - lastUpdate_lte: BigInt -} - -type transactionPage { - items: [transaction!]! - pageInfo: PageInfo! - totalCount: Int! -} - -input transactionFilter { - AND: [transactionFilter] - OR: [transactionFilter] - transactionHash: String - transactionHash_not: String - transactionHash_in: [String] - transactionHash_not_in: [String] - transactionHash_contains: String - transactionHash_not_contains: String - transactionHash_starts_with: String - transactionHash_ends_with: String - transactionHash_not_starts_with: String - transactionHash_not_ends_with: String - fromAddress: String - fromAddress_not: String - fromAddress_in: [String] - fromAddress_not_in: [String] - fromAddress_contains: String - fromAddress_not_contains: String - fromAddress_starts_with: String - fromAddress_ends_with: String - fromAddress_not_starts_with: String - fromAddress_not_ends_with: String - toAddress: String - toAddress_not: String - toAddress_in: [String] - toAddress_not_in: [String] - toAddress_contains: String - toAddress_not_contains: String - toAddress_starts_with: String - toAddress_ends_with: String - toAddress_not_starts_with: String - toAddress_not_ends_with: String - isCex: Boolean - isCex_not: Boolean - isCex_in: [Boolean] - isCex_not_in: [Boolean] - isDex: Boolean - isDex_not: Boolean - isDex_in: [Boolean] - isDex_not_in: [Boolean] - isLending: Boolean - isLending_not: Boolean - isLending_in: [Boolean] - isLending_not_in: [Boolean] - isTotal: Boolean - isTotal_not: Boolean - isTotal_in: [Boolean] - isTotal_not_in: [Boolean] - timestamp: BigInt - timestamp_not: BigInt - timestamp_in: [BigInt] - timestamp_not_in: [BigInt] - timestamp_gt: BigInt - timestamp_lt: BigInt - timestamp_gte: BigInt - timestamp_lte: BigInt -} - -type tokenPrice { - price: BigInt! - timestamp: BigInt! -} - -type tokenPricePage { - items: [tokenPrice!]! - pageInfo: PageInfo! - totalCount: Int! -} - -input tokenPriceFilter { - AND: [tokenPriceFilter] - OR: [tokenPriceFilter] - price: BigInt - price_not: BigInt - price_in: [BigInt] - price_not_in: [BigInt] - price_gt: BigInt - price_lt: BigInt - price_gte: BigInt - price_lte: BigInt - timestamp: BigInt - timestamp_not: BigInt - timestamp_in: [BigInt] - timestamp_not_in: [BigInt] - timestamp_gt: BigInt - timestamp_lt: BigInt - timestamp_gte: BigInt - timestamp_lte: BigInt -} - type historicalDelegations_200_response { items: [query_historicalDelegations_items_items]! totalCount: Float! @@ -1462,6 +224,11 @@ type query_historicalDelegations_items_items { transactionHash: String! } +""" +The `JSON` scalar type represents JSON values as specified by [ECMA-404](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf). +""" +scalar JSON @specifiedBy(url: "http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf") + """Integers that will have a value of 0 or more.""" scalar NonNegativeInt @@ -2394,6 +1161,13 @@ type AverageDelegationPercentageItem { high: String! } +type PageInfo { + hasNextPage: Boolean! + hasPreviousPage: Boolean! + endDate: String + startDate: String +} + type AverageDelegationPercentagePage { items: [AverageDelegationPercentageItem!]!