From 4b6cc84ac4b4af7d9264fa332adb39987be50bd6 Mon Sep 17 00:00:00 2001 From: Timothee Legros <62490329+timolegros@users.noreply.github.com> Date: Fri, 5 Jan 2024 18:18:15 +0100 Subject: [PATCH 1/3] Remove TBC package (#6106) * remove client side gating flag + topic threshold logic * remove token balance property + methods from client Account model * remove more token threshold logic from client * remove env var from webpack * remove ITokenAdapter * removed banner * removed NftAdapter * remove token adapters * remove .only in API tests * eslint fixes * `Topics.token_threshold` removal migration * remove `/bulkBalances` * remove `/tokenBalance` * remove `/tokenBalance` - external API * remove test + types * remove token_balance requirement in created_topics to fix topic creation * remove unused error * remove validateTopicThreshold * fix unit tests * remove token_threshold from sequelize model + delete `/setTopicThreshold` * remove setTopicThreshold mutation * reorder migration * add gating flag to unit tests * remove `/getBalanceProviders` (external API) * remove `/chainNodes` (external API) * remove PUT `/communities` (external API) * remove tbc import from external API * remove external API tests that use TBC package * remove TBC v1 from polls controller * remove TBC v1 from threads controller * remove TBC v1 from comments controller * remove TBC v1 from groups controller * remove TBC from communities controller * remove TBC v1 from server * integration test fix * remove external TBC package references * remove TBC unit tests from CI * remove TBC package + additional types * update yarn.lock * add chai-as-promised types * fix unit test * fix sublayout banner * eslint recommendations * type fix - post merge --- .github/workflows/CI.yml | 3 - knowledge_base/Link-Previews.md | 2 +- packages/commonwealth/package.json | 1 + .../scripts/refresh-all-memberships.ts | 13 +- packages/commonwealth/server-test.ts | 16 +- packages/commonwealth/server.ts | 15 +- .../commonwealth/server/api/extApiTypes.ts | 28 -- .../controllers/server_comments_controller.ts | 7 +- .../create_comment_reaction.ts | 2 +- .../server_communities_controller.ts | 7 +- .../controllers/server_groups_controller.ts | 6 +- .../refresh_community_memberships.ts | 2 +- .../refresh_membership.ts | 2 +- .../controllers/server_polls_controller.ts | 9 +- .../server_polls_methods/update_poll_vote.ts | 2 +- .../controllers/server_threads_controller.ts | 7 +- .../server_threads_methods/create_thread.ts | 2 +- .../create_thread_comment.ts | 2 +- .../create_thread_reaction.ts | 2 +- .../routes/communities/putCommunities.ts | 121 ------ .../server/routes/getBalanceProviders.ts | 36 -- .../server/routes/getChainNodes.ts | 37 -- .../commonwealth/server/routing/external.ts | 30 -- .../commonwealth/server/routing/router.ts | 39 +- .../test/integration/api/chainNodes.spec.ts | 2 +- .../test/integration/api/createChain.spec.ts | 35 +- .../integration/api/external/appHook.spec.ts | 11 +- .../api/external/cacheHooks.spec.ts | 65 ---- .../api/external/getBalanceProviders.spec.ts | 28 -- .../api/external/getChainNodes.spec.ts | 52 --- .../api/external/putCommunities.spec.ts | 45 --- .../api/getRelatedCommunities.spec.ts | 27 +- .../test/integration/api/tokenForum.spec.ts | 214 ----------- .../test/integration/api/updateChain.spec.ts | 2 +- .../server_comments_controller.spec.ts | 10 - .../server_groups_controller.spec.ts | 1 - .../server_threads_controller.spec.ts | 17 - ...r_threads_controller.update_thread.spec.ts | 1 - packages/commonwealth/test/util/modelUtils.ts | 52 +-- packages/token-balance-cache/.gitignore | 1 - packages/token-balance-cache/.mocharc.json | 7 - packages/token-balance-cache/package.json | 28 -- packages/token-balance-cache/src/index.ts | 2 - .../src/providers/cosmos.ts | 60 --- .../src/providers/ethToken.ts | 84 ----- .../src/providers/index.ts | 15 - .../src/providers/ronin.ts | 89 ----- .../src/providers/splToken.ts | 62 --- .../src/providers/terra.ts | 106 ------ packages/token-balance-cache/src/tbc.ts | 356 ------------------ .../src/tbcStatsDSender.ts | 63 ---- packages/token-balance-cache/src/types.ts | 96 ----- .../src/util/validateOpts.ts | 21 -- .../token-balance-cache/test/cosmos.spec.ts | 80 ---- .../token-balance-cache/test/ethToken.spec.ts | 73 ---- packages/token-balance-cache/test/evm.spec.ts | 55 --- .../token-balance-cache/test/ronin.spec.ts | 83 ---- .../token-balance-cache/test/splToken.spec.ts | 85 ----- packages/token-balance-cache/test/tbc.spec.ts | 200 ---------- packages/token-balance-cache/tsconfig.json | 10 - .../token-balance-cache/tsconfig.test.json | 5 - yarn.lock | 46 +-- 62 files changed, 105 insertions(+), 2475 deletions(-) delete mode 100644 packages/commonwealth/server/routes/communities/putCommunities.ts delete mode 100644 packages/commonwealth/server/routes/getBalanceProviders.ts delete mode 100644 packages/commonwealth/server/routes/getChainNodes.ts delete mode 100644 packages/commonwealth/test/integration/api/external/cacheHooks.spec.ts delete mode 100644 packages/commonwealth/test/integration/api/external/getBalanceProviders.spec.ts delete mode 100644 packages/commonwealth/test/integration/api/external/getChainNodes.spec.ts delete mode 100644 packages/commonwealth/test/integration/api/external/putCommunities.spec.ts delete mode 100644 packages/commonwealth/test/integration/api/tokenForum.spec.ts delete mode 100644 packages/token-balance-cache/.gitignore delete mode 100644 packages/token-balance-cache/.mocharc.json delete mode 100644 packages/token-balance-cache/package.json delete mode 100644 packages/token-balance-cache/src/index.ts delete mode 100644 packages/token-balance-cache/src/providers/cosmos.ts delete mode 100644 packages/token-balance-cache/src/providers/ethToken.ts delete mode 100644 packages/token-balance-cache/src/providers/index.ts delete mode 100644 packages/token-balance-cache/src/providers/ronin.ts delete mode 100644 packages/token-balance-cache/src/providers/splToken.ts delete mode 100644 packages/token-balance-cache/src/providers/terra.ts delete mode 100644 packages/token-balance-cache/src/tbc.ts delete mode 100644 packages/token-balance-cache/src/tbcStatsDSender.ts delete mode 100644 packages/token-balance-cache/src/types.ts delete mode 100644 packages/token-balance-cache/src/util/validateOpts.ts delete mode 100644 packages/token-balance-cache/test/cosmos.spec.ts delete mode 100644 packages/token-balance-cache/test/ethToken.spec.ts delete mode 100644 packages/token-balance-cache/test/evm.spec.ts delete mode 100644 packages/token-balance-cache/test/ronin.spec.ts delete mode 100644 packages/token-balance-cache/test/splToken.spec.ts delete mode 100644 packages/token-balance-cache/test/tbc.spec.ts delete mode 100644 packages/token-balance-cache/tsconfig.json delete mode 100644 packages/token-balance-cache/tsconfig.test.json diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 86c6ae42a5f..b47ddd38d29 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -491,9 +491,6 @@ jobs: echo "Network name: $network_name" /usr/bin/docker run -d --name chain --network $network_name --network-alias chain -p 8545:8545 -e GITHUB_ACTIONS=true -e CI=true trufflesuite/ganache --fork --miner.blockTime 12 --wallet.unlockedAccounts 0xF977814e90dA44bFA03b6295A0616a897441aceC --wallet.unlockedAccounts 0xfA9b5f7fDc8AB34AAf3099889475d47febF830D7 --wallet.unlockedAccounts 0xBE0eB53F46cd790Cd13851d5EFf43D12404d33E8; - - name: Run Token Balance Cache Unit Tests - run: yarn --cwd packages/token-balance-cache test --forbid-only - - name: Run EVM Devnet tests run: yarn --cwd packages/commonwealth test-devnet evm --forbid-only diff --git a/knowledge_base/Link-Previews.md b/knowledge_base/Link-Previews.md index e3fd6118fee..122e1bc1907 100644 --- a/knowledge_base/Link-Previews.md +++ b/knowledge_base/Link-Previews.md @@ -9,7 +9,7 @@ To get link previews, you will need to do the following: 3. Run against the built site in the packages/commonwealth folder with: ```bash - NO_TOKEN_BALANCE_CACHE=true NO_PRERENDER=true NO_CLIENT_SERVER=true MIXPANEL_DEV_TOKEN=foo MIXPANEL_PROD_TOKEN=bar NODE_ENV=production npx ts-node -P tsconfig.server.json -T server.ts + NO_PRERENDER=true NO_CLIENT_SERVER=true MIXPANEL_DEV_TOKEN=foo MIXPANEL_PROD_TOKEN=bar NODE_ENV=production npx ts-node -P tsconfig.server.json -T server.ts ``` 4. With the site running, query the link preview with `curl -G http://localhost:8080/` diff --git a/packages/commonwealth/package.json b/packages/commonwealth/package.json index fd37b712a06..4f879ac22c0 100644 --- a/packages/commonwealth/package.json +++ b/packages/commonwealth/package.json @@ -117,6 +117,7 @@ "@todesktop/client-core": "^1.1.3", "@types/bn.js": "^4.11.6", "@types/bs58": "^4.0.1", + "@types/chai-as-promised": "^7.1.8", "@types/express": "^4.17.1", "@types/filesystem": "^0.0.29", "@types/jquery": "^3.5.4", diff --git a/packages/commonwealth/scripts/refresh-all-memberships.ts b/packages/commonwealth/scripts/refresh-all-memberships.ts index 6aa8aeafd20..6d8a773bdb0 100644 --- a/packages/commonwealth/scripts/refresh-all-memberships.ts +++ b/packages/commonwealth/scripts/refresh-all-memberships.ts @@ -1,12 +1,11 @@ import * as dotenv from 'dotenv'; import { RedisCache } from '../../common-common/src/redisCache'; -import { TokenBalanceCache as TokenBalanceCacheV1 } from '../../token-balance-cache/src'; import { REDIS_URL } from '../server/config'; import { ServerCommunitiesController } from '../server/controllers/server_communities_controller'; import { ServerGroupsController } from '../server/controllers/server_groups_controller'; import db from '../server/database'; import BanCache from '../server/util/banCheckCache'; -import { TokenBalanceCache as TokenBalanceCacheV2 } from '../server/util/tokenBalanceCache/tokenBalanceCache'; +import { TokenBalanceCache } from '../server/util/tokenBalanceCache/tokenBalanceCache'; dotenv.config(); @@ -16,22 +15,16 @@ async function main() { await redisCache.init(REDIS_URL); const banCache = new BanCache(models); - const tokenBalanceCacheV1 = new TokenBalanceCacheV1(); - await tokenBalanceCacheV1.initBalanceProviders(); - await tokenBalanceCacheV1.start(); - - const tokenBalanceCacheV2 = new TokenBalanceCacheV2(models, redisCache); + const tokenBalanceCache = new TokenBalanceCache(models, redisCache); const communitiesController = new ServerCommunitiesController( models, - tokenBalanceCacheV1, banCache, ); const groupsController = new ServerGroupsController( models, - tokenBalanceCacheV1, - tokenBalanceCacheV2, + tokenBalanceCache, banCache, ); diff --git a/packages/commonwealth/server-test.ts b/packages/commonwealth/server-test.ts index f0f3dce324e..e598e523966 100644 --- a/packages/commonwealth/server-test.ts +++ b/packages/commonwealth/server-test.ts @@ -10,7 +10,6 @@ import http from 'http'; import passport from 'passport'; import Rollbar from 'rollbar'; import favicon from 'serve-favicon'; -import { TokenBalanceCache } from 'token-balance-cache/src/index'; import setupAPI from './server/routing/router'; // performance note: this takes 15 seconds import setupCosmosProxy from 'server/util/cosmosProxy'; @@ -18,6 +17,7 @@ import { ROLLBAR_ENV, ROLLBAR_SERVER_TOKEN, SESSION_SECRET, + TBC_BALANCE_TTL_SECONDS, } from './server/config'; import models from './server/database'; import DatabaseValidationService from './server/middleware/databaseValidationService'; @@ -25,7 +25,6 @@ import setupPassport from './server/passport'; import BanCache from './server/util/banCheckCache'; import GlobalActivityCache from './server/util/globalActivityCache'; import ViewCountCache from './server/util/viewCountCache'; -import { MockTokenBalanceProvider } from './test/util/modelUtils'; import { ServerError } from 'common-common/src/errors'; import { cacheDecorator } from '../common-common/src/cacheDecorator'; @@ -36,6 +35,7 @@ import { import { factory, formatFilename } from 'common-common/src/logging'; import { RedisCache } from 'common-common/src/redisCache'; +import { TokenBalanceCache } from './server/util/tokenBalanceCache/tokenBalanceCache'; const log = factory.getLogger(formatFilename(__filename)); @@ -45,10 +45,11 @@ const app = express(); const SequelizeStore = SessionSequelizeStore(session.Store); // set cache TTL to 1 second to test invalidation const viewCountCache = new ViewCountCache(1, 10 * 60); -const mockTokenBalanceProvider = new MockTokenBalanceProvider(); -const tokenBalanceCache = new TokenBalanceCache(0, 0, [ - mockTokenBalanceProvider, -]); +const tokenBalanceCache = new TokenBalanceCache( + models, + null as RedisCache, + TBC_BALANCE_TTL_SECONDS, +); const databaseValidationService = new DatabaseValidationService(models); let server; @@ -219,8 +220,5 @@ setupErrorHandlers(app, rollbar); setupServer(); export { resetDatabase } from './test/util/resetDatabase'; -export const getTokenBalanceCache = () => tokenBalanceCache; -export const getBanCache = () => banCache; -export const getMockBalanceProvider = () => mockTokenBalanceProvider; export default app; diff --git a/packages/commonwealth/server.ts b/packages/commonwealth/server.ts index f9e48566649..a6b9c032662 100644 --- a/packages/commonwealth/server.ts +++ b/packages/commonwealth/server.ts @@ -24,7 +24,6 @@ import prerenderNode from 'prerender-node'; import type { BrokerConfig } from 'rascal'; import Rollbar from 'rollbar'; import favicon from 'serve-favicon'; -import { TokenBalanceCache } from 'token-balance-cache/src/index'; import * as v8 from 'v8'; import setupErrorHandlers from '../common-common/src/scripts/setupErrorHandlers'; import { @@ -34,6 +33,7 @@ import { ROLLBAR_ENV, ROLLBAR_SERVER_TOKEN, SESSION_SECRET, + TBC_BALANCE_TTL_SECONDS, VULTR_IP, } from './server/config'; import models from './server/database'; @@ -52,6 +52,7 @@ import setupCosmosProxy from './server/util/cosmosProxy'; import { databaseCleaner } from './server/util/databaseCleaner'; import GlobalActivityCache from './server/util/globalActivityCache'; import setupIpfsProxy from './server/util/ipfsProxy'; +import { TokenBalanceCache } from './server/util/tokenBalanceCache/tokenBalanceCache'; import ViewCountCache from './server/util/viewCountCache'; let isServiceHealthy = false; @@ -85,7 +86,6 @@ async function main() { const SHOULD_ADD_MISSING_DECIMALS_TO_TOKENS = process.env.SHOULD_ADD_MISSING_DECIMALS_TO_TOKENS === 'true'; - const NO_TOKEN_BALANCE_CACHE = process.env.NO_TOKEN_BALANCE_CACHE === 'true'; const NO_GLOBAL_ACTIVITY_CACHE = process.env.NO_GLOBAL_ACTIVITY_CACHE === 'true'; const NO_CLIENT_SERVER = @@ -93,8 +93,6 @@ async function main() { SHOULD_SEND_EMAILS || SHOULD_ADD_MISSING_DECIMALS_TO_TOKENS; - const tokenBalanceCache = new TokenBalanceCache(); - await tokenBalanceCache.initBalanceProviders(); let rc = null; if (SHOULD_SEND_EMAILS) { rc = await sendBatchedNotificationEmails(models); @@ -262,7 +260,12 @@ async function main() { const redisCache = new RedisCache(); await redisCache.init(REDIS_URL, VULTR_IP); - if (!NO_TOKEN_BALANCE_CACHE) await tokenBalanceCache.start(); + const tokenBalanceCache = new TokenBalanceCache( + models, + redisCache, + TBC_BALANCE_TTL_SECONDS, + ); + const banCache = new BanCache(models); const globalActivityCache = new GlobalActivityCache(models, redisCache); @@ -287,7 +290,7 @@ async function main() { ); // new API - addExternalRoutes('/external', app, models, tokenBalanceCache); + addExternalRoutes('/external', app, models); addSwagger('/docs', app); setupCosmosProxy(app, models); diff --git a/packages/commonwealth/server/api/extApiTypes.ts b/packages/commonwealth/server/api/extApiTypes.ts index d2f74fac08f..50e865d7b9e 100644 --- a/packages/commonwealth/server/api/extApiTypes.ts +++ b/packages/commonwealth/server/api/extApiTypes.ts @@ -1,9 +1,5 @@ // contains types for external api -import type { - BalanceProviderResp, - ChainNodeResp, -} from 'token-balance-cache/src'; import type { CommentAttributes } from '../models/comment'; import type { CommunityAttributes } from '../models/community'; import type { ProfileAttributes } from '../models/profile'; @@ -75,14 +71,6 @@ export type GetCommunitiesReq = { page?: number; }; -export type PutCommunitiesReq = { - community: CommunityAttributes; - contract: { token_type: string; address: string }; - admin_addresses: string[]; -}; - -export type PutCommunitiesResp = { url: string; error?: string }; - export type GetCommunitiesResp = { communities?: CommunityAttributes[]; count: number; @@ -96,22 +84,6 @@ export type GetProfilesReq = { export type GetProfilesResp = { profiles?: ProfileAttributes[]; count: number }; -export type GetChainNodesReq = { - chain_node_ids?: number[]; - names?: string[]; -} & IPagination; - -export type GetChainNodesResp = { chain_nodes: ChainNodeResp[]; count: number }; - -export type GetBalanceProvidersReq = { - chain_node_ids: number[]; -}; - -export type GetBalanceProvidersResp = { - balance_providers: BalanceProviderResp[]; - count: number; -}; - export type GetTopicsReq = { community_id: string; count_only?: boolean; diff --git a/packages/commonwealth/server/controllers/server_comments_controller.ts b/packages/commonwealth/server/controllers/server_comments_controller.ts index 16d4e25f3a0..aecf9562ee3 100644 --- a/packages/commonwealth/server/controllers/server_comments_controller.ts +++ b/packages/commonwealth/server/controllers/server_comments_controller.ts @@ -1,9 +1,9 @@ import { DB } from '../models'; import BanCache from '../util/banCheckCache'; -import { TokenBalanceCache as TokenBalanceCacheV1 } from '../../../token-balance-cache/src'; import GlobalActivityCache from '../util/globalActivityCache'; -import { TokenBalanceCache as TokenBalanceCacheV2 } from '../util/tokenBalanceCache/tokenBalanceCache'; +import { TokenBalanceCache } from '../util/tokenBalanceCache/tokenBalanceCache'; + import { CreateCommentReactionOptions, CreateCommentReactionResult, @@ -32,8 +32,7 @@ import { export class ServerCommentsController { constructor( public models: DB, - public tokenBalanceCacheV1: TokenBalanceCacheV1, - public tokenBalanceCacheV2: TokenBalanceCacheV2, + public tokenBalanceCache: TokenBalanceCache, public banCache: BanCache, public globalActivityCache?: GlobalActivityCache, ) {} diff --git a/packages/commonwealth/server/controllers/server_comments_methods/create_comment_reaction.ts b/packages/commonwealth/server/controllers/server_comments_methods/create_comment_reaction.ts index 848e4ac81a3..ae7fcf30f12 100644 --- a/packages/commonwealth/server/controllers/server_comments_methods/create_comment_reaction.ts +++ b/packages/commonwealth/server/controllers/server_comments_methods/create_comment_reaction.ts @@ -97,7 +97,7 @@ export async function __createCommentReaction( try { const { isValid } = await validateTopicGroupsMembership( this.models, - this.tokenBalanceCacheV2, + this.tokenBalanceCache, thread.topic_id, community, address, diff --git a/packages/commonwealth/server/controllers/server_communities_controller.ts b/packages/commonwealth/server/controllers/server_communities_controller.ts index 1fc60c15111..7e3da279f31 100644 --- a/packages/commonwealth/server/controllers/server_communities_controller.ts +++ b/packages/commonwealth/server/controllers/server_communities_controller.ts @@ -1,4 +1,3 @@ -import { TokenBalanceCache } from '../../../token-balance-cache/src'; import { DB } from '../models'; import BanCache from '../util/banCheckCache'; import { @@ -46,11 +45,7 @@ import { * Implements methods related to communities */ export class ServerCommunitiesController { - constructor( - public models: DB, - public tokenBalanceCache: TokenBalanceCache, - public banCache: BanCache, - ) {} + constructor(public models: DB, public banCache: BanCache) {} async searchCommunities( options: SearchCommunitiesOptions, diff --git a/packages/commonwealth/server/controllers/server_groups_controller.ts b/packages/commonwealth/server/controllers/server_groups_controller.ts index a5ee678a16a..4ebe0f56432 100644 --- a/packages/commonwealth/server/controllers/server_groups_controller.ts +++ b/packages/commonwealth/server/controllers/server_groups_controller.ts @@ -1,7 +1,6 @@ -import { TokenBalanceCache as TokenBalanceCacheV1 } from '../../../token-balance-cache/src'; import { DB } from '../models'; import BanCache from '../util/banCheckCache'; -import { TokenBalanceCache as TokenBalanceCacheV2 } from '../util/tokenBalanceCache/tokenBalanceCache'; +import { TokenBalanceCache } from '../util/tokenBalanceCache/tokenBalanceCache'; import { CreateGroupOptions, CreateGroupResult, @@ -39,8 +38,7 @@ import { export class ServerGroupsController { constructor( public models: DB, - public tokenBalanceCacheV1: TokenBalanceCacheV1, - public tokenBalanceCacheV2: TokenBalanceCacheV2, + public tokenBalanceCache: TokenBalanceCache, public banCache: BanCache, ) {} diff --git a/packages/commonwealth/server/controllers/server_groups_methods/refresh_community_memberships.ts b/packages/commonwealth/server/controllers/server_groups_methods/refresh_community_memberships.ts index b5482362d67..e991e8e5794 100644 --- a/packages/commonwealth/server/controllers/server_groups_methods/refresh_community_memberships.ts +++ b/packages/commonwealth/server/controllers/server_groups_methods/refresh_community_memberships.ts @@ -62,7 +62,7 @@ export async function __refreshCommunityMemberships( getBalancesOptions.map(async (options) => { let result: Balances = {}; try { - result = await this.tokenBalanceCacheV2.getBalances({ + result = await this.tokenBalanceCache.getBalances({ ...options, cacheRefresh: false, // get cached balances }); diff --git a/packages/commonwealth/server/controllers/server_groups_methods/refresh_membership.ts b/packages/commonwealth/server/controllers/server_groups_methods/refresh_membership.ts index 1f226996597..a3ed176d405 100644 --- a/packages/commonwealth/server/controllers/server_groups_methods/refresh_membership.ts +++ b/packages/commonwealth/server/controllers/server_groups_methods/refresh_membership.ts @@ -45,7 +45,7 @@ export async function __refreshMembership( const memberships = await refreshMembershipsForAddress( this.models, - this.tokenBalanceCacheV2, + this.tokenBalanceCache, address, groups, true, // use fresh balances diff --git a/packages/commonwealth/server/controllers/server_polls_controller.ts b/packages/commonwealth/server/controllers/server_polls_controller.ts index 5fe9031d2c9..11fb49ec859 100644 --- a/packages/commonwealth/server/controllers/server_polls_controller.ts +++ b/packages/commonwealth/server/controllers/server_polls_controller.ts @@ -1,7 +1,6 @@ import { DB } from 'server/models'; -import { TokenBalanceCache as TokenBalanceCacheV1 } from '../../../token-balance-cache/src'; -import { TokenBalanceCache as TokenBalanceCacheV2 } from '../util/tokenBalanceCache/tokenBalanceCache'; +import { TokenBalanceCache } from '../util/tokenBalanceCache/tokenBalanceCache'; import { DeletePollOptions, @@ -24,11 +23,7 @@ import { * */ export class ServerPollsController { - constructor( - public models: DB, - public tokenBalanceCacheV1: TokenBalanceCacheV1, - public tokenBalanceCacheV2: TokenBalanceCacheV2, - ) {} + constructor(public models: DB, public tokenBalanceCache: TokenBalanceCache) {} async deletePoll(options: DeletePollOptions): Promise { return __deletePoll.call(this, options); diff --git a/packages/commonwealth/server/controllers/server_polls_methods/update_poll_vote.ts b/packages/commonwealth/server/controllers/server_polls_methods/update_poll_vote.ts index cee430dad72..1a2a497ff85 100644 --- a/packages/commonwealth/server/controllers/server_polls_methods/update_poll_vote.ts +++ b/packages/commonwealth/server/controllers/server_polls_methods/update_poll_vote.ts @@ -70,7 +70,7 @@ export async function __updatePollVote( // check token balance threshold if needed const { isValid } = await validateTopicGroupsMembership( this.models, - this.tokenBalanceCacheV2, + this.tokenBalanceCache, thread.topic_id, community, address, diff --git a/packages/commonwealth/server/controllers/server_threads_controller.ts b/packages/commonwealth/server/controllers/server_threads_controller.ts index 340d65881ec..75f05643479 100644 --- a/packages/commonwealth/server/controllers/server_threads_controller.ts +++ b/packages/commonwealth/server/controllers/server_threads_controller.ts @@ -1,9 +1,9 @@ import { DB } from '../models'; import BanCache from '../util/banCheckCache'; -import { TokenBalanceCache as TokenBalanceCacheV1 } from '../../../token-balance-cache/src'; import GlobalActivityCache from '../util/globalActivityCache'; -import { TokenBalanceCache as TokenBalanceCacheV2 } from '../util/tokenBalanceCache/tokenBalanceCache'; +import { TokenBalanceCache } from '../util/tokenBalanceCache/tokenBalanceCache'; + import { CreateThreadOptions, CreateThreadResult, @@ -66,8 +66,7 @@ import { export class ServerThreadsController { constructor( public models: DB, - public tokenBalanceCacheV1: TokenBalanceCacheV1, - public tokenBalanceCacheV2: TokenBalanceCacheV2, + public tokenBalanceCache: TokenBalanceCache, public banCache: BanCache, public globalActivityCache?: GlobalActivityCache, ) {} diff --git a/packages/commonwealth/server/controllers/server_threads_methods/create_thread.ts b/packages/commonwealth/server/controllers/server_threads_methods/create_thread.ts index 02606599214..a84efb1f1e2 100644 --- a/packages/commonwealth/server/controllers/server_threads_methods/create_thread.ts +++ b/packages/commonwealth/server/controllers/server_threads_methods/create_thread.ts @@ -179,7 +179,7 @@ export async function __createThread( if (!isAdmin) { const { isValid, message } = await validateTopicGroupsMembership( this.models, - this.tokenBalanceCacheV2, + this.tokenBalanceCache, topicId, community, address, diff --git a/packages/commonwealth/server/controllers/server_threads_methods/create_thread_comment.ts b/packages/commonwealth/server/controllers/server_threads_methods/create_thread_comment.ts index df53c35cc83..17069025730 100644 --- a/packages/commonwealth/server/controllers/server_threads_methods/create_thread_comment.ts +++ b/packages/commonwealth/server/controllers/server_threads_methods/create_thread_comment.ts @@ -138,7 +138,7 @@ export async function __createThreadComment( if (!isAdmin) { const { isValid, message } = await validateTopicGroupsMembership( this.models, - this.tokenBalanceCacheV2, + this.tokenBalanceCache, thread.topic_id, community, address, diff --git a/packages/commonwealth/server/controllers/server_threads_methods/create_thread_reaction.ts b/packages/commonwealth/server/controllers/server_threads_methods/create_thread_reaction.ts index 9bdbb767c30..ab93bc11f20 100644 --- a/packages/commonwealth/server/controllers/server_threads_methods/create_thread_reaction.ts +++ b/packages/commonwealth/server/controllers/server_threads_methods/create_thread_reaction.ts @@ -95,7 +95,7 @@ export async function __createThreadReaction( if (!isAdmin) { const { isValid, message } = await validateTopicGroupsMembership( this.models, - this.tokenBalanceCacheV2, + this.tokenBalanceCache, thread.topic_id, community, address, diff --git a/packages/commonwealth/server/routes/communities/putCommunities.ts b/packages/commonwealth/server/routes/communities/putCommunities.ts deleted file mode 100644 index f6d6a5efdb4..00000000000 --- a/packages/commonwealth/server/routes/communities/putCommunities.ts +++ /dev/null @@ -1,121 +0,0 @@ -import { AppError } from 'common-common/src/errors'; -import type { NextFunction } from 'express'; -import { body, validationResult } from 'express-validator'; -import type { TokenBalanceCache } from 'token-balance-cache/src'; -import type { - PutCommunitiesReq, - PutCommunitiesResp, -} from '../../api/extApiTypes'; -import { sequelize } from '../../database'; -import type { DB } from '../../models'; -import type { TypedRequest, TypedResponse } from '../../types'; -import { failure, success } from '../../types'; -import { createAddressHelper } from '../../util/createAddressHelper'; -import type { CreateAddressReq } from '../createAddress'; - -export const Errors = { - NeedPositiveBalance: 'Must provide address with positive balance', - NeedToSpecifyContract: - 'Must provide admin_addresses, contract.token_type, and contarct.address', -}; - -const optionalValidation = [ - body('contract.token_type').optional().isString().trim(), - body('contract.address').optional().isString().trim(), - body('admin_addresses').optional().isArray(), -]; - -export const putCommunitiesValidation = [ - body('community.id').exists().isString().trim(), - body('community.name').exists().isString().trim(), - body('community.chain_node_id').exists().isNumeric(), - body('community.default_symbol').exists().isString().trim(), - body('community.network').exists().isString().trim(), - body('community.type').exists().isString().trim(), - body('community.created_at').not().exists(), - body('community.updated_at').not().exists(), - body('community.deleted_at').not().exists(), - ...optionalValidation, -]; - -export async function putCommunities( - models: DB, - tbc: TokenBalanceCache, - req: TypedRequest, - res: TypedResponse, - next: NextFunction, -) { - const errors = validationResult(req).array(); - if (errors.length !== 0) { - return failure(res.status(400), errors); - } - - const { community, contract, admin_addresses } = req.body; - - const transaction = await sequelize.transaction(); - let error = ''; - try { - await models.Community.create(community); - // if optionalValidation route is used, check for positive balance in address provided - if (contract) { - if (!contract.token_type || !contract.address || !admin_addresses) { - throw new AppError(Errors.NeedToSpecifyContract); - } - - const [{ bp }] = await tbc.getBalanceProviders(community.chain_node_id); - const balanceResults = await tbc.getBalancesForAddresses( - community.chain_node_id, - admin_addresses, - bp, - { - contractType: contract.token_type, - tokenAddress: contract.address, - }, - ); - - let positiveBalance = false; - for (const balance of Object.values(balanceResults.balances)) { - if (balance !== '0') { - positiveBalance = true; - break; - } - } - - if (!positiveBalance) { - throw new AppError(Errors.NeedPositiveBalance); - } - - // create address for each admin_address, and assign to admin role - await Promise.all( - admin_addresses.map(async (address) => { - const r: CreateAddressReq = { - address, - chain: community.id, - community: community.id, - wallet_id: null, - wallet_sso_source: null, - }; - - const newAddress = await createAddressHelper( - r, - models, - req.user, - next, - ); - await models.Address.update( - { role: 'admin' }, - { where: { id: (newAddress as any).id } }, - ); - }), - ); - } - - await transaction.commit(); - } catch (e) { - error = e.message; - await transaction.rollback(); - } - - const url = `https://commonwealth.im/${community.id}`; - return success(res, { url, error }); -} diff --git a/packages/commonwealth/server/routes/getBalanceProviders.ts b/packages/commonwealth/server/routes/getBalanceProviders.ts deleted file mode 100644 index c289a929b26..00000000000 --- a/packages/commonwealth/server/routes/getBalanceProviders.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { query, validationResult } from 'express-validator'; -import type { DB } from 'server/models'; -import type { TokenBalanceCache } from 'token-balance-cache/src'; -import type { - GetBalanceProvidersReq, - GetBalanceProvidersResp, -} from '../api/extApiTypes'; -import type { TypedRequestQuery, TypedResponse } from '../types'; -import { failure, success } from '../types'; - -export const getBalanceProvidersValidation = [ - query('chain_node_ids').exists().toInt().toArray(), -]; - -export const getBalanceProviders = async ( - models: DB, - tbc: TokenBalanceCache, - req: TypedRequestQuery, - res: TypedResponse, -) => { - const errors = validationResult(req).array(); - if (errors.length !== 0) { - return failure(res.status(400), errors); - } - - const { chain_node_ids } = req.query; - - const balanceProviders = await Promise.all( - chain_node_ids.map((id) => tbc.getBalanceProviders(id)), - ); - - return success(res, { - balance_providers: balanceProviders.flat(), - count: balanceProviders.length, - }); -}; diff --git a/packages/commonwealth/server/routes/getChainNodes.ts b/packages/commonwealth/server/routes/getChainNodes.ts deleted file mode 100644 index 2059dd671c4..00000000000 --- a/packages/commonwealth/server/routes/getChainNodes.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { oneOf, query, validationResult } from 'express-validator'; -import type { DB } from 'server/models'; -import type { ChainNodeResp, TokenBalanceCache } from 'token-balance-cache/src'; -import type { GetChainNodesReq, GetChainNodesResp } from '../api/extApiTypes'; -import { needParamErrMsg } from '../api/extApiTypes'; -import type { TypedRequestQuery, TypedResponse } from '../types'; -import { failure, success } from '../types'; - -export const getChainNodesValidation = [ - oneOf( - [ - query('chain_node_ids').exists().toInt().toArray(), - query('names').exists().toArray(), - ], - `${needParamErrMsg} (chain_node_ids, names)`, - ), - query('count_only').optional().isBoolean().toBoolean(), -]; -export const getChainNodes = async ( - models: DB, - tbc: TokenBalanceCache, - req: TypedRequestQuery, - res: TypedResponse, -) => { - const errors = validationResult(req).array(); - if (errors.length !== 0) { - return failure(res.status(400), errors); - } - const { chain_node_ids, names } = req.query; - - let chainNodes: ChainNodeResp[] = await tbc.getChainNodes(); - if (chain_node_ids) - chainNodes = chainNodes.filter((c) => chain_node_ids.includes(c.id)); - if (names) chainNodes = chainNodes.filter((c) => names.includes(c.name)); - - return success(res, { chain_nodes: chainNodes, count: chainNodes.length }); -}; diff --git a/packages/commonwealth/server/routing/external.ts b/packages/commonwealth/server/routing/external.ts index 7636daf1543..dff278d9ac1 100644 --- a/packages/commonwealth/server/routing/external.ts +++ b/packages/commonwealth/server/routing/external.ts @@ -2,7 +2,6 @@ import type { Express } from 'express'; import express from 'express'; import type Router from 'express/lib/router/index'; import passport from 'passport'; -import type { TokenBalanceCache } from 'token-balance-cache/src'; import type { PostReactionsReq, PostTopicsReq, @@ -17,19 +16,7 @@ import { import getCommunities, { getCommunitiesValidation, } from '../routes/communities/getCommunities'; -import { - putCommunities, - putCommunitiesValidation, -} from '../routes/communities/putCommunities'; import { deleteEntities } from '../routes/deleteEntities'; -import { - getBalanceProviders, - getBalanceProvidersValidation, -} from '../routes/getBalanceProviders'; -import { - getChainNodes, - getChainNodesValidation, -} from '../routes/getChainNodes'; import getProfiles, { getProfilesValidation, } from '../routes/profiles/getProfiles'; @@ -51,7 +38,6 @@ export function addExternalRoutes( endpoint: string, app: Express, models: DB, - tokenBalanceCache: TokenBalanceCache, ): Router { const router = express.Router(); @@ -110,11 +96,6 @@ export function addExternalRoutes( getCommunitiesValidation, getCommunities.bind(this, models), ); - router.put( - '/communities', - putCommunitiesValidation, - putCommunities.bind(this, models, tokenBalanceCache), - ); router.get( '/profiles', @@ -140,17 +121,6 @@ export function addExternalRoutes( deleteEntities.bind(this, 'community_id', models, models.Topic), ); - router.get( - '/chainNodes', - getChainNodesValidation, - getChainNodes.bind(this, models, tokenBalanceCache), - ); - router.get( - '/balanceProviders', - getBalanceProvidersValidation, - getBalanceProviders.bind(this, models, tokenBalanceCache), - ); - app.use(endpoint, router); return router; diff --git a/packages/commonwealth/server/routing/router.ts b/packages/commonwealth/server/routing/router.ts index 141a58617f6..578ba7583ba 100644 --- a/packages/commonwealth/server/routing/router.ts +++ b/packages/commonwealth/server/routing/router.ts @@ -4,10 +4,7 @@ import express from 'express'; import useragent from 'express-useragent'; import passport from 'passport'; -import { TBC_BALANCE_TTL_SECONDS } from '../config'; - -import { TokenBalanceCache } from 'token-balance-cache/src/index'; -import { TokenBalanceCache as NewTokenBalanceCache } from '../util/tokenBalanceCache/tokenBalanceCache'; +import { TokenBalanceCache } from '../util/tokenBalanceCache/tokenBalanceCache'; import { methodNotAllowedMiddleware, @@ -205,32 +202,23 @@ function setupRouter( app: Express, models: DB, viewCountCache: ViewCountCache, - tokenBalanceCacheV1: TokenBalanceCache, + tokenBalanceCache: TokenBalanceCache, banCache: BanCache, globalActivityCache: GlobalActivityCache, databaseValidationService: DatabaseValidationService, redisCache: RedisCache, ) { // controllers - - const tokenBalanceCacheV2 = new NewTokenBalanceCache( - models, - redisCache, - TBC_BALANCE_TTL_SECONDS, - ); - const serverControllers: ServerControllers = { threads: new ServerThreadsController( models, - tokenBalanceCacheV1, - tokenBalanceCacheV2, + tokenBalanceCache, banCache, globalActivityCache, ), comments: new ServerCommentsController( models, - tokenBalanceCacheV1, - tokenBalanceCacheV2, + tokenBalanceCache, banCache, globalActivityCache, ), @@ -238,23 +226,10 @@ function setupRouter( notifications: new ServerNotificationsController(models), analytics: new ServerAnalyticsController(), profiles: new ServerProfilesController(models), - communities: new ServerCommunitiesController( - models, - tokenBalanceCacheV1, - banCache, - ), - polls: new ServerPollsController( - models, - tokenBalanceCacheV1, - tokenBalanceCacheV2, - ), + communities: new ServerCommunitiesController(models, banCache), + polls: new ServerPollsController(models, tokenBalanceCache), proposals: new ServerProposalsController(models, redisCache), - groups: new ServerGroupsController( - models, - tokenBalanceCacheV1, - tokenBalanceCacheV2, - banCache, - ), + groups: new ServerGroupsController(models, tokenBalanceCache, banCache), topics: new ServerTopicsController(models, banCache), admin: new ServerAdminController(models), }; diff --git a/packages/commonwealth/test/integration/api/chainNodes.spec.ts b/packages/commonwealth/test/integration/api/chainNodes.spec.ts index dc41d167361..8f6b63b3912 100644 --- a/packages/commonwealth/test/integration/api/chainNodes.spec.ts +++ b/packages/commonwealth/test/integration/api/chainNodes.spec.ts @@ -12,7 +12,7 @@ describe('ChainNode Tests', () => { }); it('Creates new ChainNode when', async () => { - const controller = new ServerCommunitiesController(models, null, null); + const controller = new ServerCommunitiesController(models, null); const user: UserInstance = buildUser({ models, userAttributes: { email: '', id: 1, isAdmin: true }, diff --git a/packages/commonwealth/test/integration/api/createChain.spec.ts b/packages/commonwealth/test/integration/api/createChain.spec.ts index 42ae6d1ed88..a22cdf4c9ad 100644 --- a/packages/commonwealth/test/integration/api/createChain.spec.ts +++ b/packages/commonwealth/test/integration/api/createChain.spec.ts @@ -7,11 +7,18 @@ import { buildUser } from '../../unit/unitHelpers'; describe('create chain tests', () => { it('fails when no eth_chain_id is provided when chain is ethereum', async () => { - const controller = new ServerCommunitiesController(models, null, null); - const user: UserInstance = - buildUser({ models, userAttributes: { email: '', id: 1, isAdmin: true } }) as UserInstance; + const controller = new ServerCommunitiesController(models, null); + const user: UserInstance = buildUser({ + models, + userAttributes: { email: '', id: 1, isAdmin: true }, + }) as UserInstance; try { - await controller.createChainNode({ user, url: 'wss://', name: 'test', balanceType: 'ethereum' }); + await controller.createChainNode({ + user, + url: 'wss://', + name: 'test', + balanceType: 'ethereum', + }); } catch (e) { assert.equal(e.status, 400); assert.equal(e.message, Errors.ChainIdNaN); @@ -22,13 +29,19 @@ describe('create chain tests', () => { }); it('fails when eth_chain_id is not a number', async () => { - const controller = new ServerCommunitiesController(models, null, null); - const user: UserInstance = - buildUser({ models, userAttributes: { email: '', id: 1, isAdmin: true } }) as UserInstance; + const controller = new ServerCommunitiesController(models, null); + const user: UserInstance = buildUser({ + models, + userAttributes: { email: '', id: 1, isAdmin: true }, + }) as UserInstance; try { - await controller.createChainNode( - { user, url: 'wss://', balanceType: 'ethereum', name: 'test', eth_chain_id: 'test' as unknown as number } - ); + await controller.createChainNode({ + user, + url: 'wss://', + balanceType: 'ethereum', + name: 'test', + eth_chain_id: 'test' as unknown as number, + }); } catch (e) { assert.equal(e.status, 400); assert.equal(e.message, Errors.ChainIdNaN); @@ -37,4 +50,4 @@ describe('create chain tests', () => { assert.fail(0, 1, 'Exception not thrown'); }); -}); \ No newline at end of file +}); diff --git a/packages/commonwealth/test/integration/api/external/appHook.spec.ts b/packages/commonwealth/test/integration/api/external/appHook.spec.ts index 444355db008..7db6c5e5b62 100644 --- a/packages/commonwealth/test/integration/api/external/appHook.spec.ts +++ b/packages/commonwealth/test/integration/api/external/appHook.spec.ts @@ -9,7 +9,6 @@ import passport from 'passport'; import { SESSION_SECRET } from 'server/config'; import models from 'server/database'; import { addExternalRoutes } from 'server/routing/external'; -import { tokenBalanceCache } from 'test/integration/api/external/cacheHooks.spec'; import setupPassport from '../../../../server/passport/index'; chai.use(chaiHttp); @@ -42,14 +41,14 @@ before(async () => { app.use(passport.initialize()); app.use(passport.session()); - addExternalRoutes('/api', app, models, tokenBalanceCache); + addExternalRoutes('/api', app, models); }); export async function get( path: string, val: Record = null, expectError = false, - passedApp = app + passedApp = app, ) { const res = ( await chai @@ -72,7 +71,7 @@ export async function put( path: string, val: Record, expectError = false, - passedApp = app + passedApp = app, ) { const res = ( await chai @@ -95,7 +94,7 @@ export async function post( path: string, val: Record, expectError = false, - expectedApp = app + expectedApp = app, ) { const res = ( await chai @@ -118,7 +117,7 @@ export async function del( path: string, val: Record, expectError = false, - expectedApp = app + expectedApp = app, ) { const res = ( await chai diff --git a/packages/commonwealth/test/integration/api/external/cacheHooks.spec.ts b/packages/commonwealth/test/integration/api/external/cacheHooks.spec.ts deleted file mode 100644 index 71a17fe1cb0..00000000000 --- a/packages/commonwealth/test/integration/api/external/cacheHooks.spec.ts +++ /dev/null @@ -1,65 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-vars */ -import { BalanceType } from '@hicommonwealth/core'; -import type BN from 'bn.js'; -import type { IChainNode } from 'token-balance-cache/src'; -import { BalanceProvider, TokenBalanceCache } from 'token-balance-cache/src'; - -class MockTokenBalanceProvider extends BalanceProvider< - any, - { - tokenAddress: string; - contractType: string; - } -> { - public name = 'eth-token'; - public opts = { - tokenAddress: 'string', - contractType: 'string', - }; - public validBases = [BalanceType.Ethereum]; - public balanceFn: (tokenAddress: string, userAddress: string) => Promise; - - public getExternalProvider( - node: IChainNode, - opts: { tokenAddress: string; contractType: string }, - ): Promise { - return; - } - - public async getBalance( - node: IChainNode, - address: string, - opts: { tokenAddress: string; contractType: string }, - ): Promise { - if (this.balanceFn) { - const bal = await this.balanceFn(opts.tokenAddress, address); - return bal.toString(); - } else { - throw new Error('unable to fetch token balance'); - } - } -} - -export let tokenBalanceCache: TokenBalanceCache; -export let tokenProvider: MockTokenBalanceProvider; -before(async () => { - const node: IChainNode[] = [ - { - balance_type: BalanceType.Ethereum, - id: -1, - name: 'testNode', - url: '', - description: '', - bech32: '', - }, - ]; - - tokenProvider = new MockTokenBalanceProvider(); - tokenBalanceCache = new TokenBalanceCache( - 0, - 0, - [tokenProvider], - (_: number) => new Promise((res) => res(node)), - ); - await tokenBalanceCache.start(); -}); diff --git a/packages/commonwealth/test/integration/api/external/getBalanceProviders.spec.ts b/packages/commonwealth/test/integration/api/external/getBalanceProviders.spec.ts deleted file mode 100644 index 3fd36844b2c..00000000000 --- a/packages/commonwealth/test/integration/api/external/getBalanceProviders.spec.ts +++ /dev/null @@ -1,28 +0,0 @@ -import chai from 'chai'; -import type { GetBalanceProvidersReq } from 'server/api/extApiTypes'; -import models from 'server/database'; -import { getBalanceProviders } from 'server/routes/getBalanceProviders'; -import { tokenBalanceCache } from 'test/integration/api/external/cacheHooks.spec'; -import { getReq, res } from 'test/unit/unitHelpers'; - -describe('getTokenBalance Tests', async () => { - it('returns correct token balance', async () => { - const r: GetBalanceProvidersReq = { - chain_node_ids: [(await tokenBalanceCache.getChainNodes())[0].id], - }; - - const resp = (await getBalanceProviders( - models, - tokenBalanceCache, - getReq(r), - res(), - )) as any; - - chai.assert.lengthOf(resp.result.balance_providers, 1); - chai.assert.equal(resp.result.balance_providers[0].bp, 'eth-token'); - chai.assert.deepEqual(resp.result.balance_providers[0].opts, { - tokenAddress: 'string', - contractType: 'string', - }); - }); -}); diff --git a/packages/commonwealth/test/integration/api/external/getChainNodes.spec.ts b/packages/commonwealth/test/integration/api/external/getChainNodes.spec.ts deleted file mode 100644 index b9712efd1ae..00000000000 --- a/packages/commonwealth/test/integration/api/external/getChainNodes.spec.ts +++ /dev/null @@ -1,52 +0,0 @@ -import chai from 'chai'; -import 'chai/register-should'; -import type { GetChainNodesReq } from 'server/api/extApiTypes'; -import { tokenBalanceCache } from 'test/integration/api/external/cacheHooks.spec'; -import { get } from './appHook.spec'; - -describe('getChainNodes Tests', () => { - it('should return chainNodes with specified chain_node_ids correctly', async () => { - const r: GetChainNodesReq = { - chain_node_ids: (await tokenBalanceCache.getChainNodes()).map( - (c) => c.id, - ), - }; - const resp = await get('/api/chainNodes', r, true); - - chai.assert.lengthOf(resp.result.chain_nodes, 1); - chai.assert.equal(resp.result.count, 1); - }); - - it('should return chainNodes with specified name correctly', async () => { - const r: GetChainNodesReq = { - names: (await tokenBalanceCache.getChainNodes()).map((c) => c.name), - }; - const resp = await get('/api/chainNodes', r, true); - - chai.assert.lengthOf(resp.result.chain_nodes, 1); - chai.assert.equal(resp.result.count, 1); - }); - - it('should handle errors correctly', async () => { - let resp = await get('/api/chainNodes', {}, true); - - chai.assert.lengthOf(resp.result, 1); - chai.assert.equal( - resp.result[0].msg, - 'Please provide a parameter to query by (chain_node_ids, names)', - ); - - resp = await get( - '/api/chainNodes', - { - names: (await tokenBalanceCache.getChainNodes()).map((c) => c.name), - count_only: 3, - }, - true, - ); - - chai.assert.lengthOf(resp.result, 1); - chai.assert.equal(resp.result[0].msg, 'Invalid value'); - chai.assert.equal(resp.result[0].param, 'count_only'); - }); -}); diff --git a/packages/commonwealth/test/integration/api/external/putCommunities.spec.ts b/packages/commonwealth/test/integration/api/external/putCommunities.spec.ts deleted file mode 100644 index 0b7e2383af8..00000000000 --- a/packages/commonwealth/test/integration/api/external/putCommunities.spec.ts +++ /dev/null @@ -1,45 +0,0 @@ -import chai from 'chai'; -import { Op } from 'sequelize'; -import models from 'server/database'; -import { put } from './appHook.spec'; -import { testChainNodes } from './dbEntityHooks.spec'; - -describe('putCommunities Tests', () => { - it('add entities to db', async () => { - chai.assert.equal( - await models.Community.count({ where: { id: { [Op.in]: ['-1'] } } }), - 0 - ); - - const resp = await put('/api/communities', { - community: { - id: 'testChain1', - name: 'testChain1', - network: 'cmntest', - type: 'offchain', - chain_node_id: testChainNodes[0].id, - default_symbol: 'test', - }, - }); - - chai.assert.equal(resp.result.error, ''); - chai.assert.equal( - await models.Community.count({ - where: { id: { [Op.in]: ['testChain1', 'testChain2'] } }, - }), - 1 - ); - }); - - it('fail on input error', async () => { - const resp = await put( - '/api/communities', - { - community: { bad: 3 }, - }, - true - ); - - chai.assert.equal(resp.status, 'Failure'); - }); -}); diff --git a/packages/commonwealth/test/integration/api/getRelatedCommunities.spec.ts b/packages/commonwealth/test/integration/api/getRelatedCommunities.spec.ts index 5cfa2a57da6..ded129febfb 100644 --- a/packages/commonwealth/test/integration/api/getRelatedCommunities.spec.ts +++ b/packages/commonwealth/test/integration/api/getRelatedCommunities.spec.ts @@ -1,7 +1,7 @@ import { assert } from 'chai'; +import models from 'server/database'; import { ServerCommunitiesController } from '../../../server/controllers/server_communities_controller'; import { resetDatabase } from '../../util/resetDatabase'; -import models from 'server/database'; describe('GetRelatedCommunities Tests', () => { before(async () => { @@ -9,34 +9,41 @@ describe('GetRelatedCommunities Tests', () => { }); it('Correctly returns nothing if base does not match chainNode', async () => { - const controller = new ServerCommunitiesController(models, null, null); - const response = await controller.getRelatedCommunities({ chainNodeId: -100 }) + const controller = new ServerCommunitiesController(models, null); + const response = await controller.getRelatedCommunities({ + chainNodeId: -100, + }); assert.equal(response.length, 0); }); it('Correctly returns results if base matches some chainNode.name', async () => { - const controller = new ServerCommunitiesController(models, null, null); - const response = await controller.getRelatedCommunities({ chainNodeId: 2 }) + const controller = new ServerCommunitiesController(models, null); + const response = await controller.getRelatedCommunities({ chainNodeId: 2 }); assert.equal(response.length, 3); - const ethereumCommunity = response.find(r => r.community === 'Ethereum'); + const ethereumCommunity = response.find((r) => r.community === 'Ethereum'); assert.equal(ethereumCommunity.address_count, 1); assert.equal(ethereumCommunity.thread_count, 0); assert.equal(ethereumCommunity.icon_url, '/static/img/protocols/eth.png'); assert.equal(ethereumCommunity.description, null); - const sushiCommunity = response.find(r => r.community === 'Sushi'); + const sushiCommunity = response.find((r) => r.community === 'Sushi'); assert.equal(sushiCommunity.address_count, 0); assert.equal(sushiCommunity.thread_count, 0); assert.equal(sushiCommunity.icon_url, '/static/img/protocols/eth.png'); assert.equal(sushiCommunity.description, 'sushi community description'); - const yearnFinanceCommunity = response.find(r => r.community === 'yearn.finance'); + const yearnFinanceCommunity = response.find( + (r) => r.community === 'yearn.finance', + ); assert.equal(yearnFinanceCommunity.address_count, 0); assert.equal(yearnFinanceCommunity.thread_count, 0); - assert.equal(yearnFinanceCommunity.icon_url, '/static/img/protocols/eth.png'); + assert.equal( + yearnFinanceCommunity.icon_url, + '/static/img/protocols/eth.png', + ); assert.equal(yearnFinanceCommunity.description, null); }); -}); \ No newline at end of file +}); diff --git a/packages/commonwealth/test/integration/api/tokenForum.spec.ts b/packages/commonwealth/test/integration/api/tokenForum.spec.ts deleted file mode 100644 index f454c6b9417..00000000000 --- a/packages/commonwealth/test/integration/api/tokenForum.spec.ts +++ /dev/null @@ -1,214 +0,0 @@ -/* eslint-disable global-require */ -import BN from 'bn.js'; -/* eslint-disable no-unused-expressions */ -import chai from 'chai'; -import chaiHttp from 'chai-http'; -import 'chai/register-should'; -import jwt from 'jsonwebtoken'; -import type { TokenBalanceCache } from 'token-balance-cache/src/index'; -import { - getMockBalanceProvider, - getTokenBalanceCache, - resetDatabase, -} from '../../../server-test'; -import { JWT_SECRET } from '../../../server/config'; -import { markdownComment } from '../../util/fixtures/markdownComment'; -import * as modelUtils from '../../util/modelUtils'; - -chai.use(chaiHttp); -const { expect } = chai; - -describe('Token Forum tests', () => { - const chain = 'alex'; - // The createThread util uses the chainId parameter to determine - // author_chain, which is required for authorship lookup. - // Therefore, a valid chain MUST be included alongside - // communityId, unlike in non-test thread creation - const title = 'test title'; - const body = 'test body'; - const topicName = 'test topic'; - const topicId = undefined; - const kind = 'discussion'; - const stage = 'discussion'; - - let adminJWT; - let adminAddress; - let adminAddressId; - let adminSession; - - let userJWT; - let userId; - let userAddress; - let userAddressId; - let userSession; - - let thread; - let tbc: TokenBalanceCache; - let tokenProvider: modelUtils.MockTokenBalanceProvider; - - before(async () => { - await resetDatabase(); - let res = await modelUtils.createAndVerifyAddress({ chain }); - adminAddress = res.address; - adminAddressId = res.address_id; - adminJWT = jwt.sign({ id: res.user_id, email: res.email }, JWT_SECRET); - adminSession = { session: res.session, sign: res.sign }; - const isAdmin = await modelUtils.updateRole({ - address_id: res.address_id, - chainOrCommObj: { chain_id: chain }, - role: 'admin', - }); - expect(adminAddress).to.not.be.null; - expect(adminJWT).to.not.be.null; - expect(isAdmin).to.not.be.null; - - res = await modelUtils.createAndVerifyAddress({ chain }); - userAddress = res.address; - userId = res.user_id; - userAddressId = res.address_id; - userJWT = jwt.sign({ id: res.user_id, email: res.email }, JWT_SECRET); - userSession = { session: res.session, sign: res.sign }; - expect(userAddress).to.not.be.null; - expect(userJWT).to.not.be.null; - - tbc = getTokenBalanceCache(); - tokenProvider = getMockBalanceProvider(); - }); - - beforeEach(async () => { - await tbc.reset(); - }); - - it('should permit token-holder to take actions on token forum', async () => { - // everyone is a token holder - tokenProvider.balanceFn = async () => new BN(1); - - // create a thread - const res = await modelUtils.createThread({ - address: userAddress, - kind, - stage, - chainId: chain, - title, - topicName, - topicId, - body, - jwt: userJWT, - session: userSession.session, - sign: userSession.sign, - }); - expect(res.status).to.equal('Success'); - expect(res.result).to.not.be.null; - expect(res.result.title).to.equal(encodeURIComponent(title)); - expect(res.result.body).to.equal(encodeURIComponent(body)); - expect(res.result.Address).to.not.be.null; - expect(res.result.Address.address).to.equal(userAddress); - - // create a comment - const cRes = await modelUtils.createComment({ - chain, - address: userAddress, - jwt: userJWT, - text: markdownComment.text, - thread_id: res.result.id, - session: userSession.session, - sign: userSession.sign, - }); - - expect(cRes.status).to.equal('Success'); - expect(cRes.result).to.not.be.null; - expect(cRes.result.thread_id).to.equal(res.result.id); - expect(cRes.result.text).to.equal(markdownComment.text); - expect(cRes.result.Address).to.not.be.null; - expect(cRes.result.Address.address).to.equal(userAddress); - }); - - xit('should not permit non-token-holder to take actions on token forum', async () => { - // nobody is a token holder - tokenProvider.balanceFn = async () => new BN(0); - - // fail to create a thread - const res = await modelUtils.createThread({ - address: userAddress, - kind, - stage, - chainId: chain, - title, - topicName, - topicId, - body, - jwt: userJWT, - session: userSession.session, - sign: userSession.sign, - }); - expect(res).not.to.be.null; - expect(res.error).not.to.be.null; - }); - - xit('should gracefully deny actions on token forum on balance fetch failure', async () => { - // nobody is a token holder - tokenProvider.balanceFn = null; - - // fail to create a thread - const res = await modelUtils.createThread({ - address: userAddress, - kind, - stage, - chainId: chain, - title, - topicName, - topicId, - body, - jwt: userJWT, - session: userSession.session, - sign: userSession.sign, - }); - expect(res).not.to.be.null; - expect(res.error).not.to.be.null; - }); - - it('should permit admin to act even without tokens', async () => { - // nobody is a token holder - tokenProvider.balanceFn = async () => new BN(0); - - // create a thread - const res = await modelUtils.createThread({ - address: adminAddress, - kind, - stage, - chainId: chain, - title, - topicName, - topicId, - body, - jwt: adminJWT, - session: adminSession.session, - sign: adminSession.sign, - }); - - expect(res.status).to.equal('Success'); - expect(res.result).to.not.be.null; - expect(res.result.title).to.equal(encodeURIComponent(title)); - expect(res.result.body).to.equal(encodeURIComponent(body)); - expect(res.result.Address).to.not.be.null; - expect(res.result.Address.address).to.equal(adminAddress); - - // create a comment - const cRes = await modelUtils.createComment({ - chain, - address: adminAddress, - jwt: adminJWT, - text: markdownComment.text, - thread_id: res.result.id, - session: adminSession.session, - sign: adminSession.sign, - }); - - expect(cRes.status).to.equal('Success'); - expect(cRes.result).to.not.be.null; - expect(cRes.result.thread_id).to.equal(res.result.id); - expect(cRes.result.text).to.equal(markdownComment.text); - expect(cRes.result.Address).to.not.be.null; - expect(cRes.result.Address.address).to.equal(adminAddress); - }); -}); diff --git a/packages/commonwealth/test/integration/api/updateChain.spec.ts b/packages/commonwealth/test/integration/api/updateChain.spec.ts index e311110d99d..ed0f0d7acdb 100644 --- a/packages/commonwealth/test/integration/api/updateChain.spec.ts +++ b/packages/commonwealth/test/integration/api/updateChain.spec.ts @@ -26,7 +26,7 @@ describe('UpdateChain Tests', () => { }); it('Correctly updates chain', async () => { - const controller = new ServerCommunitiesController(models, null, null); + const controller = new ServerCommunitiesController(models, null); const user: UserInstance = buildUser({ models, userAttributes: { email: '', id: 1, isAdmin: true }, diff --git a/packages/commonwealth/test/unit/server_controllers/server_comments_controller.spec.ts b/packages/commonwealth/test/unit/server_controllers/server_comments_controller.spec.ts index 1f4f542c93b..7596b057a83 100644 --- a/packages/commonwealth/test/unit/server_controllers/server_comments_controller.spec.ts +++ b/packages/commonwealth/test/unit/server_controllers/server_comments_controller.spec.ts @@ -68,7 +68,6 @@ describe('ServerCommentsController', () => { const serverCommentsController = new ServerCommentsController( db as any, tokenBalanceCache as any, - tokenBalanceCache as any, banCache as any, ); @@ -181,7 +180,6 @@ describe('ServerCommentsController', () => { const serverCommentsController = new ServerCommentsController( db as any, tokenBalanceCache as any, - tokenBalanceCache as any, banCache as any, ); @@ -251,7 +249,6 @@ describe('ServerCommentsController', () => { const serverCommentsController = new ServerCommentsController( db as any, tokenBalanceCache as any, - tokenBalanceCache as any, banCache as any, ); @@ -326,7 +323,6 @@ describe('ServerCommentsController', () => { const serverCommentsController = new ServerCommentsController( db as any, tokenBalanceCache as any, - tokenBalanceCache as any, banCache as any, ); @@ -463,7 +459,6 @@ describe('ServerCommentsController', () => { const serverCommentsController = new ServerCommentsController( db as any, tokenBalanceCache as any, - tokenBalanceCache as any, banCache as any, ); @@ -499,7 +494,6 @@ describe('ServerCommentsController', () => { const serverCommentsController = new ServerCommentsController( db as any, tokenBalanceCache as any, - tokenBalanceCache as any, banCache as any, ); @@ -561,7 +555,6 @@ describe('ServerCommentsController', () => { const serverCommentsController = new ServerCommentsController( db as any, tokenBalanceCache as any, - tokenBalanceCache as any, banCache as any, ); @@ -663,7 +656,6 @@ describe('ServerCommentsController', () => { const serverCommentsController = new ServerCommentsController( db as any, tokenBalanceCache as any, - tokenBalanceCache as any, banCache as any, ); @@ -724,7 +716,6 @@ describe('ServerCommentsController', () => { const serverCommentsController = new ServerCommentsController( db as any, tokenBalanceCache as any, - tokenBalanceCache as any, banCache as any, ); @@ -775,7 +766,6 @@ describe('ServerCommentsController', () => { const serverCommentsController = new ServerCommentsController( db as any, tokenBalanceCache as any, - tokenBalanceCache as any, banCache as any, ); diff --git a/packages/commonwealth/test/unit/server_controllers/server_groups_controller.spec.ts b/packages/commonwealth/test/unit/server_controllers/server_groups_controller.spec.ts index 2528c118e3e..08572757c85 100644 --- a/packages/commonwealth/test/unit/server_controllers/server_groups_controller.spec.ts +++ b/packages/commonwealth/test/unit/server_controllers/server_groups_controller.spec.ts @@ -125,7 +125,6 @@ const createMockedGroupsController = () => { const controller = new ServerGroupsController( db, tokenBalanceCache, - tokenBalanceCache, banCache, ); return controller; diff --git a/packages/commonwealth/test/unit/server_controllers/server_threads_controller.spec.ts b/packages/commonwealth/test/unit/server_controllers/server_threads_controller.spec.ts index 1b3e7ea6563..8b8e92c6015 100644 --- a/packages/commonwealth/test/unit/server_controllers/server_threads_controller.spec.ts +++ b/packages/commonwealth/test/unit/server_controllers/server_threads_controller.spec.ts @@ -56,7 +56,6 @@ describe('ServerThreadsController', () => { const serverThreadsController = new ServerThreadsController( db as any, tokenBalanceCache as any, - tokenBalanceCache as any, banCache as any, ); @@ -157,7 +156,6 @@ describe('ServerThreadsController', () => { const serverThreadsController = new ServerThreadsController( db as any, tokenBalanceCache as any, - tokenBalanceCache as any, banCache as any, ); @@ -227,7 +225,6 @@ describe('ServerThreadsController', () => { const serverThreadsController = new ServerThreadsController( db as any, tokenBalanceCache as any, - tokenBalanceCache as any, banCache as any, ); @@ -296,7 +293,6 @@ describe('ServerThreadsController', () => { const serverThreadsController = new ServerThreadsController( db as any, tokenBalanceCache as any, - tokenBalanceCache as any, banCache as any, ); @@ -434,7 +430,6 @@ describe('ServerThreadsController', () => { const serverThreadsController = new ServerThreadsController( db as any, tokenBalanceCache as any, - tokenBalanceCache as any, banCache as any, ); @@ -534,7 +529,6 @@ describe('ServerThreadsController', () => { const serverThreadsController = new ServerThreadsController( db as any, tokenBalanceCache as any, - tokenBalanceCache as any, banCache as any, ); @@ -625,7 +619,6 @@ describe('ServerThreadsController', () => { const serverThreadsController = new ServerThreadsController( db as any, tokenBalanceCache as any, - tokenBalanceCache as any, banCache as any, ); @@ -703,7 +696,6 @@ describe('ServerThreadsController', () => { const serverThreadsController = new ServerThreadsController( db as any, tokenBalanceCache as any, - tokenBalanceCache as any, banCache as any, ); @@ -811,7 +803,6 @@ describe('ServerThreadsController', () => { const serverThreadsController = new ServerThreadsController( db as any, tokenBalanceCache as any, - tokenBalanceCache as any, banCache as any, ); @@ -875,7 +866,6 @@ describe('ServerThreadsController', () => { const serverThreadsController = new ServerThreadsController( db as any, tokenBalanceCache as any, - tokenBalanceCache as any, banCache as any, ); @@ -961,7 +951,6 @@ describe('ServerThreadsController', () => { const serverThreadsController = new ServerThreadsController( db as any, tokenBalanceCache as any, - tokenBalanceCache as any, banCache as any, ); @@ -1042,7 +1031,6 @@ describe('ServerThreadsController', () => { const serverThreadsController = new ServerThreadsController( db as any, tokenBalanceCache as any, - tokenBalanceCache as any, banCache as any, ); @@ -1116,7 +1104,6 @@ describe('ServerThreadsController', () => { const serverThreadsController = new ServerThreadsController( db as any, tokenBalanceCache as any, - tokenBalanceCache as any, banCache as any, ); const user = { @@ -1165,7 +1152,6 @@ describe('ServerThreadsController', () => { const serverThreadsController = new ServerThreadsController( db as any, tokenBalanceCache as any, - tokenBalanceCache as any, banCache as any, ); const user = { @@ -1214,7 +1200,6 @@ describe('ServerThreadsController', () => { const serverThreadsController = new ServerThreadsController( db as any, tokenBalanceCache as any, - tokenBalanceCache as any, banCache as any, ); const user = { @@ -1262,7 +1247,6 @@ describe('ServerThreadsController', () => { const serverThreadsController = new ServerThreadsController( db as any, tokenBalanceCache as any, - tokenBalanceCache as any, banCache as any, ); const user = { @@ -1348,7 +1332,6 @@ describe('ServerThreadsController', () => { const serverThreadsController = new ServerThreadsController( db as any, tokenBalanceCache as any, - tokenBalanceCache as any, banCache as any, ); const user = { diff --git a/packages/commonwealth/test/unit/server_controllers/server_threads_controller.update_thread.spec.ts b/packages/commonwealth/test/unit/server_controllers/server_threads_controller.update_thread.spec.ts index 663bcbab7c6..9a9423d2e7e 100644 --- a/packages/commonwealth/test/unit/server_controllers/server_threads_controller.update_thread.spec.ts +++ b/packages/commonwealth/test/unit/server_controllers/server_threads_controller.update_thread.spec.ts @@ -129,7 +129,6 @@ describe('ServerThreadsController', () => { const serverThreadsController = new ServerThreadsController( db, tokenBalanceCache, - tokenBalanceCache, banCache, ); const [updatedThread, notificationOptions, analyticsOptions] = diff --git a/packages/commonwealth/test/util/modelUtils.ts b/packages/commonwealth/test/util/modelUtils.ts index 11ce0262fde..c012472ea8b 100644 --- a/packages/commonwealth/test/util/modelUtils.ts +++ b/packages/commonwealth/test/util/modelUtils.ts @@ -7,7 +7,7 @@ import type { Session, SessionPayload, } from '@canvas-js/interfaces'; -import { BalanceType, ChainBase, ChainNetwork } from '@hicommonwealth/core'; +import { ChainBase, ChainNetwork } from '@hicommonwealth/core'; import { SignTypedDataVersion, personalSign, @@ -15,7 +15,6 @@ import { } from '@metamask/eth-sig-util'; import { Keyring } from '@polkadot/api'; import { stringToU8a } from '@polkadot/util'; -import type BN from 'bn.js'; import chai from 'chai'; import 'chai/register-should'; import wallet from 'ethereumjs-wallet'; @@ -24,9 +23,6 @@ import { configure as configureStableStringify } from 'safe-stable-stringify'; import { createRole, findOneRole } from 'server/util/roles'; import * as siwe from 'siwe'; -import type { IChainNode } from 'token-balance-cache/src/index'; -import { BalanceProvider } from 'token-balance-cache/src/index'; - import { createCanvasSessionPayload } from '../../shared/canvas'; import { mnemonicGenerate } from '@polkadot/util-crypto'; @@ -67,7 +63,6 @@ export const createAndVerifyAddress = async ({ chain }, mnemonic = 'Alice') => { .set('Accept', 'application/json') .send({ address, chain, wallet_id, block_info: TEST_BLOCK_INFO_STRING }); const address_id = res.body.result.id; - const token = res.body.result.verification_token; const chain_id = chain === 'alex' ? '3' : '1'; // use ETH mainnet for testing except alex const sessionWallet = ethers.Wallet.createRandom(); const timestamp = 1665083987891; @@ -115,14 +110,11 @@ export const createAndVerifyAddress = async ({ chain }, mnemonic = 'Alice') => { email, session, sign: (actionPayload: ActionPayload) => { - const { types, primaryType, domain, message } = - getEIP712SignableAction(actionPayload); - const signature = signTypedData({ + return signTypedData({ privateKey: Buffer.from(sessionWallet.privateKey.slice(2), 'hex'), data: getEIP712SignableAction(actionPayload), version: SignTypedDataVersion.V4, }); - return signature; }, }; } @@ -184,8 +176,7 @@ export const createAndVerifyAddress = async ({ chain }, mnemonic = 'Alice') => { const signatureBytes = sessionWallet.sign( stringToU8a(sortedStringify(actionPayload)), ); - const signature = new Buffer(signatureBytes).toString('hex'); - return signature; + return new Buffer(signatureBytes).toString('hex'); }, }; } @@ -682,43 +673,6 @@ export const createCommunity = async (args: CommunityArgs) => { return community; }; -// always prune both token and non-token holders asap -export class MockTokenBalanceProvider extends BalanceProvider< - any, - { - tokenAddress: string; - contractType: string; - } -> { - public name = 'eth-token'; - public opts = { - tokenAddress: 'string', - contractType: 'string', - }; - public validBases = [BalanceType.Ethereum]; - public balanceFn: (tokenAddress: string, userAddress: string) => Promise; - - public async getExternalProvider( - node: IChainNode, - opts: { tokenAddress: string; contractType: string }, - ): Promise { - return; - } - - public async getBalance( - node: IChainNode, - address: string, - opts: { tokenAddress: string; contractType: string }, - ): Promise { - if (this.balanceFn) { - const bal = await this.balanceFn(opts.tokenAddress, address); - return bal.toString(); - } else { - throw new Error('unable to fetch token balance'); - } - } -} - export interface JoinCommunityArgs { jwt: string; address_id: number; diff --git a/packages/token-balance-cache/.gitignore b/packages/token-balance-cache/.gitignore deleted file mode 100644 index 2eea525d885..00000000000 --- a/packages/token-balance-cache/.gitignore +++ /dev/null @@ -1 +0,0 @@ -.env \ No newline at end of file diff --git a/packages/token-balance-cache/.mocharc.json b/packages/token-balance-cache/.mocharc.json deleted file mode 100644 index ef7f9fc1069..00000000000 --- a/packages/token-balance-cache/.mocharc.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "extension": [".spec.ts"], - "package": "./package.json", - "timeout": 60000, - "require": ["tsconfig-paths/register", "source-map-support/register"], - "exit": true -} diff --git a/packages/token-balance-cache/package.json b/packages/token-balance-cache/package.json deleted file mode 100644 index e0b8bf11e20..00000000000 --- a/packages/token-balance-cache/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "token-balance-cache", - "version": "0.0.0", - "private": true, - "engines": { - "node": "18.x" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/hicommonwealth/commonwealth.git" - }, - "keywords": [], - "scripts": { - "test": "ts-mocha --config ./.mocharc.json ./test/*.spec.ts", - "check-types": "tsc --noEmit" - }, - "dependencies": { - "@hicommonwealth/core": "*" - }, - "devDependencies": { - "@types/chai": "^4.3.4", - "@types/chai-as-promised": "^7.1.5", - "@types/mocha": "^10.0.1", - "chai": "^4.3.6", - "chai-as-promised": "^7.1.1", - "ts-mocha": "^10.0.0" - } -} diff --git a/packages/token-balance-cache/src/index.ts b/packages/token-balance-cache/src/index.ts deleted file mode 100644 index 0b6d1ab100e..00000000000 --- a/packages/token-balance-cache/src/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './tbc'; -export * from './types'; diff --git a/packages/token-balance-cache/src/providers/cosmos.ts b/packages/token-balance-cache/src/providers/cosmos.ts deleted file mode 100644 index 7571b63371a..00000000000 --- a/packages/token-balance-cache/src/providers/cosmos.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { fromBech32, toBech32 } from '@cosmjs/encoding'; -import type { BankExtension, StakingExtension } from '@cosmjs/stargate'; -import { - QueryClient, - setupBankExtension, - setupStakingExtension, -} from '@cosmjs/stargate'; -import { Tendermint34Client } from '@cosmjs/tendermint-rpc'; -import { BalanceType } from '@hicommonwealth/core'; - -import type { IChainNode } from '../types'; -import { BalanceProvider } from '../types'; - -export default class CosmosBalanceProvider extends BalanceProvider< - QueryClient & BankExtension & StakingExtension -> { - public name = 'cosmos'; - public opts = {}; - public validBases = [BalanceType.Cosmos]; - - public async getExternalProvider( - node: IChainNode, - ): Promise { - /* also do network === ChainNetwork.NativeCosmos / Terra or ChainNetwork.CosmosNFT => should check NFTs */ - const tmClient = await Tendermint34Client.connect( - node.private_url || node.url, - ); - - const api = QueryClient.withExtensions( - tmClient, - setupBankExtension, - setupStakingExtension, - ); - return api; - } - - public async getBalance(node: IChainNode, address: string): Promise { - // re-encode address if necessary - if (!node.bech32) { - throw new Error('No cosmos prefix found!'); - } - const { data } = fromBech32(address); - const encodedAddress = toBech32(node.bech32, data); - - const api = await this.getExternalProvider(node); - - try { - const { params } = await api.staking.params(); - const denom = params?.bondDenom; - if (!denom) { - throw new Error('Could not query staking params'); - } - // TODO: include staking balance alongside bank balance? - const bal = await api.bank.balance(encodedAddress, denom); - return bal.amount; - } catch (e) { - throw new Error(`no balance found: ${e.message}`); - } - } -} diff --git a/packages/token-balance-cache/src/providers/ethToken.ts b/packages/token-balance-cache/src/providers/ethToken.ts deleted file mode 100644 index 698fa2a5a60..00000000000 --- a/packages/token-balance-cache/src/providers/ethToken.ts +++ /dev/null @@ -1,84 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-vars */ -import { BalanceType } from '@hicommonwealth/core'; -import Web3 from 'web3'; -import type { WebsocketProvider } from 'web3-core'; -import type { EthBPOpts, IChainNode } from '../types'; -import { BalanceProvider } from '../types'; -import { validateOpts } from '../util/validateOpts'; - -export default class evmBalanceProvider extends BalanceProvider { - public name = 'eth-token'; - public opts = { - contractType: 'string?', - tokenAddress: 'string?', - tokenId: 'string?', - }; - - public validBases = [BalanceType.Ethereum]; - - private balanceSelectors = { erc20: '0x70a08231', erc1155: '0x8f32d59b' }; - - public getCacheKey(node: IChainNode, address: string, opts: any): string { - return opts.contractType - ? `${node.id}-${address}-${opts.tokenAddress}` - : `${node.id}-${address}-${'native'}`; - } - - public async getExternalProvider( - node: IChainNode, - opts: EthBPOpts, - ): Promise { - const node_url = node.private_url || node.url; - const provider = - node_url.slice(0, 4) == 'http' - ? new Web3.providers.HttpProvider(node_url) - : new Web3.providers.WebsocketProvider(node_url); - return new Web3(provider); - } - - public async getBalance( - node: IChainNode, - address: string, - opts: EthBPOpts, - ): Promise { - const { tokenAddress, contractType } = opts; - const Web3 = (await import('web3')).default; - const api = await this.getExternalProvider(node, opts); - if (!tokenAddress && !contractType) { - // Native Token flow - if (!Web3.utils.isAddress(address)) { - throw new Error('Invalid address'); - } - const balance = await api.eth.getBalance(address); - if (api.currentProvider instanceof Web3.providers.WebsocketProvider) - (api.currentProvider as WebsocketProvider).disconnect(1000, 'finished'); - // use native token if no args provided - return balance; - } - - let calldata; - if (contractType == 'erc20' || contractType == 'erc721') { - validateOpts(address, opts); - // function selector + calldata - const data = api.eth.abi - .encodeParameters(['address'], [address]) - .substring(2); - //console.log(data) - calldata = `${this.balanceSelectors.erc20}${data}`; - } else if (contractType == '1155') { - validateOpts(address, opts); - calldata = `${this.balanceSelectors.erc1155}${api.eth.abi - .encodeParameters(['address', 'uint256'], [address, opts.tokenId]) - .substring(2)}`; - } else { - throw new Error('Invalid Contract type'); - } - const result = await api.eth.call({ - to: tokenAddress, - data: calldata, - }); - if (api.currentProvider instanceof Web3.providers.WebsocketProvider) - (api.currentProvider as WebsocketProvider).disconnect(1000, 'finished'); - return api.eth.abi.decodeParameter('uint256', result).toString(); - } -} diff --git a/packages/token-balance-cache/src/providers/index.ts b/packages/token-balance-cache/src/providers/index.ts deleted file mode 100644 index a9eb0dd2e5d..00000000000 --- a/packages/token-balance-cache/src/providers/index.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { default as CosmosBalanceProvider } from './cosmos'; -import { default as EthTokenBalanceProvider } from './ethToken'; -import { default as RoninBalanceProvider } from './ronin'; -import { default as SplTokenBalanceProvider } from './splToken'; -import { default as TerraBalanceProvider } from './terra'; - -const providers = [ - new CosmosBalanceProvider(), - new EthTokenBalanceProvider(), - new RoninBalanceProvider(), - new SplTokenBalanceProvider(), - new TerraBalanceProvider(), -]; - -export default providers; diff --git a/packages/token-balance-cache/src/providers/ronin.ts b/packages/token-balance-cache/src/providers/ronin.ts deleted file mode 100644 index cc30b7b8240..00000000000 --- a/packages/token-balance-cache/src/providers/ronin.ts +++ /dev/null @@ -1,89 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-vars */ -import { BalanceType } from '@hicommonwealth/core'; -import BN from 'bn.js'; -import type { ERC20 } from 'common-common/src/eth/types'; -import { ERC20__factory } from 'common-common/src/eth/types'; -import { providers } from 'ethers'; -import Web3 from 'web3'; -import type { HttpProvider } from 'web3-core'; -import type { Contract } from 'web3-eth-contract'; -import type { AbiType, StateMutabilityType } from 'web3-utils'; -import type { IChainNode } from '../types'; -import { BalanceProvider } from '../types'; - -export default class RoninBalanceProvider extends BalanceProvider< - [ERC20, Contract] -> { - public name = 'ronin'; - public opts = {}; - public validBases = [BalanceType.AxieInfinity]; - // TODO graceful handling when the provider breaks or throw error - public async getExternalProvider( - node: IChainNode, - ): Promise<[api: ERC20, stakingContract: Contract]> { - // TODO: make configurable - const rpcUrl = 'https://api.roninchain.com/rpc'; - const provider = new Web3.providers.HttpProvider(rpcUrl); - const web3 = new Web3(provider); - const axsAddress = '0x97a9107c1793bc407d6f527b77e7fff4d812bece'; - const axsStakingPoolAddress = '05b0bb3c1c320b280501b86706c3551995bc8571'; - const axsApi = ERC20__factory.connect( - axsAddress, - new providers.Web3Provider(provider as any), - ); - await axsApi.deployed(); - - const axsStakingAbi = [ - { - constant: true, - inputs: [ - { - internalType: 'address', - name: '_user', - type: 'address', - }, - ], - name: 'getStakingAmount', - outputs: [ - { - internalType: 'uint256', - name: '', - type: 'uint256', - }, - ], - payable: false, - stateMutability: 'view' as StateMutabilityType, - type: 'function' as AbiType, - }, - ]; - const axsStakingPoolContract = new web3.eth.Contract( - axsStakingAbi, - axsStakingPoolAddress, - ); - - return [axsApi, axsStakingPoolContract]; - } - - public async getBalance(node: IChainNode, address: string): Promise { - if (!Web3.utils.isAddress(address)) { - throw new Error('Invalid address'); - } - - const [axsApi, axsStakingPoolContract] = await this.getExternalProvider( - node, - ); - - const axsBalanceBigNum = await axsApi.balanceOf(address); - - const stakingPoolBalance = await axsStakingPoolContract.methods - .getStakingAmount(address) - .call(); - - ( - (axsApi.provider as providers.Web3Provider).provider as HttpProvider - ).disconnect(); - return new BN(axsBalanceBigNum.toString()) - .add(new BN(stakingPoolBalance.toString())) - .toString(); - } -} diff --git a/packages/token-balance-cache/src/providers/splToken.ts b/packages/token-balance-cache/src/providers/splToken.ts deleted file mode 100644 index 6b2dea9ec93..00000000000 --- a/packages/token-balance-cache/src/providers/splToken.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { BalanceType } from '@hicommonwealth/core'; -import * as solw3 from '@solana/web3.js'; - -import type { IChainNode } from '../types'; -import { BalanceProvider } from '../types'; - -type SplTokenBPOpts = { - tokenAddress: string; -}; - -export default class SplTokenBalanceProvider extends BalanceProvider< - solw3.Connection, - SplTokenBPOpts -> { - public name = 'spl-token'; - public opts = { - tokenAddress: 'string', - }; - public validBases = [BalanceType.Solana]; - - public getCacheKey( - node: IChainNode, - address: string, - opts: SplTokenBPOpts, - ): string { - return `${address}-${node.url as solw3.Cluster}-${opts.tokenAddress}`; - } - - public async getExternalProvider( - node: IChainNode, - ): Promise { - const url = solw3.clusterApiUrl(node.url as solw3.Cluster); - const connection = new solw3.Connection(url); - return connection; - } - - public async getBalance( - node: IChainNode, - address: string, - opts: SplTokenBPOpts, - ): Promise { - const mintKey = new solw3.PublicKey(opts.tokenAddress); - if (mintKey.toBase58() !== opts.tokenAddress) { - throw new Error('Invalid token address'); - } - const addressKey = new solw3.PublicKey(address); - if (addressKey.toBase58() !== address) { - throw new Error('Invalid address'); - } - - const mintPubKey = new solw3.PublicKey(opts.tokenAddress); - const userPubKey = new solw3.PublicKey(address); - const connection = await this.getExternalProvider(node); - const { value } = await connection.getParsedTokenAccountsByOwner( - userPubKey, - { mint: mintPubKey }, - ); - const amount: string = - value[0]?.account?.data?.parsed?.info?.tokenAmount?.amount; - return amount; - } -} diff --git a/packages/token-balance-cache/src/providers/terra.ts b/packages/token-balance-cache/src/providers/terra.ts deleted file mode 100644 index ec8542b3d02..00000000000 --- a/packages/token-balance-cache/src/providers/terra.ts +++ /dev/null @@ -1,106 +0,0 @@ -import { fromBech32, toBech32 } from '@cosmjs/encoding'; -import { BalanceType } from '@hicommonwealth/core'; -import axios from 'axios'; -import BN from 'bn.js'; -import type { IChainNode } from '../types'; -import { BalanceProvider } from '../types'; - -export type TerraBalanceFn = (address: string) => Promise; - -export type StakedBalanceFn = (address: string) => Promise; - -export default class TerraBalanceProvider extends BalanceProvider< - [TerraBalanceFn, StakedBalanceFn] -> { - public name = 'terra'; - public opts = {}; - public validBases = [BalanceType.Terra]; - - public getExternalProvider( - node: IChainNode, - ): Promise<[TerraBalanceFn, StakedBalanceFn]> { - async function getTerraBalance(encodedAddress: string): Promise { - // make balance query - const queryUrl = `${ - node.private_url || node.url - }/cosmos/bank/v1beta1/balances/${encodedAddress}`; - - let bankBalance = new BN(0); - try { - // NOTE: terra.js staking module is incompatible with stargate queries - const balResp = await axios.get(queryUrl); // [ { denom: 'uluna', amount: '5000000' } ] - const balances: Array<{ denom: string; amount: string }> = - balResp?.data?.balances; - if (balances?.length > 0) { - const balanceObj = balances.find(({ denom }) => denom === 'uluna'); - if (balanceObj) { - bankBalance = new BN(balanceObj.amount); - return bankBalance; - } - } - } catch (e) { - throw new Error(`could not fetch terra bank balance: ${e.message}`); - } - } - - async function getTerraStakedBalance(encodedAddress: string): Promise { - // make staking query - let stakedBalance = new BN(0); - const stakedQueryUrl = `${ - node.private_url || node.url - }/cosmos/staking/v1beta1/delegations/${encodedAddress}`; - - try { - // NOTE: terra.js staking module is incompatible with stargate queries - // TODO: support pagination (currently few users, if any, will have enough delegations to trigger it) - const balResp = await axios.get(stakedQueryUrl); // [ { denom: 'uluna', amount: '5000000' } ] - const delegations: Array<{ - balance: { denom: string; amount: string }; - }> = balResp?.data?.delegation_responses; - - // sum all delegation balanaces to produce total staked balance - for (const delegation of delegations) { - if (delegation?.balance && delegation.balance.denom === 'uluna') { - stakedBalance = stakedBalance.add( - new BN(delegation.balance.amount), - ); - } - } - return stakedBalance; - } catch (e) { - throw new Error(`could not fetch staked terra balance: ${e.message}`); - } - } - return Promise.resolve([getTerraBalance, getTerraStakedBalance]); - } - - // TODO: update against staking logic on master - public async getBalance(node: IChainNode, address: string): Promise { - // re-encode address if necessary - if (!node.bech32) { - throw new Error('No cosmos prefix found!'); - } - const { data } = fromBech32(address); - const encodedAddress = toBech32(node.bech32, data); - - const [terraBalanceFn, stakedBalanceFn] = await this.getExternalProvider( - node, - ); - - let bankBalance = new BN(0); - - const fetchedBalance = await terraBalanceFn(encodedAddress); - if (fetchedBalance) { - bankBalance = fetchedBalance; - } - - let stakedBalance = new BN(0); - - const fetchedStakedBalance = await stakedBalanceFn(encodedAddress); - if (fetchedStakedBalance) { - stakedBalance = fetchedStakedBalance; - } - - return bankBalance.add(stakedBalance).toString(); - } -} diff --git a/packages/token-balance-cache/src/tbc.ts b/packages/token-balance-cache/src/tbc.ts deleted file mode 100644 index 95742287f03..00000000000 --- a/packages/token-balance-cache/src/tbc.ts +++ /dev/null @@ -1,356 +0,0 @@ -import { Client } from 'pg'; - -import { ChainNetwork } from '@hicommonwealth/core'; -import BN from 'bn.js'; -import JobRunner from 'common-common/src/cacheJobRunner'; -import { factory, formatFilename } from 'common-common/src/logging'; - -import { TbcStatsDSender } from './tbcStatsDSender'; -import type { - BalanceProvider, - BalanceProviderResp, - ChainNodeResp, - ICache, - IChainNode, - ITokenBalanceCache, - TokenBalanceResp, -} from './types'; -import { FetchTokenBalanceErrors } from './types'; - -const log = factory.getLogger(formatFilename(__filename)); - -async function queryChainNodesFromDB( - lastQueryUnixTime: number, -): Promise { - const query = `SELECT * FROM "ChainNodes" WHERE updated_at >= to_timestamp (${lastQueryUnixTime})::date;`; - - const DATABASE_URI = - !process.env.DATABASE_URL || process.env.NODE_ENV === 'development' - ? 'postgresql://commonwealth:edgeware@localhost/commonwealth' - : process.env.DATABASE_URL; - - const db = new Client({ - connectionString: DATABASE_URI, - ssl: - process.env.NODE_ENV !== 'production' || process.env.NO_SSL - ? false - : { - rejectUnauthorized: false, - }, - }); - await db.connect(); - const nodeQuery = await db.query(query); - const nodeArray = nodeQuery.rows; - await db.end(); - return nodeArray; -} - -// TODO: have JobRunner/cache as include rather than extends, for unit testing, -// then rename to TokenBalanceController / TokenBalanceService -export class TokenBalanceCache - extends JobRunner - implements ITokenBalanceCache -{ - private _nodes: { [id: number]: IChainNode } = {}; - private _providers: { [name: string]: BalanceProvider } = {}; - // Maps global chain id -> Common DB chainIds for quick lookup in _nodes - private _chainIds: { [id: string]: number } = {}; - private _lastQueryTime = 0; - private statsDSender: TbcStatsDSender = new TbcStatsDSender(); - private cacheContents = { zero: 0, nonZero: 0 }; - - constructor( - noBalancePruneTimeS: number = 5 * 60, - private readonly _hasBalancePruneTimeS: number = 1 * 60 * 60, - providers: BalanceProvider[] = null, - private readonly _nodesProvider: ( - lastQueryUnixTime: number, - ) => Promise = queryChainNodesFromDB, - ) { - super({}, noBalancePruneTimeS); - - // if providers is set, init during constructor - if (providers != null) { - for (const provider of providers) { - this._providers[provider.name] = provider; - } - } - } - - public async initBalanceProviders(providers: BalanceProvider[] = null) { - // lazy load import to improve test speed - if (providers == null) { - const p = await import('./providers'); - providers = p.default; - } - for (const provider of providers) { - this._providers[provider.name] = provider; - } - } - - public async getChainNodes(): Promise { - return Object.values(this._nodes).map( - ({ id, name, description, balance_type, ss58, bech32 }) => ({ - id, - name, - description, - base: balance_type, - prefix: bech32 || ss58?.toString(), - }), - ); - } - - public async getBalanceProviders( - nodeId?: number, - ): Promise { - const formatBps = (bps: BalanceProvider[]): BalanceProviderResp[] => { - this.statsDSender.sendProviderInfo(bps, nodeId); - return bps.map(({ name, opts }) => ({ bp: name, opts })); - }; - - // return all available providers if no nodeId passed - if (!nodeId) { - return formatBps(Object.values(this._providers)); - } - - // otherwise, return bps that support node's base - // TODO: ensure all nodes have proper bases / balance types in db... - const node = this._nodes[nodeId]; - if (!node) { - const e = new Error('Could not find node'); - this.statsDSender.sendError(e); - throw e; - } - const base = node.balance_type; - const bps = Object.values(this._providers).filter(({ validBases }) => - validBases.includes(base), - ); - return formatBps(bps); - } - - public async getBalancesForAddresses( - nodeId: number, - addresses: string[], - balanceProvider: string, - opts: Record, - ): Promise { - const node = this._nodes[nodeId]; - if (!node) { - const e = new Error('unknown node id'); - this.statsDSender.sendError(e); - throw e; - } - const [{ bp }] = await this.getBalanceProviders(nodeId); - if (bp !== balanceProvider) { - const e = new Error('balance provider not valid for node'); - this.statsDSender.sendError(e); - throw e; - } - const providerObj = this._providers[balanceProvider]; - - const getBalance = async (address: string): Promise => { - const cacheKey = providerObj.getCacheKey(node, address, opts); - const result = await this.access( - async (c: ICache): Promise => { - if (c[cacheKey]) { - return c[cacheKey].balance; - } else { - return undefined; - } - }, - ); - if (result !== undefined) return result; - - // fetch balance if not found in cache - const fetchedAt = Date.now(); - - // will throw on invalid chain / other error - const balance = await providerObj.getBalance(node, address, opts); - - // write fetched balance back to cache - await this.access(async (c: ICache) => { - c[cacheKey] = { balance, fetchedAt }; - - if (new BN(balance).eqn(0)) { - this.cacheContents['zero']++; - } else { - this.cacheContents['nonZero']++; - } - }); - return balance; - }; - - const results = { - balances: {}, - errors: {}, - }; - - await Promise.all( - addresses.map(async (address) => { - try { - const start = Date.now(); - const balance = await getBalance(address); - this.statsDSender.sendFetchTiming( - start, - Date.now(), - providerObj.name, - nodeId, - ); - - results.balances[address] = balance; - } catch (e) { - results.errors[address] = e.message; - } - }), - ); - - return results; - } - - // Backwards compatibility function to fetch a single user's token balance - // in a context where a chain node only has a single balance provider. - public async fetchUserBalance( - network: ChainNetwork, - nodeId: number, - userAddress: string, - contractAddress?: string, - tokenId?: string, - ): Promise { - let bp: string; - try { - const providersResult = await this.getBalanceProviders(nodeId); - bp = providersResult[0].bp; - } catch (e) { - throw new Error(FetchTokenBalanceErrors.NoBalanceProvider); - } - - // grab contract if provided, otherwise query native token - let opts = {}; - if (contractAddress) { - if ( - network !== ChainNetwork.ERC20 && - network !== ChainNetwork.ERC721 && - network !== ChainNetwork.ERC1155 - ) { - throw new Error(FetchTokenBalanceErrors.UnsupportedContractType); - } - if (network === ChainNetwork.ERC1155) { - opts = { - tokenAddress: contractAddress, - contractType: network, - tokenId: tokenId, - }; - } else { - opts = { - tokenAddress: contractAddress, - contractType: network, - }; - } - } - - let balancesResp: TokenBalanceResp; - try { - balancesResp = await this.getBalancesForAddresses( - nodeId, - [userAddress], - bp, - opts, - ); - } catch (err) { - throw new Error('Query Failed'); - } - - if (balancesResp.balances[userAddress]) { - return balancesResp.balances[userAddress]; - } else if (balancesResp.errors[userAddress]) { - throw new Error( - `Error querying balance: ${balancesResp.errors[userAddress]}`, - ); - } else { - throw new Error('Query failed'); - } - } - - public async fetchUserBalanceWithChain( - network: ChainNetwork, - userAddress: string, - chainId: string, - contractAddress?: string, - tokenId?: string, - ): Promise { - const nodeId = this._chainIds[chainId]; - if (!nodeId) { - throw new Error('Invalid Chain Id'); - } - const balance = await this.fetchUserBalance( - network, - nodeId, - userAddress, - contractAddress, - tokenId, - ); - return balance; - } - - private async _refreshNodes() { - const lastQueryTime = this._lastQueryTime; - this._lastQueryTime = Math.floor(Date.now() / 1000); - const nodes = await this._nodesProvider(lastQueryTime); - for (const n of nodes) { - this._nodes[n.id] = n; - if (n.eth_chain_id) { - this._chainIds[n.eth_chain_id.toString()] = n.id; - } else if (n.cosmos_chain_id) { - this._chainIds[n.cosmos_chain_id] = n.id; - } - } - } - - public async start() { - // all nodes at startup - this._nodes = {}; - await this._refreshNodes(); - - // kick off job - super.start(); - log.info(`Started Token Balance Cache.`); - } - - public async reset() { - super.close(); - await this.access(async (cache) => { - for (const key of Object.keys(cache)) { - delete cache[key]; - this.statsDSender.sendJobItemRemoved(key); - } - }); - return this.start(); - } - - // prune cache job - protected async _job(cache: ICache): Promise { - // clear stale cache members - for (const key of Object.keys(cache)) { - if (new BN(cache[key].balance).eqn(0)) { - // 5 minute lifetime (i.e. one job run) if no token balance - delete cache[key]; - - this.cacheContents['zero']--; - } else { - // 1 hour lifetime if token balance exists - const cutoff = Date.now() - this._hasBalancePruneTimeS * 1000; - const fetchedAt = cache[key].fetchedAt; - if (fetchedAt <= cutoff) { - delete cache[key]; - - this.cacheContents['nonZero']--; - } - } - } - - this.statsDSender.sendCacheSizeInfo(this.cacheContents); - - // run update query - await this._refreshNodes(); - } -} diff --git a/packages/token-balance-cache/src/tbcStatsDSender.ts b/packages/token-balance-cache/src/tbcStatsDSender.ts deleted file mode 100644 index 98271c5528b..00000000000 --- a/packages/token-balance-cache/src/tbcStatsDSender.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { StatsDController, ProjectTag } from 'common-common/src/statsd'; -import type { BalanceProvider } from './types'; - -// Class with Helper functions to send statsD -export class TbcStatsDSender { - private statsD = StatsDController.get(); - - // Log requests per provider + node + contract - sendProviderInfo(bps: BalanceProvider[], nodeId?: number) { - bps.forEach((bp) => { - const tags = { - name: bp.name, - nodeId: nodeId.toString(), - contract: bp.opts['contract'], - project: ProjectTag.TokenBalanceCache, - }; - - this.statsD.increment(`tbc.provider_requests`, tags); - }); - } - - // Total cache size of 0 vs non-0 balance entries - sendCacheSizeInfo({ zero, nonZero }) { - const tags = { - project: ProjectTag.TokenBalanceCache, - }; - - this.statsD.gauge('tbc.cache_size_zero', zero, tags); - this.statsD.gauge('tbc.cache_size_nonzero', nonZero, tags); - } - - // Fetch timings per provider + node. - sendFetchTiming(start: number, stop: number, name: string, nodeId: number) { - const tags = { - name: name, - node: nodeId.toString(), - project: ProjectTag.TokenBalanceCache, - }; - - this.statsD.timing('tbc.fetch_timings', stop - start, tags); - } - - // Cache job items removed + timings - sendJobItemRemoved(cacheKey: string) { - const tags = { - cacheKey: cacheKey, - date: Date.now().toString(), - project: ProjectTag.TokenBalanceCache, - }; - - this.statsD.increment('tbc.node_removed', tags); - } - - // Failure counts + reasons - sendError(error: Error) { - const tags = { - reason: error.message, - project: ProjectTag.TokenBalanceCache, - }; - - this.statsD.increment('tbc.error', tags); - } -} diff --git a/packages/token-balance-cache/src/types.ts b/packages/token-balance-cache/src/types.ts deleted file mode 100644 index a3d1a3cab05..00000000000 --- a/packages/token-balance-cache/src/types.ts +++ /dev/null @@ -1,96 +0,0 @@ -import type { BalanceType } from '@hicommonwealth/core'; - -// map of addresses to balances -export interface ICache { - [cacheKey: string]: { - balance: string; - fetchedAt: number; - }; -} - -export enum FetchTokenBalanceErrors { - NoBalanceProvider = 'Balance provider not found', - UnsupportedContractType = 'Unsupported contract type', -} - -export type IChainNode = { - id: number; - url: string; - eth_chain_id?: number; - cosmos_chain_id?: string; - alt_wallet_url?: string; - private_url?: string; - balance_type: BalanceType; - name: string; - description?: string; - ss58?: number; - bech32?: string; -}; - -export type ChainNodeResp = { - id: number; - name: string; - description?: string; - base: BalanceType; - prefix?: string; -}; - -export abstract class BalanceProvider< - ExternalProviderT, - OptT extends Record = Record, -> { - public readonly name: string; - public readonly opts: Record; - public abstract readonly validBases: BalanceType[]; - - // eslint-disable-next-line @typescript-eslint/no-unused-vars - public getCacheKey(node: IChainNode, address: string, opts: OptT): string { - return `${node.id}-${address}`; - } - - public abstract getBalance( - node: IChainNode, - address: string, - opts: OptT, - ): Promise; - - public abstract getExternalProvider( - node: IChainNode, - opts: OptT, - ): Promise; -} - -export type BalanceProviderResp = { - bp: string; - opts: Record; -}; - -export type TokenBalanceResp = { - balances: { [address: string]: string }; - errors: { [address: string]: string }; -}; - -export type ITokenBalanceCache = { - getChainNodes(): Promise; - getBalanceProviders(nodeId: number): Promise; - getBalancesForAddresses( - nodeId: number, - addresses: string[], - balanceProvider: string, - opts: Record, // TODO: if we want, we can add ts overrides - ): Promise; -}; - -const ContractTypes = ['erc20', 'erc721', 'erc1155', 'spl-token'] as const; -export type ContractType = typeof ContractTypes[number]; -export function parseContractType(arg: string): ContractType { - const ct = ContractTypes.find((validName) => validName === arg); - if (ct) return ct; - throw new Error('Invalid contract type'); -} - -export type EthBPOpts = { - tokenAddress?: string; - contractType?: string; - tokenId?: string; -}; diff --git a/packages/token-balance-cache/src/util/validateOpts.ts b/packages/token-balance-cache/src/util/validateOpts.ts deleted file mode 100644 index 0de4c4d7891..00000000000 --- a/packages/token-balance-cache/src/util/validateOpts.ts +++ /dev/null @@ -1,21 +0,0 @@ -import type { EthBPOpts } from '../types'; -import Web3 from 'web3'; - -export function validateOpts( - address: string, - opts: EthBPOpts & { tokenId?: string } -) { - const { tokenAddress, contractType, tokenId } = opts; - if (!tokenAddress) { - throw new Error('Need Token Address'); - } - if (contractType === 'erc1155' && !tokenId) { - throw new Error('Token Id Required For ERC-1155'); - } - if (!Web3.utils.isAddress(tokenAddress)) { - throw new Error('Invalid token address'); - } - if (!Web3.utils.isAddress(address)) { - throw new Error('Invalid address'); - } -} diff --git a/packages/token-balance-cache/test/cosmos.spec.ts b/packages/token-balance-cache/test/cosmos.spec.ts deleted file mode 100644 index 4f70c5ba4d8..00000000000 --- a/packages/token-balance-cache/test/cosmos.spec.ts +++ /dev/null @@ -1,80 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-vars */ -import { BalanceType } from '@hicommonwealth/core'; -import { assert, use as chaiUse, expect } from 'chai'; -import chaiAsPromised from 'chai-as-promised'; -import CosmosBalanceProvider from '../src/providers/cosmos'; -import type { IChainNode } from '../src/types'; - -chaiUse(chaiAsPromised); - -class MockProvider { - bank = { - balance: (address: string, denom: string) => { - return { - amount: '12345678912345678910', - denom: 'denom', - }; - }, - }; - - staking = { - params: () => { - return { - params: { - bondDenom: 'denom', - }, - }; - }, - }; -} - -class MockCosmosBalanceProvider extends CosmosBalanceProvider { - public readonly validBases = [BalanceType.Ethereum]; - public async getExternalProvider(node: IChainNode): Promise { - return new MockProvider(); - } -} - -async function mockNodesProvider(): Promise { - return [ - { - id: 1, - url: 'none', - eth_chain_id: 5555, - balance_type: BalanceType.Cosmos, - name: 'Mock Node', - bech32: 'cosmos', - }, - { - id: 2, - url: 'none', - eth_chain_id: 5555, - balance_type: BalanceType.Ethereum, - name: 'Mock Node', - }, - ]; -} - -describe('Cosmos BP unit tests', () => { - it('cosmosBp balance provider should return balance', async () => { - const cosmosBp: MockCosmosBalanceProvider = new MockCosmosBalanceProvider(); - const nodes = await mockNodesProvider(); - const balance = await cosmosBp.getBalance( - nodes[0], - 'cosmos1tn4hpcgfxxjhs3y06g5je0cg6tn3xqrkh99z7e', - ); - - assert.equal(balance, '12345678912345678910'); - }); - - it('cosmosBp balance provider should return error if wrong contract type', async () => { - const cosmosBp: MockCosmosBalanceProvider = new MockCosmosBalanceProvider(); - const nodes = await mockNodesProvider(); - return expect( - cosmosBp.getBalance( - nodes[1], - 'cosmos1tn4hpcgfxxjhs3y06g5je0cg6tn3xqrkh99z7e', - ), - ).to.be.rejectedWith('No cosmos prefix found!'); - }); -}); diff --git a/packages/token-balance-cache/test/ethToken.spec.ts b/packages/token-balance-cache/test/ethToken.spec.ts deleted file mode 100644 index 27da66edc42..00000000000 --- a/packages/token-balance-cache/test/ethToken.spec.ts +++ /dev/null @@ -1,73 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-vars */ -import { BalanceType } from '@hicommonwealth/core'; -import { assert, use as chaiUse, expect } from 'chai'; -import chaiAsPromised from 'chai-as-promised'; -import { BigNumber, BigNumberish, CallOverrides } from 'ethers'; -import EthTokenBalanceProvider from '../src/providers/ethToken'; - -import type { IChainNode } from '../src/types'; - -chaiUse(chaiAsPromised); - -type EthBPOpts = { - tokenAddress?: string; - contractType?: string; - tokenId?: string; -}; - -class MockProvider { - eth = { - getBalance: ( - account: string, - id: BigNumberish, - overrides?: CallOverrides, - ) => { - return BigNumber.from('12345678912345678910'); - }, - }; - - currentProvider = { - disconnect: (code: number, reason: string) => {}, - }; -} - -async function mockNodesProvider(): Promise { - return [ - { - id: 1, - url: 'none', - eth_chain_id: 5555, - balance_type: BalanceType.Ethereum, - name: 'Mock Node', - }, - ]; -} - -class MockEthTokenBalanceProvider extends EthTokenBalanceProvider { - public readonly validBases = [BalanceType.Ethereum]; - public async getExternalProvider(node: IChainNode): Promise { - return new MockProvider(); - } -} - -describe('Eth Token BP unit tests', () => { - it('ethToken balance provider should return balance', async () => { - const ethTokenBp: MockEthTokenBalanceProvider = - new MockEthTokenBalanceProvider(); - const balance = await ethTokenBp.getBalance( - await mockNodesProvider()[0], - '0x71C7656EC7ab88b098defB751B7401B5f6d8976F', - {}, - ); - - assert.equal(balance, '12345678912345678910'); - }); - - it('ethToken balance provider should return error if invalid address', async () => { - const ethTokenBp: MockEthTokenBalanceProvider = - new MockEthTokenBalanceProvider(); - return expect( - ethTokenBp.getBalance(await mockNodesProvider()[0], 'abcd', {}), - ).to.be.rejectedWith('Invalid address'); - }); -}); diff --git a/packages/token-balance-cache/test/evm.spec.ts b/packages/token-balance-cache/test/evm.spec.ts deleted file mode 100644 index 636db0961f4..00000000000 --- a/packages/token-balance-cache/test/evm.spec.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { BalanceType } from '@hicommonwealth/core'; -import { assert } from 'chai'; -import { ChainTesting } from '../../commonwealth/test/util/evm-chain-testing/sdk/chainTesting'; -import { default as evmBalanceProvider } from '../src/providers/ethToken'; -import { TokenBalanceCache } from '../src/tbc'; -import { IChainNode } from '../src/types'; - -async function mockNodesProvider(): Promise { - return [ - { - id: 1, - url: 'http://127.0.0.1:8545', - eth_chain_id: 5555, - balance_type: BalanceType.Ethereum, - name: 'eth-token', - }, - ]; -} - -const providers = [new evmBalanceProvider()]; -const tbc = new TokenBalanceCache(0, 0, providers, mockNodesProvider); - -const testSDK = new ChainTesting('http://127.0.0.1:3000'); - -describe('EVM Token BP unit tests', () => { - it('should return the correct ERC20 balance', async () => { - await tbc.start(); - let amt = 10; - const accounts = await testSDK.getAccounts(); - const token = '0x92D6C1e31e14520e676a687F0a93788B716BEff5'; - await testSDK.getErc20(token, accounts[0], amt.toString()); - const balance = await tbc.getBalancesForAddresses( - 1, - [accounts[0]], - 'eth-token', - { contractType: 'erc20', tokenAddress: token }, - ); - amt *= 1e18; - assert.equal(balance.balances[accounts[0]], amt.toString()); - }); - - it('should return the correct ERC721 balance', async () => { - const accounts = await testSDK.getAccounts(); - const nft = await testSDK.deployNFT(); - await nft.mint('137', 0); - const token = nft.address; - const balance = await tbc.getBalancesForAddresses( - 1, - [accounts[0]], - 'eth-token', - { contractType: 'erc721', tokenAddress: token }, - ); - assert.equal(balance.balances[accounts[0]], '1'); - }); -}); diff --git a/packages/token-balance-cache/test/ronin.spec.ts b/packages/token-balance-cache/test/ronin.spec.ts deleted file mode 100644 index 93f15f2b742..00000000000 --- a/packages/token-balance-cache/test/ronin.spec.ts +++ /dev/null @@ -1,83 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-vars */ -import { BalanceType } from '@hicommonwealth/core'; -import { assert, use as chaiUse, expect } from 'chai'; -import chaiAsPromised from 'chai-as-promised'; -import { BigNumber, BigNumberish, CallOverrides } from 'ethers'; -import RoninBalanceProvider from '../src/providers/ronin'; -import type { IChainNode } from '../src/types'; - -chaiUse(chaiAsPromised); - -class MockProvider { - public async balanceOf( - account: string, - id: BigNumberish, - overrides?: CallOverrides, - ): Promise { - return BigNumber.from('1'); - } - - provider = { - provider: { - disconnect: (code: number, reason: string) => {}, - }, - }; -} - -class MockStakingContract { - methods = { - getStakingAmount: (address: string) => { - return { - call: () => { - return '1'; - }, - }; - }, - }; -} - -class MockRoninBalanceProvider extends RoninBalanceProvider { - public readonly validBases = [BalanceType.Ethereum]; - public async getExternalProvider(node: IChainNode): Promise { - return [new MockProvider(), new MockStakingContract()]; - } -} - -async function mockNodesProvider(): Promise { - return [ - { - id: 1, - url: 'none', - eth_chain_id: 5555, - balance_type: BalanceType.Ethereum, - name: 'Mock Node', - }, - { - id: 2, - url: 'none', - eth_chain_id: 5555, - balance_type: BalanceType.Ethereum, - name: 'Mock Node', - }, - ]; -} - -describe('ERC1155 BP unit tests', () => { - it('ronin balance provider should return balance', async () => { - const roninBp: MockRoninBalanceProvider = new MockRoninBalanceProvider(); - const balance = await roninBp.getBalance( - await mockNodesProvider()[0], - '0x71C7656EC7ab88b098defB751B7401B5f6d8976F', - ); - - assert.equal(balance, '2'); - }); - - it('ronin balance provider should return error if wrong contract type', async () => { - const roninBp: MockRoninBalanceProvider = new MockRoninBalanceProvider(); - - return expect( - roninBp.getBalance(await mockNodesProvider()[0], 'abcd'), - ).to.be.rejectedWith('Invalid address'); - }); -}); diff --git a/packages/token-balance-cache/test/splToken.spec.ts b/packages/token-balance-cache/test/splToken.spec.ts deleted file mode 100644 index bbe839468f3..00000000000 --- a/packages/token-balance-cache/test/splToken.spec.ts +++ /dev/null @@ -1,85 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-vars */ -import { BalanceType } from '@hicommonwealth/core'; -import { assert, use as chaiUse, expect } from 'chai'; -import chaiAsPromised from 'chai-as-promised'; -import SplTokenBalanceProvider from '../src/providers/splToken'; - -chaiUse(chaiAsPromised); - -import { PublicKey, TokenAccountsFilter } from '@solana/web3.js'; -import type { IChainNode } from '../src/types'; - -class MockProvider { - public async getParsedTokenAccountsByOwner( - ownerAddress: PublicKey, - filter: TokenAccountsFilter, - ): Promise { - return { - value: [ - { - account: { - data: { - parsed: { - info: { - tokenAmount: { - amount: '12345678912345678910', - }, - }, - }, - }, - }, - }, - ], - }; - } -} - -async function mockNodesProvider(): Promise { - return [ - { - id: 1, - url: 'none', - eth_chain_id: 5555, - balance_type: BalanceType.Ethereum, - name: 'Mock Node', - }, - ]; -} - -class MockSplTokenBalanceProvider extends SplTokenBalanceProvider { - public readonly validBases = [BalanceType.Ethereum]; - public async getExternalProvider(node: IChainNode): Promise { - return new MockProvider(); - } -} - -describe('SplBp BP unit tests', () => { - it('splBp balance provider should return balance', async () => { - const splBp: MockSplTokenBalanceProvider = - new MockSplTokenBalanceProvider(); - const balance = await splBp.getBalance( - await mockNodesProvider()[0], - 'xzaSRbYFi2x4rQFtcVzbjUwJ7t7qRsfoFGTJTaFMJ3e', - { - tokenAddress: 'xzaSRbYFi2x4rQFtcVzbjUwJ7t7qRsfoFGTJTaFMJ3e', - }, - ); - - assert.equal(balance, '12345678912345678910'); - }); - - it('splBp balance provider should return error if wrong contract type', async () => { - const splBp: MockSplTokenBalanceProvider = - new MockSplTokenBalanceProvider(); - - return expect( - splBp.getBalance( - await mockNodesProvider()[0], - 'xzaSRbYFi2x4rQFtcVzbjUwJ7t7qRsfoFGTJTaFMJ3e', - { - tokenAddress: '123', - }, - ), - ).to.be.rejectedWith('Invalid public key input'); - }); -}); diff --git a/packages/token-balance-cache/test/tbc.spec.ts b/packages/token-balance-cache/test/tbc.spec.ts deleted file mode 100644 index d1b8e1c810c..00000000000 --- a/packages/token-balance-cache/test/tbc.spec.ts +++ /dev/null @@ -1,200 +0,0 @@ -import { BalanceType } from '@hicommonwealth/core'; -import { assert } from 'chai'; -import Web3 from 'web3'; - -import { TokenBalanceCache } from '../src/tbc'; -import type { IChainNode } from '../src/types'; -import { BalanceProvider } from '../src/types'; - -class MockErc1155BalanceProvider extends BalanceProvider<{ - testBalance: string; -}> { - public readonly name = 'test-provider'; - public readonly opts = { - testBalance: 'string', - testTokenId: 'string?', - contractType: 'string?', - }; - public readonly validBases = [BalanceType.Ethereum]; - public async getBalance( - _node: IChainNode, - address: string, - opts: { testBalance: string; testTokenId?: string; contractType?: string }, - ): Promise { - const { testBalance, testTokenId, contractType } = opts; - if (Web3.utils.isAddress(address)) { - if (contractType === 'erc1155' && !testTokenId) { - throw new Error('Token Id Required For ERC-1155'); - } - return testBalance; - } else { - throw new Error('Invalid address!'); - } - } -} - -class MockBalanceProvider extends BalanceProvider<{ testBalance: string }> { - public readonly name = 'test-provider'; - public readonly opts = { testBalance: 'string' }; - public readonly validBases = [BalanceType.Ethereum]; - public async getBalance( - _node: IChainNode, - address: string, - opts: { testBalance: string }, - ): Promise { - if (Web3.utils.isAddress(address)) { - return opts.testBalance; - } else { - throw new Error('Invalid address!'); - } - } -} - -async function mockNodesProvider(): Promise { - return [ - { - id: 1, - url: 'none', - eth_chain_id: 5555, - balance_type: BalanceType.Ethereum, - name: 'Mock Node', - }, - ]; -} - -describe('TBC unit tests', () => { - it('should return chain nodes', async () => { - const tbc = new TokenBalanceCache( - 0, - 0, - [new MockBalanceProvider()], - mockNodesProvider, - ); - await tbc.start(); - const nodes = await tbc.getChainNodes(); - assert.sameDeepMembers(nodes, [ - { - id: 1, - name: 'Mock Node', - base: BalanceType.Ethereum, - description: undefined, - prefix: undefined, - }, - ]); - tbc.close(); - }); - - it('should return balance providers', async () => { - const tbc = new TokenBalanceCache( - 0, - 0, - [new MockBalanceProvider()], - mockNodesProvider, - ); - await tbc.start(); - const bps = await tbc.getBalanceProviders(1); - assert.sameDeepMembers(bps, [ - { - bp: 'test-provider', - opts: { testBalance: 'string' }, - }, - ]); - tbc.close(); - }); - - it('should return erc1155 balance providers', async () => { - const tbc = new TokenBalanceCache( - 0, - 0, - [new MockErc1155BalanceProvider()], - mockNodesProvider, - ); - await tbc.start(); - const bps = await tbc.getBalanceProviders(1); - assert.sameDeepMembers(bps, [ - { - bp: 'test-provider', - opts: { - testBalance: 'string', - testTokenId: 'string?', - contractType: 'string?', - }, - }, - ]); - tbc.close(); - }); - - it('should throw error when no node exists for id', async () => { - const tbc = new TokenBalanceCache( - 0, - 0, - [new MockBalanceProvider()], - mockNodesProvider, - ); - await tbc.start(); - try { - await tbc.getBalanceProviders(2); - } catch (e) { - // we expect error - return; - } - - // if no error, fail test - assert.fail(); - }); - - it('should return token balances', async () => { - const tbc = new TokenBalanceCache( - 0, - 0, - [new MockBalanceProvider()], - mockNodesProvider, - ); - await tbc.start(); - const addresses = ['abcd', '0x71C7656EC7ab88b098defB751B7401B5f6d8976F']; - const testBalance = '123456789123456789'; - const tokenBalances = await tbc.getBalancesForAddresses( - 1, - addresses, - 'test-provider', - { testBalance }, - ); - assert.deepEqual(tokenBalances, { - balances: { - [addresses[1]]: testBalance, - }, - errors: { - [addresses[0]]: 'Invalid address!', - }, - }); - tbc.close(); - }); - - it('should return token balances for erc1155 token id', async () => { - const tbc = new TokenBalanceCache( - 0, - 0, - [new MockErc1155BalanceProvider()], - mockNodesProvider, - ); - await tbc.start(); - const addresses = ['abcd', '0x71C7656EC7ab88b098defB751B7401B5f6d8976F']; - const testBalance = '12345678912345678910'; - const testTokenId = '123456789'; - const tokenBalances = await tbc.getBalancesForAddresses( - 1, - addresses, - 'test-provider', - { testBalance, testTokenId }, - ); - assert.deepEqual(tokenBalances, { - balances: { - [addresses[1]]: testBalance, - }, - errors: { - [addresses[0]]: 'Invalid address!', - }, - }); - tbc.close(); - }); -}); diff --git a/packages/token-balance-cache/tsconfig.json b/packages/token-balance-cache/tsconfig.json deleted file mode 100644 index 642ba91468a..00000000000 --- a/packages/token-balance-cache/tsconfig.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "extends": "../../tsconfig.json", - "compilerOptions": { - "outDir": "./dist", - "baseUrl": "./src", - "typeRoots": ["./node_modules/@types"] - }, - "include": ["./src"], - "exclude": ["./dist", "./node_modules", "./test"] -} diff --git a/packages/token-balance-cache/tsconfig.test.json b/packages/token-balance-cache/tsconfig.test.json deleted file mode 100644 index b3b8fb05f8b..00000000000 --- a/packages/token-balance-cache/tsconfig.test.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "extends": "./tsconfig.json", - "include": ["./test"], - "exclude": ["./dist", "./node_modules"] -} diff --git a/yarn.lock b/yarn.lock index dfa7c79a8c7..4d8a8c90bc6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5438,17 +5438,17 @@ resolved "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.2.tgz" integrity sha512-6ckxMjBBD8URvjB6J3NcnuAn5Pkl7t3TizAg+xdlzzQGSPSmBcXf8KoIH0ua/i+tio+ZRUHEXp0HEmvaR4kt0w== -"@types/chai-as-promised@^7.1.5": - version "7.1.5" - resolved "https://registry.yarnpkg.com/@types/chai-as-promised/-/chai-as-promised-7.1.5.tgz#6e016811f6c7a64f2eed823191c3a6955094e255" - integrity sha512-jStwss93SITGBwt/niYrkf2C+/1KTeZCZl1LaeezTlqppAKeoQC7jxyqYuP72sxBGKCIbw7oHgbYssIRzT5FCQ== +"@types/chai-as-promised@^7.1.8": + version "7.1.8" + resolved "https://registry.yarnpkg.com/@types/chai-as-promised/-/chai-as-promised-7.1.8.tgz#f2b3d82d53c59626b5d6bbc087667ccb4b677fe9" + integrity sha512-ThlRVIJhr69FLlh6IctTXFkmhtP3NpMZ2QGq69StYLyKZFp/HOp1VdKZj7RvfNWYYcJ1xlbLGLLWj1UvP5u/Gw== dependencies: "@types/chai" "*" "@types/chai@*": - version "4.3.1" - resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.3.1.tgz#e2c6e73e0bdeb2521d00756d099218e9f5d90a04" - integrity sha512-/zPMqDkzSZ8t3VtxOa4KPq7uzzW978M9Tvh+j7GHKuo6k6GTLxPJ4J5gE5cjfJ26pnXst0N5Hax8Sr0T2Mi9zQ== + version "4.3.11" + resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.3.11.tgz#e95050bf79a932cb7305dd130254ccdf9bde671c" + integrity sha512-qQR1dr2rGIHYlJulmr8Ioq3De0Le9E4MJ5AiaeAETJJpndT1uUNHsGFK3L/UIu+rbkQSdj8J/w2bCsBZc/Y5fQ== "@types/chai@4": version "4.2.10" @@ -5460,11 +5460,6 @@ resolved "https://registry.npmjs.org/@types/chai/-/chai-4.2.11.tgz" integrity sha512-t7uW6eFafjO+qJ3BIV2gGUyZs27egcNRkUdalkud+Qa3+kg//f129iuOFivHDXQ+vnU3fDXuwgv0cqMCbcE8sw== -"@types/chai@^4.3.4": - version "4.3.4" - resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.3.4.tgz#e913e8175db8307d78b4e8fa690408ba6b65dee4" - integrity sha512-KnRanxnpfpjUTqTCXslZSEdLfXExwgNxYPdiO2WGUj8+HDjFi8R3k5RVKPeSCzLjCcshCAtVO2QBbVuAV4kTnw== - "@types/color-name@^1.1.1": version "1.1.1" resolved "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz" @@ -5778,11 +5773,6 @@ resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-10.0.0.tgz#3d9018c575f0e3f7386c1de80ee66cc21fbb7a52" integrity sha512-rADY+HtTOA52l9VZWtgQfn4p+UDVM2eDVkMZT1I6syp0YKxW2F9v+0pbRZLsvskhQv/vMb6ZfCay81GHbz5SHg== -"@types/mocha@^10.0.1": - version "10.0.1" - resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-10.0.1.tgz#2f4f65bb08bc368ac39c96da7b2f09140b26851b" - integrity sha512-/fvYntiO1GeICvqbQ3doGDIP97vWmvFt83GKguJ6prmQM2iXZfFcq6YE8KteFyRtX2/h5Hf91BYvPodJKFYv5Q== - "@types/mocha@^7.0.2": version "7.0.2" resolved "https://registry.npmjs.org/@types/mocha/-/mocha-7.0.2.tgz" @@ -8651,19 +8641,6 @@ chai@^4.2.0: pathval "^1.1.0" type-detect "^4.0.5" -chai@^4.3.6: - version "4.3.6" - resolved "https://registry.yarnpkg.com/chai/-/chai-4.3.6.tgz#ffe4ba2d9fa9d6680cc0b370adae709ec9011e9c" - integrity sha512-bbcp3YfHCUzMOvKqsztczerVgBKSsEijCySNlHHbX3VG1nskvqjz5Rfso1gGwD6w6oOV3eI60pKuMOV5MV7p3Q== - dependencies: - assertion-error "^1.1.0" - check-error "^1.0.2" - deep-eql "^3.0.1" - get-func-name "^2.0.0" - loupe "^2.3.1" - pathval "^1.1.1" - type-detect "^4.0.5" - chalk@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" @@ -15861,13 +15838,6 @@ loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0: dependencies: js-tokens "^3.0.0 || ^4.0.0" -loupe@^2.3.1: - version "2.3.4" - resolved "https://registry.yarnpkg.com/loupe/-/loupe-2.3.4.tgz#7e0b9bffc76f148f9be769cb1321d3dcf3cb25f3" - integrity sha512-OvKfgCC2Ndby6aSTREl5aCCPTNIzlDfQZvZxNUrBrihDhL3xcrYegTblhmEiCrg2kKQz4XsFIaemE5BF4ybSaQ== - dependencies: - get-func-name "^2.0.0" - lower-case@^1.1.1: version "1.1.4" resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-1.1.4.tgz#9a2cabd1b9e8e0ae993a4bf7d5875c39c42e8eac" @@ -17991,7 +17961,7 @@ pathe@^1.1.1: resolved "https://registry.yarnpkg.com/pathe/-/pathe-1.1.1.tgz#1dd31d382b974ba69809adc9a7a347e65d84829a" integrity sha512-d+RQGp0MAYTIaDBIMmOfMwz3E+LOZnxx1HZd5R18mmCZY0QBlK0LDZfPc8FW8Ed2DlvsuE6PRjroDY+wg4+j/Q== -pathval@^1.1.0, pathval@^1.1.1: +pathval@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.1.tgz#8534e77a77ce7ac5a2512ea21e0fdb8fcf6c3d8d" integrity sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ== From aea711b14b47d904fdb427e2ff19a257b5103eea Mon Sep 17 00:00:00 2001 From: Timothee Legros <62490329+timolegros@users.noreply.github.com> Date: Fri, 5 Jan 2024 19:18:54 +0100 Subject: [PATCH 2/3] Remove unused dependencies (#6167) * remove crypto-js * remove create-hash * remove ethereum-block-by-date * remove node-statsd * remove object-hash * remove passport-discord * remove passport-github2 * remove passport-local * remove rxjs * remove secp256k1 * remove sharp * remove source-map * remove throttled-queue * remove velocity * remove ws * remove bcrypt-nodejs * remove bip39 * remove chart.js * remove clipboard-polyfill * remove core-js * add core-js back * `yarn.lock` update * yarn.lock --- packages/commonwealth/madge.sh | 2 +- packages/commonwealth/package.json | 21 +- .../webpack/webpack.base.config.js | 5 - yarn.lock | 267 +----------------- 4 files changed, 16 insertions(+), 279 deletions(-) diff --git a/packages/commonwealth/madge.sh b/packages/commonwealth/madge.sh index 286e101ddd7..3449b3f90b6 100755 --- a/packages/commonwealth/madge.sh +++ b/packages/commonwealth/madge.sh @@ -1,3 +1,3 @@ #!/bin/sh # Generates a visualization of module dependencies -madge -i out.png --exclude '^state\.ts$|^identifiers\.ts$|app\/notifications|(node_modules\/@types)|rxjs|construct-ui|models\/|stores\/|shared\/adapters\/|helpers' client/scripts/app.tsx +madge -i out.png --exclude '^state\.ts$|^identifiers\.ts$|app\/notifications|(node_modules\/@types)|construct-ui|models\/|stores\/|shared\/adapters\/|helpers' client/scripts/app.tsx diff --git a/packages/commonwealth/package.json b/packages/commonwealth/package.json index 4f879ac22c0..dfe91fe4985 100644 --- a/packages/commonwealth/package.json +++ b/packages/commonwealth/package.json @@ -138,28 +138,21 @@ "amqplib": "^0.8.0", "assert": "^2.0.0", "aws-sdk": "^2.814.0", - "bcrypt-nodejs": "^0.0.3", "bech32": "^2.0.0", - "bip39": "^3.0.2", "bn.js": "^4.12.0", "browser-image-compression": "^2.0.2", "browserify-zlib": "^0.2.0", "bs58": "^4.0.1", "buffer": "^6.0.3", - "chart.js": "^2.8.0", "cheerio": "1.0.0-rc.3", - "clipboard-polyfill": "^2.8.6", "clsx": "^1.2.1", "compression": "^1.7.4", "connect-session-sequelize": "^7.1.1", "cookie-parser": "^1.4.4", - "core-js": "3", - "create-hash": "^1.2.0", + "core-js": "^3.34.0", "crypto-browserify": "^3.12.0", - "crypto-js": "^4.1.1", "dompurify": "^2.2.6", "dotenv": "^8.2.0", - "ethereum-block-by-date": "^1.2.2", "ethereumjs-util": "7.1.0", "ethereumjs-wallet": "^1.0.2", "express": "^4.17.3", @@ -190,17 +183,12 @@ "node-fetch": "2", "node-jose": "^2.2.0", "node-object-hash": "^3.0.0", - "node-statsd": "^0.1.1", "numeral": "^2.0.6", - "object-hash": "^3.0.0", "openai": "^3.1.0", "os-browserify": "^0.3.0", "parchment": "^1.1.4", "passport": "^0.4.0", - "passport-discord": "^0.1.4", - "passport-github2": "^0.1.12", "passport-jwt": "^4.0.0", - "passport-local": "^1.0.0", "passport-magic": "^1.0.0", "path-browserify": "^1.0.1", "prerender": "^5.6.0", @@ -232,31 +220,24 @@ "redis": "4.2.0", "remove-markdown": "^0.5.0", "rollbar": "^2.6.1", - "rxjs": "^7.3.0", "safe-stable-stringify": "^2.4.2", "sass": "^1.55.0", - "secp256k1": "^4.0.2", "sequelize-cli": "^6.2.0", "serve-favicon": "^2.5.0", - "sharp": "^0.31.2", "siwe": "^2.1.4", "sleep-promise": "^8.0.1", "smart-truncate": "^1.0.1", - "source-map": "^0.7.3", "stream-browserify": "^3.0.0", "stream-http": "^3.2.0", "superagent": "^5.2.2", "swagger-ui-express": "^4.6.0", - "throttled-queue": "^1.0.7", "ts-node": "^8.6.2", "tsc-alias": "^1.7.0", "tsconfig-paths": "^4.2.0", "tweetnacl": "^1.0.3", "underscore": "^1.13.1", "usehooks-ts": "^2.9.1", - "velocity": "^0.7.2", "vm-browserify": "^1.1.2", - "ws": "^7.4.6", "yargs": "^17.7.2", "zod": "^3.22.4", "zustand": "^4.3.8" diff --git a/packages/commonwealth/webpack/webpack.base.config.js b/packages/commonwealth/webpack/webpack.base.config.js index 92822c20bb4..3e87ad0b3f7 100644 --- a/packages/commonwealth/webpack/webpack.base.config.js +++ b/packages/commonwealth/webpack/webpack.base.config.js @@ -92,11 +92,6 @@ module.exports = { chunks: 'all', // TODO: Commented out packages need to be code split. Commented out for now so that webpack can tree shake the imports cacheGroups: { - bitcoin: { - test: /[\\/]node_modules[\\/](bip39)[\\/]/, - name: 'bitcoin', - chunks: 'all', - }, ethersAsync: { test: /[\\/]node_modules[\\/](ethers)[\\/]/, name: 'ethersAsync', diff --git a/yarn.lock b/yarn.lock index 4d8a8c90bc6..ab38bae37e5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7850,7 +7850,7 @@ base64-js@^1.3.0, base64-js@^1.3.1, base64-js@^1.5.1: resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== -base64url@3.x.x, base64url@^3.0.1: +base64url@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/base64url/-/base64url-3.0.1.tgz#6399d572e2bc3f90a9a8b22d5dbb0a32d33f788d" integrity sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A== @@ -7862,11 +7862,6 @@ basic-auth@~2.0.0: dependencies: safe-buffer "5.1.2" -bcrypt-nodejs@^0.0.3: - version "0.0.3" - resolved "https://registry.npmjs.org/bcrypt-nodejs/-/bcrypt-nodejs-0.0.3.tgz" - integrity sha1-xgkX8m3CNWYVZsaBBhwwPCsohCs= - bcrypt-pbkdf@^1.0.0: version "1.0.2" resolved "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz" @@ -7955,16 +7950,6 @@ bip32@^2.0.6: typeforce "^1.11.5" wif "^2.0.6" -bip39@^3.0.2: - version "3.0.2" - resolved "https://registry.npmjs.org/bip39/-/bip39-3.0.2.tgz" - integrity sha512-J4E1r2N0tUylTKt07ibXvhpT2c5pyAFgvuA5q1H9uDy6dEGpjV8jmymh3MTYJDLCNbIVClSB9FbND49I6N24MQ== - dependencies: - "@types/node" "11.11.6" - create-hash "^1.1.0" - pbkdf2 "^3.0.9" - randombytes "^2.0.1" - bip39@^3.0.3: version "3.0.4" resolved "https://registry.yarnpkg.com/bip39/-/bip39-3.0.4.tgz#5b11fed966840b5e1b8539f0f54ab6392969b2a0" @@ -8519,15 +8504,6 @@ camel-case@^4.1.2: pascal-case "^3.1.2" tslib "^2.0.3" -camelcase-keys@^6.1.1: - version "6.2.1" - resolved "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.1.tgz" - integrity sha512-BPCNVH56RVIxQQIXskp5tLQXUNGQ6sXr7iCv1FHDt81xBOQ/1r6H8SPxf19InVP6DexWar4s87q9thfuk8X9HA== - dependencies: - camelcase "^5.3.1" - map-obj "^4.0.0" - quick-lru "^4.0.1" - camelcase-keys@^6.2.2: version "6.2.2" resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-6.2.2.tgz#5e755d6ba51aa223ec7d3d52f25778210f9dc3c0" @@ -8687,29 +8663,6 @@ chalk@^5.2.0: resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.3.0.tgz#67c20a7ebef70e7f3970a01f90fa210cb6860385" integrity sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w== -chart.js@^2.8.0: - version "2.9.3" - resolved "https://registry.npmjs.org/chart.js/-/chart.js-2.9.3.tgz" - integrity sha512-+2jlOobSk52c1VU6fzkh3UwqHMdSlgH1xFv9FKMqHiNCpXsGPQa/+81AFa+i3jZ253Mq9aAycPwDjnn1XbRNNw== - dependencies: - chartjs-color "^2.1.0" - moment "^2.10.2" - -chartjs-color-string@^0.6.0: - version "0.6.0" - resolved "https://registry.npmjs.org/chartjs-color-string/-/chartjs-color-string-0.6.0.tgz" - integrity sha512-TIB5OKn1hPJvO7JcteW4WY/63v6KwEdt6udfnDE9iCAZgy+V4SrbSxoIbTw/xkUIapjEI4ExGtD0+6D3KyFd7A== - dependencies: - color-name "^1.0.0" - -chartjs-color@^2.1.0: - version "2.4.1" - resolved "https://registry.npmjs.org/chartjs-color/-/chartjs-color-2.4.1.tgz" - integrity sha512-haqOg1+Yebys/Ts/9bLo/BqUcONQOdr/hoEr2LLTRl6C5LXctUdHxsCYfvQVg5JIxITrfCNUDr4ntqmQk9+/0w== - dependencies: - chartjs-color-string "^0.6.0" - color-convert "^1.9.3" - check-error@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz" @@ -8894,11 +8847,6 @@ clipanion@^2.6.2: resolved "https://registry.yarnpkg.com/clipanion/-/clipanion-2.6.2.tgz#820e7440812052442455b248f927b187ed732f71" integrity sha512-0tOHJNMF9+4R3qcbBL+4IxLErpaYSYvzs10aXuECDbZdJOuJHdagJMAqvLdeaUQTI/o2uSCDRpet6ywDiKOAYw== -clipboard-polyfill@^2.8.6: - version "2.8.6" - resolved "https://registry.npmjs.org/clipboard-polyfill/-/clipboard-polyfill-2.8.6.tgz" - integrity sha512-kz/1ov+PXsBpGnW9XJH3dLWdYj12FpXqO89Dngm/GRPoI36E/tnYs6N0YPTEhxM9WHAlFiN5eoyIVuv5nzKXvg== - clipboardy@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/clipboardy/-/clipboardy-3.0.0.tgz#f3876247404d334c9ed01b6f269c11d09a5e3092" @@ -9023,7 +8971,7 @@ color-name@^1.0.0, color-name@~1.1.4: resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== -color-string@^1.6.0, color-string@^1.9.0: +color-string@^1.6.0: version "1.9.1" resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.9.1.tgz#4467f9146f036f855b764dfb5bf8582bf342c7a4" integrity sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg== @@ -9039,14 +8987,6 @@ color@^3.0.0: color-convert "^1.9.3" color-string "^1.6.0" -color@^4.2.3: - version "4.2.3" - resolved "https://registry.yarnpkg.com/color/-/color-4.2.3.tgz#d781ecb5e57224ee43ea9627560107c0e0c6463a" - integrity sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A== - dependencies: - color-convert "^2.0.1" - color-string "^1.9.0" - colord@^2.9.1, colord@^2.9.3: version "2.9.3" resolved "https://registry.yarnpkg.com/colord/-/colord-2.9.3.tgz#4f8ce919de456f1d5c1c368c307fe20f3e59fb43" @@ -9062,16 +9002,6 @@ colorette@^2.0.10, colorette@^2.0.14: resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.19.tgz#cdf044f47ad41a0f4b56b3a0d5b4e6e1a2d5a798" integrity sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ== -colorful@2.1.0, colorful@~2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/colorful/-/colorful-2.1.0.tgz" - integrity sha1-aovcvC2kKlDbO0iC+iUmOqofLY4= - -colors@1.0.3: - version "1.0.3" - resolved "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz" - integrity sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs= - combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6: version "1.0.8" resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz" @@ -9133,11 +9063,6 @@ commander@^9.3.0: resolved "https://registry.yarnpkg.com/commander/-/commander-9.5.0.tgz#bc08d1eb5cedf7ccb797a96199d41c7bc3e60d30" integrity sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ== -commander@~2.3.0: - version "2.3.0" - resolved "https://registry.npmjs.org/commander/-/commander-2.3.0.tgz" - integrity sha1-/UMOiJgy7DU7ms0d4hfBHLPu+HM= - commondir@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz" @@ -9387,16 +9312,16 @@ core-js-pure@^3.20.2: resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.24.0.tgz#10eeb90dbf0d670a6b22b081aecc7deb2faec7e1" integrity sha512-uzMmW8cRh7uYw4JQtzqvGWRyC2T5+4zipQLQdi2FmiRqP83k3d6F3stv2iAlNhOs6cXN401FCD5TL0vvleuHgA== -core-js@3: - version "3.27.2" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.27.2.tgz#85b35453a424abdcacb97474797815f4d62ebbf7" - integrity sha512-9ashVQskuh5AZEZ1JdQWp1GqSoC1e1G87MzRqg2gIfVAQ7Qn9K+uFj8EcniUFA4P2NLZfV+TOlX1SzoKfo+s7w== - core-js@^2.6.5: version "2.6.11" resolved "https://registry.npmjs.org/core-js/-/core-js-2.6.11.tgz" integrity sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg== +core-js@^3.34.0: + version "3.35.0" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.35.0.tgz#58e651688484f83c34196ca13f099574ee53d6b4" + integrity sha512-ntakECeqg81KqMueeGJ79Q5ZgQNR+6eaE8sxGCx62zMbAIj65q+uYvatToew3m6eAGdU4gNZwpZ34NMe4GYswg== + core-util-is@1.0.2, core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz" @@ -9571,11 +9496,6 @@ crypto-browserify@^3.11.0, crypto-browserify@^3.12.0: randombytes "^2.0.0" randomfill "^1.0.3" -crypto-js@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-4.1.1.tgz#9e485bcf03521041bd85844786b83fb7619736cf" - integrity sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw== - crypto-random-string@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-4.0.0.tgz#5a3cc53d7dd86183df5da0312816ceeeb5bb1fc2" @@ -9892,14 +9812,6 @@ date-fns@^2.29.1: resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.29.3.tgz#27402d2fc67eb442b511b70bbdf98e6411cd68a8" integrity sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA== -dateformat@1.0.11: - version "1.0.11" - resolved "https://registry.npmjs.org/dateformat/-/dateformat-1.0.11.tgz" - integrity sha1-8ny+56ASu/uC6gUVYtOXf2CT27E= - dependencies: - get-stdin "*" - meow "*" - debug@2.6.9, debug@^2.2.0, debug@^2.6.9, debug@~2.6.9: version "2.6.9" resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz" @@ -11494,13 +11406,6 @@ eth-sig-util@2.1.2: tweetnacl "^1.0.0" tweetnacl-util "^0.15.0" -ethereum-block-by-date@^1.2.2: - version "1.2.2" - resolved "https://registry.npmjs.org/ethereum-block-by-date/-/ethereum-block-by-date-1.2.2.tgz" - integrity sha512-2a3Ll/798vqzB7CH3dMBCHsAMgJk/bNR1YvRj3sCxwWMxH4znA2ZRxLwx/MZY/hBAYrWf/GIg49dVG1uSqVdkw== - dependencies: - moment "^2.25.0" - ethereum-bloom-filters@^1.0.6: version "1.0.6" resolved "https://registry.npmjs.org/ethereum-bloom-filters/-/ethereum-bloom-filters-1.0.6.tgz" @@ -12731,11 +12636,6 @@ get-port@^3.1.0: resolved "https://registry.yarnpkg.com/get-port/-/get-port-3.2.0.tgz#dd7ce7de187c06c8bf353796ac71e099f0980ebc" integrity sha1-3Xzn3hh8Bsi/NTeWrHHgmfCYDrw= -get-stdin@*: - version "7.0.0" - resolved "https://registry.npmjs.org/get-stdin/-/get-stdin-7.0.0.tgz" - integrity sha512-zRKcywvrXlXsA0v0i9Io4KDRaAw7+a1ZpjRwl9Wox8PFlVCCHra7E9c4kqXCoCM9nR5tBkaTTZRBoCm60bFqTQ== - get-stream@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz" @@ -13099,7 +12999,7 @@ har-validator@~5.1.3: ajv "^6.5.5" har-schema "^2.0.0" -hard-rejection@^2.0.0, hard-rejection@^2.1.0: +hard-rejection@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/hard-rejection/-/hard-rejection-2.1.0.tgz#1c6eda5c1685c63942766d79bb40ae773cecd883" integrity sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA== @@ -13567,11 +13467,6 @@ husky@^8.0.0: resolved "https://registry.yarnpkg.com/husky/-/husky-8.0.3.tgz#4936d7212e46d1dea28fef29bb3a108872cd9184" integrity sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg== -iconv-lite@0.2.11: - version "0.2.11" - resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.2.11.tgz" - integrity sha1-HOYKOleGSiktEyH/RgnKS7llrcg= - iconv-lite@0.4.23: version "0.4.23" resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz" @@ -16090,23 +15985,6 @@ memorystream@^0.3.1: resolved "https://registry.yarnpkg.com/memorystream/-/memorystream-0.3.1.tgz#86d7090b30ce455d63fbae12dda51a47ddcaf9b2" integrity sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw== -meow@*: - version "6.0.1" - resolved "https://registry.npmjs.org/meow/-/meow-6.0.1.tgz" - integrity sha512-kxGTFgT/b7/oSRSQsJ0qsT5IMU+bgZ1eAdSA3kIV7onkW0QWo/hL5RbGlMfvBjHJKPE1LaPX0kdecYFiqYWjUw== - dependencies: - "@types/minimist" "^1.2.0" - camelcase-keys "^6.1.1" - decamelize-keys "^1.1.0" - hard-rejection "^2.0.0" - minimist-options "^4.0.1" - normalize-package-data "^2.5.0" - read-pkg-up "^7.0.0" - redent "^3.0.0" - trim-newlines "^3.0.0" - type-fest "^0.8.1" - yargs-parser "^16.1.0" - meow@^9.0.0: version "9.0.0" resolved "https://registry.yarnpkg.com/meow/-/meow-9.0.0.tgz#cd9510bc5cac9dee7d03c73ee1f9ad959f4ea364" @@ -16296,14 +16174,6 @@ minimist-options@4.1.0: is-plain-obj "^1.1.0" kind-of "^6.0.3" -minimist-options@^4.0.1: - version "4.0.2" - resolved "https://registry.npmjs.org/minimist-options/-/minimist-options-4.0.2.tgz" - integrity sha512-seq4hpWkYSUh1y7NXxzucwAN9yVlBc3Upgdjz8vLCP97jG8kaOmzYrVH/m7tQ1NYD1wdtZbSLfdy4zFmRWuc/w== - dependencies: - arrify "^1.0.1" - is-plain-obj "^1.1.0" - minimist@0.0.8: version "0.0.8" resolved "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz" @@ -16529,7 +16399,7 @@ moment-timezone@^0.5.43: dependencies: moment "^2.29.4" -moment@*, "moment@>= 2.9.0", moment@^2.10.2, moment@^2.23.0, moment@^2.25.0, moment@^2.29.1: +moment@*, "moment@>= 2.9.0", moment@^2.23.0, moment@^2.29.1: version "2.29.1" resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.1.tgz#b2be769fa31940be9eeea6469c075e35006fa3d3" integrity sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ== @@ -16903,11 +16773,6 @@ node-addon-api@^2.0.0: resolved "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz" integrity sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA== -node-addon-api@^5.0.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-5.1.0.tgz#49da1ca055e109a23d537e9de43c09cca21eb762" - integrity sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA== - node-addon-api@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-7.0.0.tgz#8136add2f510997b3b94814f4af1cce0b0e3962e" @@ -17031,11 +16896,6 @@ node-releases@^2.0.6: resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.6.tgz#8a7088c63a55e493845683ebf3c828d8c51c5503" integrity sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg== -node-statsd@^0.1.1: - version "0.1.1" - resolved "https://registry.npmjs.org/node-statsd/-/node-statsd-0.1.1.tgz" - integrity sha1-J6WTSHY9CvegN6wqAx/vPwUQE9M= - node.extend@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/node.extend/-/node.extend-2.0.2.tgz#b4404525494acc99740f3703c496b7d5182cc6cc" @@ -17178,11 +17038,6 @@ oauth-sign@~0.9.0: resolved "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz" integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== -oauth@0.9.x: - version "0.9.15" - resolved "https://registry.yarnpkg.com/oauth/-/oauth-0.9.15.tgz#bd1fefaf686c96b75475aed5196412ff60cfb9c1" - integrity sha1-vR/vr2hslrdUda7VGWQS/2DPucE= - object-assign@^4, object-assign@^4.1.0, object-assign@^4.1.1: version "4.1.1" resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz" @@ -17815,20 +17670,6 @@ pascal-case@^3.1.2: no-case "^3.0.4" tslib "^2.0.3" -passport-discord@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/passport-discord/-/passport-discord-0.1.4.tgz#9265be11952cdd54d77c47eaae352834444cf0f6" - integrity sha512-VJWPYqSOmh7SaCLw/C+k1ZqCzJnn2frrmQRx1YrcPJ3MQ+Oa31XclbbmqFICSvl8xv3Fqd6YWQ4H4p1MpIN9rA== - dependencies: - passport-oauth2 "^1.5.0" - -passport-github2@^0.1.12: - version "0.1.12" - resolved "https://registry.yarnpkg.com/passport-github2/-/passport-github2-0.1.12.tgz#a72ebff4fa52a35bc2c71122dcf470d1116f772c" - integrity sha512-3nPUCc7ttF/3HSP/k9sAXjz3SkGv5Nki84I05kSQPo01Jqq1NzJACgMblCK0fGcv9pKCG/KXU3AJRDGLqHLoIw== - dependencies: - passport-oauth2 "1.x.x" - passport-jwt@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/passport-jwt/-/passport-jwt-4.0.0.tgz#7f0be7ba942e28b9f5d22c2ebbb8ce96ef7cf065" @@ -17855,17 +17696,6 @@ passport-magic@^1.0.0: passport-local "^1.0.0" passport-strategy "^1.0.0" -passport-oauth2@1.x.x, passport-oauth2@^1.5.0: - version "1.6.1" - resolved "https://registry.yarnpkg.com/passport-oauth2/-/passport-oauth2-1.6.1.tgz#c5aee8f849ce8bd436c7f81d904a3cd1666f181b" - integrity sha512-ZbV43Hq9d/SBSYQ22GOiglFsjsD1YY/qdiptA+8ej+9C1dL1TVB+mBE5kDH/D4AJo50+2i8f4bx0vg4/yDDZCQ== - dependencies: - base64url "3.x.x" - oauth "0.9.x" - passport-strategy "1.x.x" - uid2 "0.0.x" - utils-merge "1.x.x" - passport-strategy@1.x.x, passport-strategy@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/passport-strategy/-/passport-strategy-1.0.0.tgz#b5539aa8fc225a3d1ad179476ddf236b440f52e4" @@ -18855,7 +18685,7 @@ postgres-interval@^1.1.0: dependencies: xtend "^4.0.0" -prebuild-install@^7.1.0, prebuild-install@^7.1.1: +prebuild-install@^7.1.0: version "7.1.1" resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-7.1.1.tgz#de97d5b34a70a0c81334fd24641f2a1702352e45" integrity sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw== @@ -19755,7 +19585,7 @@ react@^18.2.0: dependencies: loose-envify "^1.1.0" -read-pkg-up@^7.0.0, read-pkg-up@^7.0.1: +read-pkg-up@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-7.0.1.tgz#f3a6135758459733ae2b95638056e1854e7ef507" integrity sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg== @@ -20788,20 +20618,6 @@ shallow-clone@^3.0.0: dependencies: kind-of "^6.0.2" -sharp@^0.31.2: - version "0.31.3" - resolved "https://registry.yarnpkg.com/sharp/-/sharp-0.31.3.tgz#60227edc5c2be90e7378a210466c99aefcf32688" - integrity sha512-XcR4+FCLBFKw1bdB+GEhnUNXNXvnt0tDo4WsBsraKymuo/IAuPuCBVAL2wIkUw2r/dwFW5Q5+g66Kwl2dgDFVg== - dependencies: - color "^4.2.3" - detect-libc "^2.0.1" - node-addon-api "^5.0.0" - prebuild-install "^7.1.1" - semver "^7.3.8" - simple-get "^4.0.1" - tar-fs "^2.1.1" - tunnel-agent "^0.6.0" - shebang-command@^1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz" @@ -20886,7 +20702,7 @@ simple-get@^2.7.0: once "^1.3.1" simple-concat "^1.0.0" -simple-get@^4.0.0, simple-get@^4.0.1: +simple-get@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-4.0.1.tgz#4a39db549287c979d352112fa03fd99fd6bc3543" integrity sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA== @@ -21076,11 +20892,6 @@ source-map@^0.5.0, source-map@^0.5.7: resolved "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz" integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= -source-map@^0.7.3: - version "0.7.3" - resolved "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz" - integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== - sparse-array@^1.3.1: version "1.3.2" resolved "https://registry.yarnpkg.com/sparse-array/-/sparse-array-1.3.2.tgz#0e1a8b71706d356bc916fe754ff496d450ec20b0" @@ -21997,7 +21808,7 @@ tape@^5.5.3: string.prototype.trim "^1.2.7" through "^2.3.8" -tar-fs@^2.0.0, tar-fs@^2.1.1: +tar-fs@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.1.1.tgz#489a15ab85f1f0befabb370b7de4f9eb5cbe8784" integrity sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng== @@ -22137,11 +21948,6 @@ thread-stream@^0.15.1: dependencies: real-require "^0.1.0" -throttled-queue@^1.0.7: - version "1.0.7" - resolved "https://registry.npmjs.org/throttled-queue/-/throttled-queue-1.0.7.tgz" - integrity sha512-/HT49S7m+NvdyJMoMRzIYlawKjeHn8jEc8TZaGmFi5IBu09hIiU/QoP1zcrB9X2qsVC11PgfRfqd8zEQs7PlEA== - through2@^2.0.0: version "2.0.5" resolved "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz" @@ -22211,11 +22017,6 @@ tiny-secp256k1@^1.1.3: elliptic "^6.4.0" nan "^2.13.2" -tinytim@0.1.1: - version "0.1.1" - resolved "https://registry.npmjs.org/tinytim/-/tinytim-0.1.1.tgz" - integrity sha1-yWih5VWa2VUyJO92J7qzTjyu+Kg= - tmp-promise@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/tmp-promise/-/tmp-promise-3.0.2.tgz#6e933782abff8b00c3119d63589ca1fb9caaa62a" @@ -22300,15 +22101,6 @@ tr46@~0.0.3: resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" integrity sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o= -tracer@~0.7.3: - version "0.7.4" - resolved "https://registry.npmjs.org/tracer/-/tracer-0.7.4.tgz" - integrity sha1-d/oEN8+Ct2vNvNRLhHRHcuWeUlk= - dependencies: - colors "1.0.3" - dateformat "1.0.11" - tinytim "0.1.1" - traverse-chain@~0.1.0: version "0.1.0" resolved "https://registry.npmjs.org/traverse-chain/-/traverse-chain-0.1.0.tgz" @@ -22804,11 +22596,6 @@ uid-safe@~2.1.5: dependencies: random-bytes "~1.0.0" -uid2@0.0.x: - version "0.0.4" - resolved "https://registry.yarnpkg.com/uid2/-/uid2-0.0.4.tgz#033f3b1d5d32505f5ce5f888b9f3b667123c0a44" - integrity sha512-IevTus0SbGwQzYh3+fRsAMTVVPOoIVufzacXcHPmdlle1jUpq7BRL+mw3dgeLanvGZdwwbWhRV6XrcFNdBmjWA== - uint8-varint@^1.0.1, uint8-varint@^1.0.2, uint8-varint@^1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/uint8-varint/-/uint8-varint-1.0.6.tgz#bacf9526b0ddcd38fd6645e17895a4ee42d2bec4" @@ -23245,19 +23032,11 @@ utility-types@^3.10.0: resolved "https://registry.yarnpkg.com/utility-types/-/utility-types-3.10.0.tgz#ea4148f9a741015f05ed74fd615e1d20e6bed82b" integrity sha512-O11mqxmi7wMKCo6HKFt5AhO4BwY3VV68YU07tgxfz8zJTIxr4BpsezN49Ffwy9j3ZpwwJp4fkRwjRzq3uWE6Rg== -utils-merge@1.0.1, utils-merge@1.x.x: +utils-merge@1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz" integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= -utilx@0.0.5: - version "0.0.5" - resolved "https://registry.npmjs.org/utilx/-/utilx-0.0.5.tgz" - integrity sha1-OhBnyM2yzB/uTGLnIbGERnVK9M4= - dependencies: - colorful "2.1.0" - iconv-lite "0.2.11" - uuid@3.0.x: version "3.0.1" resolved "https://registry.npmjs.org/uuid/-/uuid-3.0.1.tgz" @@ -23366,16 +23145,6 @@ vary@^1, vary@~1.1.2: resolved "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz" integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= -velocity@^0.7.2: - version "0.7.2" - resolved "https://registry.npmjs.org/velocity/-/velocity-0.7.2.tgz" - integrity sha1-614WK+GYoXULtGQVZvtW7yv38do= - dependencies: - colorful "~2.1.0" - commander "~2.3.0" - tracer "~0.7.3" - utilx "0.0.5" - vendors@^1.0.0: version "1.0.4" resolved "https://registry.yarnpkg.com/vendors/-/vendors-1.0.4.tgz#e2b800a53e7a29b93506c3cf41100d16c4c4ad8e" @@ -24280,14 +24049,6 @@ yargs-parser@20.2.4: resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54" integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA== -yargs-parser@^16.1.0: - version "16.1.0" - resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-16.1.0.tgz" - integrity sha512-H/V41UNZQPkUMIT5h5hiwg4QKIY1RPvoBV4XcjUbRM8Bk2oKqqyZ0DIEbTFZB0XjbtSPG8SAa/0DxCQmiRgzKg== - dependencies: - camelcase "^5.0.0" - decamelize "^1.2.0" - yargs-parser@^18.1.2: version "18.1.3" resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz" From ab057261169d48a4cf37899c15198275b7e04fb3 Mon Sep 17 00:00:00 2001 From: Ifu Aniemeka Date: Fri, 5 Jan 2024 12:19:26 -0600 Subject: [PATCH 3/3] #5506 - Create upvote popover (#5992) * create upvote popover * update styling; variable names * remove console log statement * set empty array as default value for upvoters * no popover shows if 0 upvoters * fix user info styling * use CWText for vote weight and upvoter count * add type for arg to createUpvoterList function * put mouseover on div wrapping button to allow clicking user in popover * add close button for mobile --- .../UpvotePopover/UpvotePopover.scss | 42 ++++++++++ .../UpvotePopover/UpvotePopover.tsx | 80 +++++++++++++++++++ .../views/components/UpvotePopover/index.tsx | 3 + .../component_kit/cw_component_showcase.tsx | 27 +++++++ .../new_designs/CWPopover/CWPopover.tsx | 12 ++- .../component_kit/cw_component_showcase.scss | 7 +- 6 files changed, 168 insertions(+), 3 deletions(-) create mode 100644 packages/commonwealth/client/scripts/views/components/UpvotePopover/UpvotePopover.scss create mode 100644 packages/commonwealth/client/scripts/views/components/UpvotePopover/UpvotePopover.tsx create mode 100644 packages/commonwealth/client/scripts/views/components/UpvotePopover/index.tsx diff --git a/packages/commonwealth/client/scripts/views/components/UpvotePopover/UpvotePopover.scss b/packages/commonwealth/client/scripts/views/components/UpvotePopover/UpvotePopover.scss new file mode 100644 index 00000000000..8cd9b1cb44d --- /dev/null +++ b/packages/commonwealth/client/scripts/views/components/UpvotePopover/UpvotePopover.scss @@ -0,0 +1,42 @@ +@import '../../../../styles/shared.scss'; + +.Popover.UpvotePopover { + padding: 8px 0; + width: 256px; + + .popover-title { + padding: 8px 16px; + margin-bottom: 0; + } + + .upvoters-list { + display: flex; + flex-direction: column; + + .upvoter-row { + display: flex; + height: 40px; + justify-content: space-between; + align-items: center; + padding: 0 20px; + align-self: stretch; + + .User { + .user-display-name { + font-size: 12px; + font-weight: 500; + line-height: 16px; + letter-spacing: 0.24px; + } + } + } + } + + .upvoter-count { + height: 40px; + padding: 0 20px; + display: flex; + align-items: center; + color: $neutral-400; + } +} \ No newline at end of file diff --git a/packages/commonwealth/client/scripts/views/components/UpvotePopover/UpvotePopover.tsx b/packages/commonwealth/client/scripts/views/components/UpvotePopover/UpvotePopover.tsx new file mode 100644 index 00000000000..ea94b19565f --- /dev/null +++ b/packages/commonwealth/client/scripts/views/components/UpvotePopover/UpvotePopover.tsx @@ -0,0 +1,80 @@ +import React from 'react'; +import { isMobile } from 'react-device-detect'; +import app from 'state'; +import { CWText } from '../component_kit/cw_text'; +import CWIconButton from '../component_kit/new_designs/CWIconButton'; +import CWPopover, { + UsePopoverProps, +} from '../component_kit/new_designs/CWPopover/CWPopover'; +import { User } from '../user/user'; +import './UpvotePopover.scss'; + +type UpvotePopoverProps = { + upvoters: string[]; +} & UsePopoverProps; + +export const UpvotePopover = ({ + upvoters = [], + ...popoverProps +}: UpvotePopoverProps) => { + const maxVisibleUpvotingAccounts = 3; + + const createUpvoterList = (upvoterAddresses: string[]) => { + const slicedUpvoters = upvoterAddresses + .slice(0, maxVisibleUpvotingAccounts) + .map((upvoterAddress) => { + return ( +
+ + + 5x + +
+ ); + }); + + if (upvoterAddresses.length > maxVisibleUpvotingAccounts) { + slicedUpvoters.push( + {`${upvoterAddresses.length} votes total`}, + ); + } + + return
{slicedUpvoters}
; + }; + + return ( + <> + {upvoters.length > 0 && ( + + Recent Upvotes + {isMobile && ( +
+ +
+ )} + + } + body={createUpvoterList(upvoters)} + {...popoverProps} + /> + )} + + ); +}; diff --git a/packages/commonwealth/client/scripts/views/components/UpvotePopover/index.tsx b/packages/commonwealth/client/scripts/views/components/UpvotePopover/index.tsx new file mode 100644 index 00000000000..bd7867b3583 --- /dev/null +++ b/packages/commonwealth/client/scripts/views/components/UpvotePopover/index.tsx @@ -0,0 +1,3 @@ +import { UpvotePopover } from './UpvotePopover'; + +export default UpvotePopover; diff --git a/packages/commonwealth/client/scripts/views/components/component_kit/cw_component_showcase.tsx b/packages/commonwealth/client/scripts/views/components/component_kit/cw_component_showcase.tsx index af2c61d2ec5..e92a741ec71 100644 --- a/packages/commonwealth/client/scripts/views/components/component_kit/cw_component_showcase.tsx +++ b/packages/commonwealth/client/scripts/views/components/component_kit/cw_component_showcase.tsx @@ -23,6 +23,7 @@ import CWFormSteps from 'views/components/component_kit/new_designs/CWFormSteps' import CWPopover, { usePopover, } from 'views/components/component_kit/new_designs/CWPopover'; + import { createDeltaFromText, ReactQuillEditor, @@ -31,6 +32,7 @@ import { openConfirmation } from 'views/modals/confirmation_modal'; import { z } from 'zod'; import { AvatarUpload } from '../Avatar'; import CommunityStakeBanner from '../CommunityStakeBanner'; +import UpvotePopover from '../UpvotePopover'; import { CWCard } from './cw_card'; import { CWCheckbox } from './cw_checkbox'; import { CWCollapsible } from './cw_collapsible'; @@ -238,6 +240,7 @@ export const ComponentShowcase = () => { const unstyledPopoverProps = usePopover(); const styledPopoverProps = usePopover(); + const upvotePopoverProps = usePopover(); const renderModal = (size?: ModalSize) => { return ( @@ -380,6 +383,30 @@ export const ComponentShowcase = () => { /> +
+ Upvote Popover +
+ + +
+
Popover Menu { const popoverContent = content || ( -
+
( + { className }, + ComponentType.Popover, + )} + > {title && ( {title} diff --git a/packages/commonwealth/client/styles/components/component_kit/cw_component_showcase.scss b/packages/commonwealth/client/styles/components/component_kit/cw_component_showcase.scss index da93561ac08..54b03329f96 100644 --- a/packages/commonwealth/client/styles/components/component_kit/cw_component_showcase.scss +++ b/packages/commonwealth/client/styles/components/component_kit/cw_component_showcase.scss @@ -33,6 +33,10 @@ $width: 360px; color: $neutral-400; } } + + .upvote-popover-wrapper { + width: fit-content + } } .progress-gallery { @@ -237,6 +241,7 @@ $width: 360px; .multi-select, .typeahead { + .multi-select-row, .typeahead-row { margin-bottom: 15px; @@ -269,4 +274,4 @@ $width: 360px; margin-bottom: 15px; } } -} +} \ No newline at end of file