From 6d3d73c7fe2e8979c957435efea46219484c21b3 Mon Sep 17 00:00:00 2001 From: CarlosQ96 <92376054+CarlosQ96@users.noreply.github.com> Date: Sun, 2 Jun 2024 04:42:46 -0500 Subject: [PATCH] Release upgrades + Base integration (#1586) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add activeQfRoundId to sortingBy InstantBoosting * add orderBy totalDonations and totalReactions * feat: add getRecurringDonationStats resolver * fix filtering by QF * remove qfRounds joins for non qf round filters * add some temp logs * remove temp logs * fix: changes test cases of recuring donations stats - create recored with createdAt field in past so test result won't be related to other endpoints test cases * Fix projectActualserviceView * fix stream balance depleted issue (#1496) Co-authored-by: mohammadranjbarz * rebuild * refresh and fetch user address separately (#1499) * Added pg_trgm extension migration (#1502) * fix: change recurring donations stats query to single query * fix recurring donation count * WIP: projectIds textArea * fix actual matching cap (#1507) * fix query error * fix user donations count * fix recurring donation count tests * fix user recurring donation query * fix user recurring donation test * add donations relation to qfround * add findArchivedQfRounds endpoint * add findArchivedQfRounds endpoint * feat: add sponsors & banner images upload * add sortBy to findArchivedQfRounds * 1.23.3 * add new test graphql query * add tests for new QfArchivedRounds * fixes on qfArchivedRounds query * add new tests for qfArchivedRounds query * fix findArchivedQfRounds tests * fix: keep already uploaded sponsors images * fix skip and limit for findArchivedQfRounds * Add logs and refactor the bootstrap code to help investigate latency problem * Add poolSize to orm config * Fix eslint errors * remove changing squareRootSumOfProjects when cap is overflown * Trigger ortto activity when user saves their profile info for the first time (#1520) * add newUser to updateUser query * add createOrttoProfile * add createOrttoProfile to NotificationAdapterInterface * add createOrttoProfile to MockNotificationAdapter * add CREATE_ORTTO_PROFILE event * Allow to set the matching pool token & amount to be something other than usd (#1517) * Allow to set the matching pool token & amount to be something other than USD in adminjs * Allow to set the matching pool token & amount to be something other than USD in QFRound table * add null to allocatedTokenSymbol and allocatedTokenChainId * add nullable true to allocatedTokenSymbol and allocatedTokenChainId * add allocatedFundUSDPreferred and allocatedFundUSD to qfRound * Comment migrations * Hotfix db improvements (#1523) * add extra configurations for postgresql connections * add master and slave replication strategy for typeorm * add qfRound to qfRoundStats * fix qfRoundStatsQuery * Hotfix staging fix latency (#1528) * add project donation summary view entity * convert projectQueries to querybuilder * add cache to projectDonationSummary queries * add configurable cache to slow queries * remove massive recurring donation log * add await for project queries * Add logs to projectVerificationForm * Add logs to projectVerificationForm * fix: add project Ids list textarea for qf round edit * Master to staging (#1543) * Hotfix db improvements (#1523) (#1524) * add extra configurations for postgresql connections * add master and slave replication strategy for typeorm Co-authored-by: CarlosQ96 <92376054+CarlosQ96@users.noreply.github.com> * Fix/db replica production (#1525) * Hotfix db improvements (#1523) * add extra configurations for postgresql connections * add master and slave replication strategy for typeorm * Define db read only configs --------- Co-authored-by: CarlosQ96 <92376054+CarlosQ96@users.noreply.github.com> * update comment * Hotfix latency issues for prod (#1529) * Hotfix staging fix latency (#1528) * add project donation summary view entity * convert projectQueries to querybuilder * add cache to projectDonationSummary queries * add configurable cache to slow queries * remove massive recurring donation log * add await for project queries * Add informative logs for draft donation service job (#1537) * Fix eslint errors * Fix/master test (#1541) * Fixed master test issue * Returned test to master pipeline * Comment executing donation summary view --------- Co-authored-by: Mohammad Ranjbar Z --------- Co-authored-by: CarlosQ96 <92376054+CarlosQ96@users.noreply.github.com> Co-authored-by: Carlos Co-authored-by: mohammadranjbarz * Fix/word similarity - staging (#1546) * Hotfix db improvements (#1523) (#1524) * add extra configurations for postgresql connections * add master and slave replication strategy for typeorm Co-authored-by: CarlosQ96 <92376054+CarlosQ96@users.noreply.github.com> * Fix/db replica production (#1525) * Hotfix db improvements (#1523) * add extra configurations for postgresql connections * add master and slave replication strategy for typeorm * Define db read only configs --------- Co-authored-by: CarlosQ96 <92376054+CarlosQ96@users.noreply.github.com> * update comment * Hotfix latency issues for prod (#1529) * Hotfix staging fix latency (#1528) * add project donation summary view entity * convert projectQueries to querybuilder * add cache to projectDonationSummary queries * add configurable cache to slow queries * remove massive recurring donation log * add await for project queries * Add informative logs for draft donation service job (#1537) * Fix eslint errors * Fix/master test (#1541) * Fixed master test issue * Returned test to master pipeline * Comment executing donation summary view --------- Co-authored-by: Mohammad Ranjbar Z * Fixed word similarity issue * Removed unused import --------- Co-authored-by: CarlosQ96 <92376054+CarlosQ96@users.noreply.github.com> Co-authored-by: Carlos Co-authored-by: mohammadranjbarz * remove refresh_project_summary_from totals and add user cache (#1539) * Remove users field from project * Remove users field from filterProjectsQuery * Remove projects field from user * remove added logs * fix eslint errors * remove users from Project.create * remove users from Project.create in testUtils.ts * remove projectOwnerId * replace admin with adminUserId * Add recurring donation join to donations() endpoint (#1554) related to #1483 * replace admin with adminUserId in SEED data * replace admin with adminUserId * replace admin with adminUserId in projectResolver.ts * replace admin with adminUserId in projectsTab.ts * replace admin with adminUserId in projectResolver.test.ts * replace admin with adminUserId in projectResolver.ts * add allocatedFundUSD and allocatedTokenSymbol to qfArchivedRounds * fix nullable * remove admin from project * replace admin with adminUserId * replace admin with adminUserId * add adminUserId field * drop admin column * Implementing read-only node replica in local * fix: add telegram to ProjectSocialMediaType enum to allow adding telegram url * Add some logs * Fix eslint errors * Add maxQueuedJobs for draft donation worker * Fix eslint errors * fix unstable test case * Disable concurrency for draft donation worker * add indexes to project_summary_view (#1568) * improve projectBySlug query * fix: change output types to float * Ignore small differences of amounts when matching draft donation for erc20 * add graphql-fields * add getVerificationFormStatusByProjectId * refactor projectBySlug * add findProjectIdBySlug * fix projectBySlug tests with new changes * fix projectBySlug tests with new changes * fix projectBySlug tests with new changes * remove projectVerificationForm assert * add logs * fix title in should return projects with indicated slug test * Add streamed mini donations to qf round (#1557) * Add streamed mini donations to qf round related to Giveth/giveth-dapps-v2#3284 * Fix eslint error * Fix eslint errors * make verificationFormStatus field public * Reduce test runnning time (#1574) * fix: reduce test runnning time * fix: add permissions test case * fix: add permissions test case * fix: refactor (excluding permissions test cases from global beforeEach) * add migration and columns for totals in project entity (#1571) * add migration and columns for totals in project entity * add service to update project totals * add filling the value for new fields * WIP add base network * add word similarity to search * fix word similarity test case * add defaultMode to replication * Continue on integrating with base chain * Fix migrations * Fix migrations * optimize projectById * add passport score to streams minidonations * Add methods for adding matching to totals usd received (#1582) * add methods for adding matching to totals usd received * Update src/repositories/qfRoundHistoryRepository.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --------- Co-authored-by: mohammadranjbarz Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * add coalesce to get 0 always incase null total matching * Add test cases about filteriing base network * Add BASE node http urls for rpc * Add BASE node http urls for rpc * Add missing things for integrating with base * merge stage * Limit characters of each cell to less than 5000 characters * Fix eslint errors * Fix creating new token with coingeckoId related to https://github.com/Giveth/impact-graph/issues/1564 * Fill base mainnet tokens related to https://github.com/Giveth/impact-graph/issues/1561 * optimize qfRounds query * Add base chain (#1579) * Ignore small differences of amounts when matching draft donation for … (#1573) * Ignore small differences of amounts when matching draft donation for erc20 * Fix eslint errors * Release Integrate QF with super fluid streamed donations (#1555) * add activeQfRoundId to sortingBy InstantBoosting * add orderBy totalDonations and totalReactions * feat: add getRecurringDonationStats resolver * fix filtering by QF * remove qfRounds joins for non qf round filters * add some temp logs * remove temp logs * fix: changes test cases of recuring donations stats - create recored with createdAt field in past so test result won't be related to other endpoints test cases * Fix projectActualserviceView * fix stream balance depleted issue (#1496) Co-authored-by: mohammadranjbarz * rebuild * refresh and fetch user address separately (#1499) * Added pg_trgm extension migration (#1502) * fix: change recurring donations stats query to single query * fix recurring donation count * WIP: projectIds textArea * fix actual matching cap (#1507) * fix query error * fix user donations count * fix recurring donation count tests * fix user recurring donation query * fix user recurring donation test * add donations relation to qfround * add findArchivedQfRounds endpoint * add findArchivedQfRounds endpoint * feat: add sponsors & banner images upload * add sortBy to findArchivedQfRounds * 1.23.3 * add new test graphql query * add tests for new QfArchivedRounds * fixes on qfArchivedRounds query * add new tests for qfArchivedRounds query * fix findArchivedQfRounds tests * fix: keep already uploaded sponsors images * fix skip and limit for findArchivedQfRounds * Add logs and refactor the bootstrap code to help investigate latency problem * Add poolSize to orm config * Fix eslint errors * remove changing squareRootSumOfProjects when cap is overflown * Trigger ortto activity when user saves their profile info for the first time (#1520) * add newUser to updateUser query * add createOrttoProfile * add createOrttoProfile to NotificationAdapterInterface * add createOrttoProfile to MockNotificationAdapter * add CREATE_ORTTO_PROFILE event * Allow to set the matching pool token & amount to be something other than usd (#1517) * Allow to set the matching pool token & amount to be something other than USD in adminjs * Allow to set the matching pool token & amount to be something other than USD in QFRound table * add null to allocatedTokenSymbol and allocatedTokenChainId * add nullable true to allocatedTokenSymbol and allocatedTokenChainId * add allocatedFundUSDPreferred and allocatedFundUSD to qfRound * Comment migrations * Hotfix db improvements (#1523) * add extra configurations for postgresql connections * add master and slave replication strategy for typeorm * add qfRound to qfRoundStats * fix qfRoundStatsQuery * Hotfix staging fix latency (#1528) * add project donation summary view entity * convert projectQueries to querybuilder * add cache to projectDonationSummary queries * add configurable cache to slow queries * remove massive recurring donation log * add await for project queries * Add logs to projectVerificationForm * Add logs to projectVerificationForm * fix: add project Ids list textarea for qf round edit * Master to staging (#1543) * Hotfix db improvements (#1523) (#1524) * add extra configurations for postgresql connections * add master and slave replication strategy for typeorm Co-authored-by: CarlosQ96 <92376054+CarlosQ96@users.noreply.github.com> * Fix/db replica production (#1525) * Hotfix db improvements (#1523) * add extra configurations for postgresql connections * add master and slave replication strategy for typeorm * Define db read only configs --------- Co-authored-by: CarlosQ96 <92376054+CarlosQ96@users.noreply.github.com> * update comment * Hotfix latency issues for prod (#1529) * Hotfix staging fix latency (#1528) * add project donation summary view entity * convert projectQueries to querybuilder * add cache to projectDonationSummary queries * add configurable cache to slow queries * remove massive recurring donation log * add await for project queries * Add informative logs for draft donation service job (#1537) * Fix eslint errors * Fix/master test (#1541) * Fixed master test issue * Returned test to master pipeline * Comment executing donation summary view --------- Co-authored-by: Mohammad Ranjbar Z --------- Co-authored-by: CarlosQ96 <92376054+CarlosQ96@users.noreply.github.com> Co-authored-by: Carlos Co-authored-by: mohammadranjbarz * Fix/word similarity - staging (#1546) * Hotfix db improvements (#1523) (#1524) * add extra configurations for postgresql connections * add master and slave replication strategy for typeorm Co-authored-by: CarlosQ96 <92376054+CarlosQ96@users.noreply.github.com> * Fix/db replica production (#1525) * Hotfix db improvements (#1523) * add extra configurations for postgresql connections * add master and slave replication strategy for typeorm * Define db read only configs --------- Co-authored-by: CarlosQ96 <92376054+CarlosQ96@users.noreply.github.com> * update comment * Hotfix latency issues for prod (#1529) * Hotfix staging fix latency (#1528) * add project donation summary view entity * convert projectQueries to querybuilder * add cache to projectDonationSummary queries * add configurable cache to slow queries * remove massive recurring donation log * add await for project queries * Add informative logs for draft donation service job (#1537) * Fix eslint errors * Fix/master test (#1541) * Fixed master test issue * Returned test to master pipeline * Comment executing donation summary view --------- Co-authored-by: Mohammad Ranjbar Z * Fixed word similarity issue * Removed unused import --------- Co-authored-by: CarlosQ96 <92376054+CarlosQ96@users.noreply.github.com> Co-authored-by: Carlos Co-authored-by: mohammadranjbarz * remove refresh_project_summary_from totals and add user cache (#1539) * Remove users field from project * Remove users field from filterProjectsQuery * Remove projects field from user * remove added logs * fix eslint errors * remove users from Project.create * remove users from Project.create in testUtils.ts * remove projectOwnerId * replace admin with adminUserId * Add recurring donation join to donations() endpoint (#1554) related to #1483 * replace admin with adminUserId in SEED data * replace admin with adminUserId * replace admin with adminUserId in projectResolver.ts * replace admin with adminUserId in projectsTab.ts * replace admin with adminUserId in projectResolver.test.ts * replace admin with adminUserId in projectResolver.ts * add allocatedFundUSD and allocatedTokenSymbol to qfArchivedRounds * fix nullable * remove admin from project * replace admin with adminUserId * replace admin with adminUserId * add adminUserId field * drop admin column * fix: add telegram to ProjectSocialMediaType enum to allow adding telegram url * Add some logs * Fix eslint errors * Add maxQueuedJobs for draft donation worker * Fix eslint errors * fix unstable test case * Disable concurrency for draft donation worker * add indexes to project_summary_view (#1568) * improve projectBySlug query * fix: change output types to float * Ignore small differences of amounts when matching draft donation for erc20 * add graphql-fields * add getVerificationFormStatusByProjectId * refactor projectBySlug * add findProjectIdBySlug * fix projectBySlug tests with new changes * fix projectBySlug tests with new changes * fix projectBySlug tests with new changes * remove projectVerificationForm assert * add logs * fix title in should return projects with indicated slug test * Add streamed mini donations to qf round (#1557) * Add streamed mini donations to qf round related to Giveth/giveth-dapps-v2#3284 * Fix eslint error * Fix eslint errors * make verificationFormStatus field public * Reduce test runnning time (#1574) * fix: reduce test runnning time * fix: add permissions test case * fix: add permissions test case * fix: refactor (excluding permissions test cases from global beforeEach) --------- Co-authored-by: Ramin Co-authored-by: Meriem-BM Co-authored-by: CarlosQ96 <92376054+CarlosQ96@users.noreply.github.com> Co-authored-by: Amin Latifi Co-authored-by: Carlos * WIP add base network * Continue on integrating with base chain * Fix migrations * Fix migrations * Add test cases about filteriing base network * Add BASE node http urls for rpc * Add BASE node http urls for rpc * Add missing things for integrating with base * Fix creating new token with coingeckoId related to https://github.com/Giveth/impact-graph/issues/1564 * Fill base mainnet tokens related to https://github.com/Giveth/impact-graph/issues/1561 --------- Co-authored-by: Ramin Co-authored-by: Meriem-BM Co-authored-by: CarlosQ96 <92376054+CarlosQ96@users.noreply.github.com> Co-authored-by: Amin Latifi Co-authored-by: Carlos * Add coingeckoId to BASE_SEPOLIA (#1592) * Ignore small differences of amounts when matching draft donation for … (#1573) * Ignore small differences of amounts when matching draft donation for erc20 * Fix eslint errors * Release Integrate QF with super fluid streamed donations (#1555) * add activeQfRoundId to sortingBy InstantBoosting * add orderBy totalDonations and totalReactions * feat: add getRecurringDonationStats resolver * fix filtering by QF * remove qfRounds joins for non qf round filters * add some temp logs * remove temp logs * fix: changes test cases of recuring donations stats - create recored with createdAt field in past so test result won't be related to other endpoints test cases * Fix projectActualserviceView * fix stream balance depleted issue (#1496) Co-authored-by: mohammadranjbarz * rebuild * refresh and fetch user address separately (#1499) * Added pg_trgm extension migration (#1502) * fix: change recurring donations stats query to single query * fix recurring donation count * WIP: projectIds textArea * fix actual matching cap (#1507) * fix query error * fix user donations count * fix recurring donation count tests * fix user recurring donation query * fix user recurring donation test * add donations relation to qfround * add findArchivedQfRounds endpoint * add findArchivedQfRounds endpoint * feat: add sponsors & banner images upload * add sortBy to findArchivedQfRounds * 1.23.3 * add new test graphql query * add tests for new QfArchivedRounds * fixes on qfArchivedRounds query * add new tests for qfArchivedRounds query * fix findArchivedQfRounds tests * fix: keep already uploaded sponsors images * fix skip and limit for findArchivedQfRounds * Add logs and refactor the bootstrap code to help investigate latency problem * Add poolSize to orm config * Fix eslint errors * remove changing squareRootSumOfProjects when cap is overflown * Trigger ortto activity when user saves their profile info for the first time (#1520) * add newUser to updateUser query * add createOrttoProfile * add createOrttoProfile to NotificationAdapterInterface * add createOrttoProfile to MockNotificationAdapter * add CREATE_ORTTO_PROFILE event * Allow to set the matching pool token & amount to be something other than usd (#1517) * Allow to set the matching pool token & amount to be something other than USD in adminjs * Allow to set the matching pool token & amount to be something other than USD in QFRound table * add null to allocatedTokenSymbol and allocatedTokenChainId * add nullable true to allocatedTokenSymbol and allocatedTokenChainId * add allocatedFundUSDPreferred and allocatedFundUSD to qfRound * Comment migrations * Hotfix db improvements (#1523) * add extra configurations for postgresql connections * add master and slave replication strategy for typeorm * add qfRound to qfRoundStats * fix qfRoundStatsQuery * Hotfix staging fix latency (#1528) * add project donation summary view entity * convert projectQueries to querybuilder * add cache to projectDonationSummary queries * add configurable cache to slow queries * remove massive recurring donation log * add await for project queries * Add logs to projectVerificationForm * Add logs to projectVerificationForm * fix: add project Ids list textarea for qf round edit * Master to staging (#1543) * Hotfix db improvements (#1523) (#1524) * add extra configurations for postgresql connections * add master and slave replication strategy for typeorm Co-authored-by: CarlosQ96 <92376054+CarlosQ96@users.noreply.github.com> * Fix/db replica production (#1525) * Hotfix db improvements (#1523) * add extra configurations for postgresql connections * add master and slave replication strategy for typeorm * Define db read only configs --------- Co-authored-by: CarlosQ96 <92376054+CarlosQ96@users.noreply.github.com> * update comment * Hotfix latency issues for prod (#1529) * Hotfix staging fix latency (#1528) * add project donation summary view entity * convert projectQueries to querybuilder * add cache to projectDonationSummary queries * add configurable cache to slow queries * remove massive recurring donation log * add await for project queries * Add informative logs for draft donation service job (#1537) * Fix eslint errors * Fix/master test (#1541) * Fixed master test issue * Returned test to master pipeline * Comment executing donation summary view --------- Co-authored-by: Mohammad Ranjbar Z --------- Co-authored-by: CarlosQ96 <92376054+CarlosQ96@users.noreply.github.com> Co-authored-by: Carlos Co-authored-by: mohammadranjbarz * Fix/word similarity - staging (#1546) * Hotfix db improvements (#1523) (#1524) * add extra configurations for postgresql connections * add master and slave replication strategy for typeorm Co-authored-by: CarlosQ96 <92376054+CarlosQ96@users.noreply.github.com> * Fix/db replica production (#1525) * Hotfix db improvements (#1523) * add extra configurations for postgresql connections * add master and slave replication strategy for typeorm * Define db read only configs --------- Co-authored-by: CarlosQ96 <92376054+CarlosQ96@users.noreply.github.com> * update comment * Hotfix latency issues for prod (#1529) * Hotfix staging fix latency (#1528) * add project donation summary view entity * convert projectQueries to querybuilder * add cache to projectDonationSummary queries * add configurable cache to slow queries * remove massive recurring donation log * add await for project queries * Add informative logs for draft donation service job (#1537) * Fix eslint errors * Fix/master test (#1541) * Fixed master test issue * Returned test to master pipeline * Comment executing donation summary view --------- Co-authored-by: Mohammad Ranjbar Z * Fixed word similarity issue * Removed unused import --------- Co-authored-by: CarlosQ96 <92376054+CarlosQ96@users.noreply.github.com> Co-authored-by: Carlos Co-authored-by: mohammadranjbarz * remove refresh_project_summary_from totals and add user cache (#1539) * Remove users field from project * Remove users field from filterProjectsQuery * Remove projects field from user * remove added logs * fix eslint errors * remove users from Project.create * remove users from Project.create in testUtils.ts * remove projectOwnerId * replace admin with adminUserId * Add recurring donation join to donations() endpoint (#1554) related to #1483 * replace admin with adminUserId in SEED data * replace admin with adminUserId * replace admin with adminUserId in projectResolver.ts * replace admin with adminUserId in projectsTab.ts * replace admin with adminUserId in projectResolver.test.ts * replace admin with adminUserId in projectResolver.ts * add allocatedFundUSD and allocatedTokenSymbol to qfArchivedRounds * fix nullable * remove admin from project * replace admin with adminUserId * replace admin with adminUserId * add adminUserId field * drop admin column * fix: add telegram to ProjectSocialMediaType enum to allow adding telegram url * Add some logs * Fix eslint errors * Add maxQueuedJobs for draft donation worker * Fix eslint errors * fix unstable test case * Disable concurrency for draft donation worker * add indexes to project_summary_view (#1568) * improve projectBySlug query * fix: change output types to float * Ignore small differences of amounts when matching draft donation for erc20 * add graphql-fields * add getVerificationFormStatusByProjectId * refactor projectBySlug * add findProjectIdBySlug * fix projectBySlug tests with new changes * fix projectBySlug tests with new changes * fix projectBySlug tests with new changes * remove projectVerificationForm assert * add logs * fix title in should return projects with indicated slug test * Add streamed mini donations to qf round (#1557) * Add streamed mini donations to qf round related to Giveth/giveth-dapps-v2#3284 * Fix eslint error * Fix eslint errors * make verificationFormStatus field public * Reduce test runnning time (#1574) * fix: reduce test runnning time * fix: add permissions test case * fix: add permissions test case * fix: refactor (excluding permissions test cases from global beforeEach) --------- Co-authored-by: Ramin Co-authored-by: Meriem-BM Co-authored-by: CarlosQ96 <92376054+CarlosQ96@users.noreply.github.com> Co-authored-by: Amin Latifi Co-authored-by: Carlos * WIP add base network * Continue on integrating with base chain * Fix migrations * Fix migrations * Add test cases about filteriing base network * Add BASE node http urls for rpc * Add BASE node http urls for rpc * Add missing things for integrating with base * Fix creating new token with coingeckoId related to https://github.com/Giveth/impact-graph/issues/1564 * Fill base mainnet tokens related to https://github.com/Giveth/impact-graph/issues/1561 * add coingeckoId to BASE_SEPOLIA --------- Co-authored-by: mohammadranjbarz Co-authored-by: Ramin Co-authored-by: CarlosQ96 <92376054+CarlosQ96@users.noreply.github.com> Co-authored-by: Amin Latifi Co-authored-by: Carlos Co-authored-by: Meriem-B <135605616+Meriem-B@users.noreply.github.com> * Deleting redis * sync all donations totals (#1594) * sync all donations totals * add update qfroundmatching * Add coingeckoId for BASE ETH * Changee isGivbaclEligble of base chain tokens to false --------- Co-authored-by: Ramin Co-authored-by: Meriem-BM Co-authored-by: Mohammad Ranjbar Z Co-authored-by: Amin Latifi Co-authored-by: Rolazo Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: Meriem-B <135605616+Meriem-B@users.noreply.github.com> Co-authored-by: Nicolas <38561963+Rolazo@users.noreply.github.com> --- .github/workflows/develop-pipeline.yml | 2 + .github/workflows/master-pipeline.yml | 2 + .github/workflows/staging-pipeline.yml | 2 + config/example.env | 11 + config/test.env | 6 + docker-compose-local-postgres-db-readonly.yml | 44 +++ .../1716367359560-add_base_chain_tokens.ts | 55 ++++ migration/data/seedTokens.ts | 288 ++++++++++++++++++ package.json | 4 +- src/entities/project.ts | 1 + src/orm.ts | 1 + src/provider.ts | 50 +++ src/repositories/qfRoundRepository.ts | 28 +- src/resolvers/donationResolver.test.ts | 2 +- .../projectResolver.allProject.test.ts | 107 ++++++- src/resolvers/projectResolver.test.ts | 1 - src/resolvers/projectResolver.ts | 79 ++++- .../projectVerificationFormResolver.test.ts | 10 + src/resolvers/qfRoundResolver.ts | 17 +- src/server/adminJs/tabs/donationTab.ts | 2 + src/server/adminJs/tabs/qfRoundTab.ts | 2 + src/server/adminJs/tabs/tokenTab.ts | 4 + src/services/chains/index.test.ts | 38 +++ src/services/googleSheets.ts | 20 +- src/utils/networksConfig.ts | 2 + .../validators/graphqlQueryValidators.ts | 2 + src/utils/validators/projectValidator.ts | 2 + test/graphqlQueries.ts | 1 - test/pre-test-scripts.ts | 28 ++ test/testUtils.ts | 18 ++ 30 files changed, 797 insertions(+), 32 deletions(-) create mode 100644 docker-compose-local-postgres-db-readonly.yml create mode 100644 migration/1716367359560-add_base_chain_tokens.ts diff --git a/.github/workflows/develop-pipeline.yml b/.github/workflows/develop-pipeline.yml index bf6209ae8..58a3f5af2 100644 --- a/.github/workflows/develop-pipeline.yml +++ b/.github/workflows/develop-pipeline.yml @@ -65,6 +65,8 @@ jobs: CELO_ALFAJORES_SCAN_API_KEY: ${{ secrets.CELO_ALFAJORES_SCAN_API_KEY }} ARBITRUM_SCAN_API_KEY: ${{ secrets.ARBITRUM_SCAN_API_KEY }} ARBITRUM_SEPOLIA_SCAN_API_KEY: ${{ secrets.ARBITRUM_SEPOLIA_SCAN_API_KEY }} + BASE_SCAN_API_KEY: ${{ secrets.BASE_SCAN_API_KEY }} + BASE_SEPOLIA_SCAN_API_KEY: ${{ secrets.BASE_SEPOLIA_SCAN_API_KEY }} MORDOR_ETC_TESTNET: ${{ secrets.MORDOR_ETC_TESTNET }} ETC_NODE_HTTP_URL: ${{ secrets.ETC_NODE_HTTP_URL }} SOLANA_TEST_NODE_RPC_URL: ${{ secrets.SOLANA_TEST_NODE_RPC_URL }} diff --git a/.github/workflows/master-pipeline.yml b/.github/workflows/master-pipeline.yml index 6bcebcb83..433ab725d 100644 --- a/.github/workflows/master-pipeline.yml +++ b/.github/workflows/master-pipeline.yml @@ -102,6 +102,8 @@ jobs: CELO_ALFAJORES_SCAN_API_KEY: ${{ secrets.CELO_ALFAJORES_SCAN_API_KEY }} ARBITRUM_SCAN_API_KEY: ${{ secrets.ARBITRUM_SCAN_API_KEY }} ARBITRUM_SEPOLIA_SCAN_API_KEY: ${{ secrets.ARBITRUM_SEPOLIA_SCAN_API_KEY }} + BASE_SCAN_API_KEY: ${{ secrets.BASE_SCAN_API_KEY }} + BASE_SEPOLIA_SCAN_API_KEY: ${{ secrets.BASE_SEPOLIA_SCAN_API_KEY }} MORDOR_ETC_TESTNET: ${{ secrets.MORDOR_ETC_TESTNET }} ETC_NODE_HTTP_URL: ${{ secrets.ETC_NODE_HTTP_URL }} DROP_DATABASE: ${{ secrets.DROP_DATABASE_DURING_TEST_PROD }} diff --git a/.github/workflows/staging-pipeline.yml b/.github/workflows/staging-pipeline.yml index 388f4660c..b49337e84 100644 --- a/.github/workflows/staging-pipeline.yml +++ b/.github/workflows/staging-pipeline.yml @@ -102,6 +102,8 @@ jobs: CELO_ALFAJORES_SCAN_API_KEY: ${{ secrets.CELO_ALFAJORES_SCAN_API_KEY }} ARBITRUM_SCAN_API_KEY: ${{ secrets.ARBITRUM_SCAN_API_KEY }} ARBITRUM_SEPOLIA_SCAN_API_KEY: ${{ secrets.ARBITRUM_SEPOLIA_SCAN_API_KEY }} + BASE_SCAN_API_KEY: ${{ secrets.BASE_SCAN_API_KEY }} + BASE_SEPOLIA_SCAN_API_KEY: ${{ secrets.BASE_SEPOLIA_SCAN_API_KEY }} MORDOR_ETC_TESTNET: ${{ secrets.MORDOR_ETC_TESTNET }} ETC_NODE_HTTP_URL: ${{ secrets.ETC_NODE_HTTP_URL }} DROP_DATABASE: ${{ secrets.DROP_DATABASE_DURING_TEST_STAGING }} diff --git a/config/example.env b/config/example.env index 8c3393325..18fb2d657 100644 --- a/config/example.env +++ b/config/example.env @@ -307,3 +307,14 @@ ENABLE_DRAFT_RECURRING_DONATION=true DRAFT_RECURRING_DONATION_MATCH_EXPIRATION_HOURS=24 OPTIMISTIC_SEPOLIA_SCAN_API_KEY= + +BASE_SCAN_API_URL=https://api.basescan.org/api +BASE_SCAN_API_KEY=0000000000000000000000000000000000 +BASE_SEPOLIA_SCAN_API_URL=https://api-sepolia.basescan.org/api +BASE_SEPOLIA_SCAN_API_KEY=0000000000000000000000000000000000 + +# BASE MAINNET +BASE_MAINNET_NODE_HTTP_URL= + +# BASE SEPOLIA +BASE_SEPOLIA_NODE_HTTP_URL= diff --git a/config/test.env b/config/test.env index ef55172b7..6092dca7c 100644 --- a/config/test.env +++ b/config/test.env @@ -47,6 +47,12 @@ ARBITRUM_SCAN_API_URL=https://api.arbiscan.io/api ARBITRUM_SCAN_API_KEY=0000000000000000000000000000000000 ARBITRUM_SEPOLIA_SCAN_API_URL=https://api-sepolia.arbiscan.io/api ARBITRUM_SEPOLIA_SCAN_API_KEY=0000000000000000000000000000000000 + +BASE_SCAN_API_URL=https://api.basescan.org/api +BASE_SCAN_API_KEY=0000000000000000000000000000000000 +BASE_SEPOLIA_SCAN_API_URL=https://api-sepolia.basescan.org/api +BASE_SEPOLIA_SCAN_API_KEY=0000000000000000000000000000000000 + GNOSISSCAN_API_URL=https://api.gnosisscan.io/api ETHERSCAN_API_KEY=00000000000000000000000000000000 GNOSISSCAN_API_KEY=0000000000000000000000000000000000 diff --git a/docker-compose-local-postgres-db-readonly.yml b/docker-compose-local-postgres-db-readonly.yml new file mode 100644 index 000000000..3e56f8800 --- /dev/null +++ b/docker-compose-local-postgres-db-readonly.yml @@ -0,0 +1,44 @@ +services: + impact-graph-postgres: + # Use this postgres image https://github.com/Giveth/postgres-givethio + image: ghcr.io/giveth/postgres-givethio:latest + restart: always + environment: + - POSTGRES_DB=givethio + - POSTGRES_USER=postgres + - POSTGRES_PASSWORD=postgres + - PGDATA=/var/lib/postgresql/data/pgdata + ports: + - "5432:5432" + volumes: + - db-data:/var/lib/postgresql/data + + impact-graph-postgres-replica: + # Read-only replica of the main Postgres container + image: ghcr.io/giveth/postgres-givethio:latest + restart: always + environment: + - POSTGRES_DB=givethio + - POSTGRES_USER=postgres + - POSTGRES_PASSWORD=postgres + - PGDATA=/var/lib/postgresql/data/pgdata + - POSTGRES_PRIMARY_HOST=impact-graph-postgres + - POSTGRES_PRIMARY_PORT=5432 + - POSTGRES_PRIMARY_USER=postgres + - POSTGRES_PRIMARY_PASSWORD=postgres + - POSTGRES_REPLICA=true + ports: + - "5431:5432" + volumes: + - db-data-replica:/var/lib/postgresql/data + networks: + - giveth + + +volumes: + db-data: + db-data-replica: + + +networks: + giveth: \ No newline at end of file diff --git a/migration/1716367359560-add_base_chain_tokens.ts b/migration/1716367359560-add_base_chain_tokens.ts new file mode 100644 index 000000000..4e5f0eb00 --- /dev/null +++ b/migration/1716367359560-add_base_chain_tokens.ts @@ -0,0 +1,55 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; +import { Token } from '../src/entities/token'; +import seedTokens from './data/seedTokens'; +import config from '../src/config'; +import { NETWORK_IDS } from '../src/provider'; + +export class AddBaseChainTokens1716367359560 implements MigrationInterface { + public async up(queryRunner: QueryRunner): Promise { + const environment = config.get('ENVIRONMENT') as string; + + const networkId = + environment === 'production' + ? NETWORK_IDS.BASE_MAINNET + : NETWORK_IDS.BASE_SEPOLIA; + + await queryRunner.manager.save( + Token, + seedTokens + .filter(token => token.networkId === networkId) + .map(token => { + const t = { + ...token, + }; + t.address = t.address?.toLowerCase(); + delete t.chainType; + return t; + }), + ); + const tokens = await queryRunner.query(` + SELECT * FROM token + WHERE "networkId" = ${networkId} + `); + const givethOrganization = ( + await queryRunner.query(`SELECT * FROM organization + WHERE label='giveth'`) + )[0]; + + const traceOrganization = ( + await queryRunner.query(`SELECT * FROM organization + WHERE label='trace'`) + )[0]; + + for (const token of tokens) { + // Add all Base tokens to Giveth organization + await queryRunner.query(`INSERT INTO organization_tokens_token ("tokenId","organizationId") VALUES + (${token.id}, ${givethOrganization.id}), + (${token.id}, ${traceOrganization.id}) + ;`); + } + } + + public async down(_queryRunner: QueryRunner): Promise { + // + } +} diff --git a/migration/data/seedTokens.ts b/migration/data/seedTokens.ts index be4fe6dec..f9193b370 100644 --- a/migration/data/seedTokens.ts +++ b/migration/data/seedTokens.ts @@ -15,6 +15,7 @@ interface ITokenData { coingeckoId?: string; isStableCoin?: boolean; } + const seedTokens: ITokenData[] = [ // Mainnet tokens { @@ -1593,6 +1594,293 @@ const seedTokens: ITokenData[] = [ networkId: NETWORK_IDS.ARBITRUM_MAINNET, coingeckoId: 'cartesi', }, + + // BASE Sepolia + { + name: 'BASE', + symbol: 'ETH', + address: '0x0000000000000000000000000000000000000000', + decimals: 18, + networkId: NETWORK_IDS.BASE_SEPOLIA, + coingeckoId: 'ethereum', + }, + + // BASE Mainnet - https://basescan.org/token/0x0000000000000000000000000000000000000000 + { + name: 'BASE', + symbol: 'ETH', + address: '0x0000000000000000000000000000000000000000', + decimals: 18, + networkId: NETWORK_IDS.BASE_MAINNET, + coingeckoId: 'ethereum', + isGivbackEligible: false, + }, + + // USDC - https://basescan.org/token/0x833589fcd6edb6e08f4c7c32d4f71b54bda02913 + { + name: 'USDC', + symbol: 'USDC', + address: '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913', + decimals: 6, + networkId: NETWORK_IDS.BASE_MAINNET, + coingeckoId: 'usd-coin', + isGivbackEligible: false, + isStableCoin: true, + }, + // Dai Stablecoin - https://basescan.org/token/0x50c5725949a6f0c72e6c4a641f24049a917db0cb + { + name: 'Dai Stablecoin', + symbol: 'DAI', + address: '0x50c5725949a6f0c72e6c4a641f24049a917db0cb', + decimals: 18, + networkId: NETWORK_IDS.BASE_MAINNET, + coingeckoId: 'dai', + isGivbackEligible: false, + isStableCoin: true, + }, + // Rocket Pool ETH - https://basescan.org/token/0xb6fe221fe9eef5aba221c348ba20a1bf5e73624c + { + name: 'Rocket Pool ETH', + symbol: 'rETH', + address: '0xb6fe221fe9eef5aba221c348ba20a1bf5e73624c', + decimals: 18, + networkId: NETWORK_IDS.BASE_MAINNET, + coingeckoId: 'rocket-pool-eth', + isGivbackEligible: false, + }, + // Synthetix Network Token - https://basescan.org/token/0x22e6966b799c4d5b13be962e1d117b56327fda66 + { + name: 'Synthetix Network Token', + symbol: 'SNX', + address: '0x22e6966b799c4d5b13be962e1d117b56327fda66', + decimals: 18, + networkId: NETWORK_IDS.BASE_MAINNET, + coingeckoId: 'havven', + isGivbackEligible: false, + }, + // Coinbase Wrapped Staked ETH - https://basescan.org/token/0x2ae3f1ec7f1f5012cfeab0185bfc7aa3cf0dec22 + { + name: 'Coinbase Wrapped Staked ETH', + symbol: 'cbETH', + address: '0x2ae3f1ec7f1f5012cfeab0185bfc7aa3cf0dec22', + decimals: 18, + networkId: NETWORK_IDS.BASE_MAINNET, + coingeckoId: 'coinbase-wrapped-staked-eth', + isGivbackEligible: false, + }, + // Prime - https://basescan.org/token/0xfA980cEd6895AC314E7dE34Ef1bFAE90a5AdD21b + { + name: 'Prime', + symbol: 'PRIME', + address: '0xfA980cEd6895AC314E7dE34Ef1bFAE90a5AdD21b', + decimals: 18, + networkId: NETWORK_IDS.BASE_MAINNET, + coingeckoId: 'echelon-prime', + isGivbackEligible: false, + }, + // Aerodrome - https://basescan.org/token/0x940181a94a35a4569e4529a3cdfb74e38fd98631 + { + name: 'Aerodrome', + symbol: 'AERO', + address: '0x940181a94a35a4569e4529a3cdfb74e38fd98631', + decimals: 18, + networkId: NETWORK_IDS.BASE_MAINNET, + coingeckoId: 'aerodrome-finance', + isGivbackEligible: false, + }, + // Degen - https://basescan.org/token/0x4ed4e862860bed51a9570b96d89af5e1b0efefed + { + name: 'Degen', + symbol: 'DEGEN', + address: '0x4ed4e862860bed51a9570b96d89af5e1b0efefed', + decimals: 18, + networkId: NETWORK_IDS.BASE_MAINNET, + coingeckoId: 'degen-base', + isGivbackEligible: false, + }, + // Osaka Protocol - https://basescan.org/token/0xbFd5206962267c7b4b4A8B3D76AC2E1b2A5c4d5e + { + name: 'Osaka Protocol', + symbol: 'OSAK', + address: '0xbFd5206962267c7b4b4A8B3D76AC2E1b2A5c4d5e', + decimals: 18, + networkId: NETWORK_IDS.BASE_MAINNET, + coingeckoId: 'osaka-protocol', + isGivbackEligible: false, + }, + // BTRST - https://basescan.org/token/0xa7d68d155d17cb30e311367c2ef1e82ab6022b67 + { + name: 'BTRST', + symbol: 'BTRST', + address: '0xa7d68d155d17cb30e311367c2ef1e82ab6022b67', + decimals: 18, + networkId: NETWORK_IDS.BASE_MAINNET, + coingeckoId: 'braintrust', + isGivbackEligible: false, + }, + // SmarDex Token - https://basescan.org/token/0xfd4330b0312fdeec6d4225075b82e00493ff2e3f + { + name: 'SmarDex Token', + symbol: 'SDEX', + address: '0xfd4330b0312fdeec6d4225075b82e00493ff2e3f', + decimals: 18, + networkId: NETWORK_IDS.BASE_MAINNET, + coingeckoId: 'smardex', + isGivbackEligible: false, + }, + // Spectral Token - https://basescan.org/token/0x96419929d7949d6a801a6909c145c8eef6a40431 + { + name: 'Spectral Token', + symbol: 'SPEC', + address: '0x96419929d7949d6a801a6909c145c8eef6a40431', + decimals: 18, + networkId: NETWORK_IDS.BASE_MAINNET, + coingeckoId: 'spectral', + isGivbackEligible: false, + }, + // Heroes of Mavia - https://basescan.org/token/0x24fcFC492C1393274B6bcd568ac9e225BEc93584 + { + name: 'Heroes of Mavia', + symbol: 'MAVIA', + address: '0x24fcFC492C1393274B6bcd568ac9e225BEc93584', + decimals: 18, + networkId: NETWORK_IDS.BASE_MAINNET, + coingeckoId: 'heroes-of-mavia', + isGivbackEligible: false, + }, + // Maverick Token - https://basescan.org/token/0x64b88c73a5dfa78d1713fe1b4c69a22d7e0faaa7 + { + name: 'Maverick Token', + symbol: 'MAV', + address: '0x64b88c73a5dfa78d1713fe1b4c69a22d7e0faaa7', + decimals: 18, + networkId: NETWORK_IDS.BASE_MAINNET, + coingeckoId: 'maverick-protocol', + isGivbackEligible: false, + }, + // Dola USD Stablecoin - https://basescan.org/token/0x4621b7a9c75199271f773ebd9a499dbd165c3191 + { + name: 'Dola USD Stablecoin', + symbol: 'DOLA', + address: '0x4621b7a9c75199271f773ebd9a499dbd165c3191', + decimals: 18, + networkId: NETWORK_IDS.BASE_MAINNET, + coingeckoId: 'dola-usd', + isGivbackEligible: false, + isStableCoin: true, + }, + // USD+ - https://basescan.org/token/0xb79dd08ea68a908a97220c76d19a6aa9cbde4376 + { + name: 'USD+', + symbol: 'USD+', + address: '0xb79dd08ea68a908a97220c76d19a6aa9cbde4376', + decimals: 18, + networkId: NETWORK_IDS.BASE_MAINNET, + coingeckoId: 'usd', + isGivbackEligible: false, + isStableCoin: true, + }, + // Magic Internet Money - https://basescan.org/token/0x4A3A6Dd60A34bB2Aba60D73B4C88315E9CeB6A3D + { + name: 'Magic Internet Money', + symbol: 'MIM', + address: '0x4A3A6Dd60A34bB2Aba60D73B4C88315E9CeB6A3D', + decimals: 18, + networkId: NETWORK_IDS.BASE_MAINNET, + coingeckoId: 'magic-internet-money', + isGivbackEligible: false, + }, + // Seamless - https://basescan.org/token/0x1c7a460413dd4e964f96d8dfc56e7223ce88cd85 + { + name: 'Seamless', + symbol: 'SEAM', + address: '0x1c7a460413dd4e964f96d8dfc56e7223ce88cd85', + decimals: 18, + networkId: NETWORK_IDS.BASE_MAINNET, + coingeckoId: 'seamless-protocol', + isGivbackEligible: false, + }, + // Extra Finance - https://basescan.org/token/0x2dad3a13ef0c6366220f989157009e501e7938f8 + { + name: 'Extra Finance', + symbol: 'EXTRA', + address: '0x2dad3a13ef0c6366220f989157009e501e7938f8', + decimals: 18, + networkId: NETWORK_IDS.BASE_MAINNET, + coingeckoId: 'extra-finance', + isGivbackEligible: false, + }, + // agEUR - https://basescan.org/token/0xa61beb4a3d02decb01039e378237032b351125b4 + { + name: 'agEUR', + symbol: 'agEUR', + address: '0xa61beb4a3d02decb01039e378237032b351125b4', + decimals: 18, + networkId: NETWORK_IDS.BASE_MAINNET, + coingeckoId: 'ageur-plenty-bridge', + isGivbackEligible: false, + isStableCoin: true, + }, + // SubQueryToken - https://basescan.org/token/0x858c50C3AF1913b0E849aFDB74617388a1a5340d + { + name: 'SubQueryToken', + symbol: 'SQT', + address: '0x858c50C3AF1913b0E849aFDB74617388a1a5340d', + decimals: 18, + networkId: NETWORK_IDS.BASE_MAINNET, + coingeckoId: 'subquery-network', + isGivbackEligible: false, + }, + // Rai.Finance - https://basescan.org/token/0x703d57164ca270b0b330a87fd159cfef1490c0a5 + { + name: 'Rai.Finance', + symbol: 'SOFI', + address: '0x703d57164ca270b0b330a87fd159cfef1490c0a5', + decimals: 18, + networkId: NETWORK_IDS.BASE_MAINNET, + coingeckoId: 'rai-finance', + isGivbackEligible: false, + }, + // UNJD (MBS) - https://basescan.org/token/0x8fbd0648971d56f1f2c35fa075ff5bc75fb0e39d + { + name: 'UNJD', + symbol: 'MBS', + address: '0x8fbd0648971d56f1f2c35fa075ff5bc75fb0e39d', + decimals: 18, + networkId: NETWORK_IDS.BASE_MAINNET, + coingeckoId: 'monkeyball', + isGivbackEligible: false, + }, + // Rigo Token - https://basescan.org/token/0x09188484e1ab980daef53a9755241d759c5b7d60 + { + name: 'Rigo Token', + symbol: 'GRG', + address: '0x09188484e1ab980daef53a9755241d759c5b7d60', + decimals: 18, + networkId: NETWORK_IDS.BASE_MAINNET, + coingeckoId: 'rigoblock', + isGivbackEligible: false, + }, + // DEUS - https://basescan.org/token/0xde5ed76e7c05ec5e4572cfc88d1acea165109e44 + { + name: 'DEUS', + symbol: 'DEUS', + address: '0xde5ed76e7c05ec5e4572cfc88d1acea165109e44', + decimals: 18, + networkId: NETWORK_IDS.BASE_MAINNET, + coingeckoId: 'deus-finance-2', + isGivbackEligible: false, + }, + // Alongside Crypto Market Index - https://basescan.org/token/0x13f4196cc779275888440b3000ae533bbbbc3166 + { + name: 'Alongside Crypto Market Index', + symbol: 'AMKT', + address: '0x13f4196cc779275888440b3000ae533bbbbc3166', + decimals: 18, + networkId: NETWORK_IDS.BASE_MAINNET, + coingeckoId: 'alongside-crypto-market-index', + isGivbackEligible: false, + }, ]; export default seedTokens; diff --git a/package.json b/package.json index 4174475a4..76f307419 100644 --- a/package.json +++ b/package.json @@ -145,7 +145,7 @@ "test:reactionResolver": "NODE_ENV=test mocha ./test/pre-test-scripts.ts ./src/resolvers/reactionResolver.test.ts", "test:donationResolver": "NODE_ENV=test mocha ./test/pre-test-scripts.ts ./src/resolvers/donationResolver.test.ts", "test:draftDonationResolver": "NODE_ENV=test mocha ./test/pre-test-scripts.ts ./src/resolvers/draftDonationResolver.test.ts", - "test:projectResolver": "NODE_ENV=test mocha ./test/pre-test-scripts.ts ./src/resolvers/projectResolver.test.ts", + "test:projectResolver": "NODE_ENV=test mocha ./test/pre-test-scripts.ts ./src/resolvers/projectResolver.test.ts ./src/resolvers/projectResolver.allProject.test.ts", "test:chainvineResolver": "NODE_ENV=test mocha ./test/pre-test-scripts.ts ./src/resolvers/chainvineResolver.test.ts", "test:qfRoundResolver": "NODE_ENV=test mocha ./test/pre-test-scripts.ts ./src/resolvers/qfRoundResolver.test.ts", "test:qfRoundHistoryResolver": "NODE_ENV=test mocha ./test/pre-test-scripts.ts ./src/resolvers/qfRoundHistoryResolver.test.ts", @@ -192,7 +192,7 @@ "test:instantPowerBoostingService": "NODE_ENV=test mocha ./test/pre-test-scripts.ts ./src/services/instantBoostingServices.test.ts", "test:actualMatchingFundView": "NODE_ENV=test mocha ./test/pre-test-scripts.ts ./src/services/actualMatchingFundView.test.ts", "test:categoryResolver": "NODE_ENV=test mocha ./test/pre-test-scripts.ts ./src/resolvers/categoryResolver.test.ts", - "test:givpower": "NODE_ENV=test mocha -b -t 30000 ./test/pre-test-scripts.ts ./src/repositories/powerBoostingRepository.test.ts ./src/repositories/userPowerRepository.test.ts ./src/repositories/powerRoundRepository.test.ts ./src/repositories/userProjectPowerViewRepository.test.ts ./src/repositories/projectPowerViewRepository.test.ts ./src/resolvers/powerBoostingResolver.test.ts ./src/resolvers/userProjectPowerResolver.test.ts ./src/resolvers/projectPowerResolver.test.ts ./src/adapters/givpowerSubgraph/givPowerSubgraphAdapter.test.ts ./src/repositories/projectRepository.test.ts ./src/resolvers/projectResolver.test.ts ./src/repositories/dbCronRepository.test.ts", + "test:givpower": "NODE_ENV=test mocha -b -t 30000 ./test/pre-test-scripts.ts ./src/repositories/powerBoostingRepository.test.ts ./src/repositories/userPowerRepository.test.ts ./src/repositories/powerRoundRepository.test.ts ./src/repositories/userProjectPowerViewRepository.test.ts ./src/repositories/projectPowerViewRepository.test.ts ./src/resolvers/powerBoostingResolver.test.ts ./src/resolvers/userProjectPowerResolver.test.ts ./src/resolvers/projectPowerResolver.test.ts ./src/adapters/givpowerSubgraph/givPowerSubgraphAdapter.test.ts ./src/repositories/projectRepository.test.ts ./src/resolvers/projectResolver.test.ts ./src/resolvers/projectResolver.allProject.test.ts ./src/repositories/dbCronRepository.test.ts", "test:apiGive": "NODE_ENV=test mocha ./test/pre-test-scripts.ts ./src/routers/apiGivRoutes.test.ts", "test:adminJs": "NODE_ENV=test mocha ./test/pre-test-scripts.ts ./src/server/adminJs/**/*.test.ts ", "test:adminJsRolePermissions": "NODE_ENV=test mocha ./test/pre-test-scripts.ts ./src/server/adminJs/adminJsPermissions.test.ts", diff --git a/src/entities/project.ts b/src/entities/project.ts index 479a12979..f5bfbdb0d 100644 --- a/src/entities/project.ts +++ b/src/entities/project.ts @@ -86,6 +86,7 @@ export enum FilterField { AcceptFundOnETC = 'acceptFundOnETC', AcceptFundOnCelo = 'acceptFundOnCelo', AcceptFundOnArbitrum = 'acceptFundOnArbitrum', + AcceptFundOnBase = 'acceptFundOnBase', AcceptFundOnOptimism = 'acceptFundOnOptimism', AcceptFundOnSolana = 'acceptFundOnSolana', GivingBlock = 'fromGivingBlock', diff --git a/src/orm.ts b/src/orm.ts index e1f399452..7961e434e 100644 --- a/src/orm.ts +++ b/src/orm.ts @@ -29,6 +29,7 @@ export class AppDataSource { schema: 'public', type: 'postgres', replication: { + defaultMode: 'master', master: { database: config.get('TYPEORM_DATABASE_NAME') as string, username: config.get('TYPEORM_DATABASE_USER') as string, diff --git a/src/provider.ts b/src/provider.ts index a3b972971..26fa243f8 100644 --- a/src/provider.ts +++ b/src/provider.ts @@ -1,6 +1,7 @@ import { ethers } from 'ethers'; import config from './config'; import { i18n, translationErrorMessagesKeys } from './utils/errorMessages'; +import { logger } from './utils/logger'; const INFURA_ID = config.get('INFURA_ID'); @@ -21,6 +22,9 @@ export const NETWORK_IDS = { ARBITRUM_MAINNET: 42161, ARBITRUM_SEPOLIA: 421614, + BASE_MAINNET: 8453, + BASE_SEPOLIA: 84532, + // https://docs.particle.network/developers/other-services/node-service/solana-api SOLANA_MAINNET: 101, SOLANA_TESTNET: 102, @@ -154,6 +158,8 @@ const NETWORK_NAMES = { MORDOR_ETC_TESTNET: 'Ethereum Classic Testnet', ARBITRUM_MAINNET: 'Arbitrum Mainnet', ARBITRUM_SEPOLIA: 'Arbitrum Sepolia', + BASE_MAINNET: 'Base Mainnet', + BASE_SEPOLIA: 'Base Sepolia', }; const NETWORK_NATIVE_TOKENS = { @@ -171,6 +177,8 @@ const NETWORK_NATIVE_TOKENS = { MORDOR_ETC_TESTNET: 'mETC', ARBITRUM_MAINNET: 'ETH', ARBITRUM_SEPOLIA: 'ETH', + BASE_MAINNET: 'ETH', + BASE_SEPOLIA: 'ETH', }; const networkNativeTokensList = [ @@ -244,6 +252,16 @@ const networkNativeTokensList = [ networkId: NETWORK_IDS.ARBITRUM_SEPOLIA, nativeToken: NETWORK_NATIVE_TOKENS.ARBITRUM_SEPOLIA, }, + { + networkName: NETWORK_NAMES.BASE_MAINNET, + networkId: NETWORK_IDS.BASE_MAINNET, + nativeToken: NETWORK_NATIVE_TOKENS.BASE_MAINNET, + }, + { + networkName: NETWORK_NAMES.BASE_SEPOLIA, + networkId: NETWORK_IDS.BASE_SEPOLIA, + nativeToken: NETWORK_NATIVE_TOKENS.BASE_SEPOLIA, + }, ]; export function getNetworkNameById(networkId: number): string { @@ -251,6 +269,10 @@ export function getNetworkNameById(networkId: number): string { item => item.networkId === networkId, ); if (!networkInfo) { + logger.error( + 'getNetworkNameById() error networkNativeTokensList doesnt have info for networkId', + networkId, + ); throw new Error(i18n.__(translationErrorMessagesKeys.INVALID_NETWORK_ID)); } return networkInfo.networkName; @@ -261,6 +283,10 @@ export function getNetworkNativeToken(networkId: number): string { return item.networkId === networkId; }); if (!networkInfo) { + logger.error( + 'getNetworkNativeToken() error networkNativeTokensList doesnt have info for networkId', + networkId, + ); throw new Error(i18n.__(translationErrorMessagesKeys.INVALID_NETWORK_ID)); } return networkInfo.nativeToken; @@ -319,6 +345,18 @@ export function getProvider(networkId: number) { `https://arbitrum-sepolia.infura.io/v3/${INFURA_ID}`; break; + case NETWORK_IDS.BASE_MAINNET: + url = + (process.env.BASE_MAINNET_NODE_HTTP_URL as string) || + `https://base-mainnet.infura.io/v3/${INFURA_ID}`; + break; + + case NETWORK_IDS.BASE_SEPOLIA: + url = + (process.env.BASE_SEPOLIA_NODE_HTTP_URL as string) || + `https://base-sepolia.infura.io/v3/${INFURA_ID}`; + break; + default: { // Use infura const connectionInfo = ethers.providers.InfuraProvider.getUrl( @@ -398,7 +436,19 @@ export function getBlockExplorerApiUrl(networkId: number): string { apiUrl = config.get('ARBITRUM_SEPOLIA_SCAN_API_URL'); apiKey = config.get('ARBITRUM_SEPOLIA_SCAN_API_KEY'); break; + case NETWORK_IDS.BASE_MAINNET: + apiUrl = config.get('BASE_SCAN_API_URL'); + apiKey = config.get('BASE_SCAN_API_KEY'); + break; + case NETWORK_IDS.BASE_SEPOLIA: + apiUrl = config.get('BASE_SEPOLIA_SCAN_API_URL'); + apiKey = config.get('BASE_SEPOLIA_SCAN_API_KEY'); + break; default: + logger.error( + 'getBlockExplorerApiUrl() no url found for networkId', + networkId, + ); throw new Error(i18n.__(translationErrorMessagesKeys.INVALID_NETWORK_ID)); } diff --git a/src/repositories/qfRoundRepository.ts b/src/repositories/qfRoundRepository.ts index bc8e6f3ac..cc24d32dc 100644 --- a/src/repositories/qfRoundRepository.ts +++ b/src/repositories/qfRoundRepository.ts @@ -1,16 +1,34 @@ import { Field, Float, Int, ObjectType, registerEnumType } from 'type-graphql'; import { QfRound } from '../entities/qfRound'; import { AppDataSource } from '../orm'; -import { QfArchivedRoundsOrderBy } from '../resolvers/qfRoundResolver'; +import { + QfArchivedRoundsOrderBy, + QfRoundsArgs, +} from '../resolvers/qfRoundResolver'; const qfRoundEstimatedMatchingParamsCacheDuration = Number( process.env.QF_ROUND_ESTIMATED_MATCHING_CACHE_DURATION || 60000, ); -export const findAllQfRounds = async (): Promise => { - return QfRound.createQueryBuilder('qf_round') - .addOrderBy('qf_round.id', 'DESC') - .getMany(); +export const findAllQfRounds = async ({ + slug, + activeOnly, +}: QfRoundsArgs): Promise => { + const query = QfRound.createQueryBuilder('qf_round').addOrderBy( + 'qf_round.id', + 'DESC', + ); + if (slug) { + query.where('slug = :slug', { slug }); + } + if (activeOnly) { + query.andWhere('"isActive" = true'); + } + if (slug || activeOnly) { + const res = await query.getOne(); + return res ? [res] : []; + } + return query.getMany(); }; export enum QfArchivedRoundsSortType { diff --git a/src/resolvers/donationResolver.test.ts b/src/resolvers/donationResolver.test.ts index 10edd7f07..74916e03c 100644 --- a/src/resolvers/donationResolver.test.ts +++ b/src/resolvers/donationResolver.test.ts @@ -2611,7 +2611,7 @@ function createDonationTestCases() { ); assert.equal( saveDonationResponse.data.errors[0].message, - '"transactionNetworkId" must be one of [1, 3, 5, 100, 137, 10, 11155420, 56, 42220, 44787, 61, 63, 42161, 421614, 101, 102, 103]', + '"transactionNetworkId" must be one of [1, 3, 5, 100, 137, 10, 11155420, 56, 42220, 44787, 61, 63, 42161, 421614, 8453, 84532, 101, 102, 103]', ); }); it('should not throw exception when currency is not valid when currency is USDC.e', async () => { diff --git a/src/resolvers/projectResolver.allProject.test.ts b/src/resolvers/projectResolver.allProject.test.ts index 854400e34..5dfea13bc 100644 --- a/src/resolvers/projectResolver.allProject.test.ts +++ b/src/resolvers/projectResolver.allProject.test.ts @@ -918,7 +918,6 @@ function allProjectsTestCases() { ), ); }); - it('should return projects, filter by accept donation on arbitrum, not return when it doesnt have arbitrum address', async () => { const arbitrumProject = await saveProjectDirectlyToDb({ ...createProjectData(), @@ -964,6 +963,112 @@ function allProjectsTestCases() { ); }); + it('should return projects, filter by accept donation on base', async () => { + const savedProject = await saveProjectDirectlyToDb({ + ...createProjectData(), + title: String(new Date().getTime()), + slug: String(new Date().getTime()), + networkId: NETWORK_IDS.BASE_MAINNET, + }); + const result = await axios.post(graphqlUrl, { + query: fetchMultiFilterAllProjectsQuery, + variables: { + filters: ['AcceptFundOnBase'], + sortingBy: SortingField.Newest, + }, + }); + result.data.data.allProjects.projects.forEach(project => { + assert.isOk( + project.addresses.find( + address => + address.isRecipient === true && + (address.networkId === NETWORK_IDS.BASE_MAINNET || + address.networkId === NETWORK_IDS.BASE_SEPOLIA), + ), + ); + }); + assert.isOk( + result.data.data.allProjects.projects.find( + project => Number(project.id) === Number(savedProject.id), + ), + ); + }); + it('should return projects, filter by accept donation on base', async () => { + const savedProject = await saveProjectDirectlyToDb({ + ...createProjectData(), + title: String(new Date().getTime()), + slug: String(new Date().getTime()), + networkId: NETWORK_IDS.BASE_MAINNET, + }); + const result = await axios.post(graphqlUrl, { + query: fetchMultiFilterAllProjectsQuery, + variables: { + filters: ['AcceptFundOnBase'], + sortingBy: SortingField.Newest, + }, + }); + result.data.data.allProjects.projects.forEach(project => { + assert.isOk( + project.addresses.find( + address => + address.isRecipient === true && + (address.networkId === NETWORK_IDS.BASE_MAINNET || + address.networkId === NETWORK_IDS.BASE_SEPOLIA) && + address.chainType === ChainType.EVM, + ), + ); + }); + assert.isOk( + result.data.data.allProjects.projects.find( + project => Number(project.id) === Number(savedProject.id), + ), + ); + }); + it('should return projects, filter by accept donation on base, not return when it doesnt have base address', async () => { + const baseProject = await saveProjectDirectlyToDb({ + ...createProjectData(), + title: String(new Date().getTime()), + slug: String(new Date().getTime()), + networkId: NETWORK_IDS.BASE_MAINNET, + }); + const polygonProject = await saveProjectDirectlyToDb({ + ...createProjectData(), + title: String(new Date().getTime()), + slug: String(new Date().getTime()), + networkId: NETWORK_IDS.POLYGON, + }); + + const result = await axios.post(graphqlUrl, { + query: fetchMultiFilterAllProjectsQuery, + variables: { + filters: ['AcceptFundOnBase'], + sortingBy: SortingField.Newest, + }, + }); + + result.data.data.allProjects.projects.forEach(project => { + assert.isOk( + project.addresses.find( + address => + address.isRecipient === true && + (address.networkId === NETWORK_IDS.BASE_MAINNET || + address.networkId === NETWORK_IDS.BASE_SEPOLIA) && + address.chainType === ChainType.EVM, + ), + ); + }); + assert.isNotOk( + result.data.data.allProjects.projects.find( + project => Number(project.id) === Number(polygonProject.id), + ), + ); + assert.isOk( + result.data.data.allProjects.projects.find( + project => Number(project.id) === Number(baseProject.id), + ), + ); + }); + it('should return projects, filter by accept donation on mainnet', async () => { const savedProject = await saveProjectDirectlyToDb({ ...createProjectData(), diff --git a/src/resolvers/projectResolver.test.ts b/src/resolvers/projectResolver.test.ts index 5d82a7df0..a2c90da77 100644 --- a/src/resolvers/projectResolver.test.ts +++ b/src/resolvers/projectResolver.test.ts @@ -117,7 +117,6 @@ describe( 'addRecipientAddressToProject test cases --->', addRecipientAddressToProjectTestCases, ); - describe('projectsByUserId test cases --->', projectsByUserIdTestCases); describe('deactivateProject test cases --->', deactivateProjectTestCases); diff --git a/src/resolvers/projectResolver.ts b/src/resolvers/projectResolver.ts index 456d37b6c..cfffb7cdd 100644 --- a/src/resolvers/projectResolver.ts +++ b/src/resolvers/projectResolver.ts @@ -527,6 +527,11 @@ export class ProjectResolver { networkIds.push(NETWORK_IDS.ARBITRUM_SEPOLIA); return; + case FilterField.AcceptFundOnBase: + networkIds.push(NETWORK_IDS.BASE_MAINNET); + networkIds.push(NETWORK_IDS.BASE_SEPOLIA); + return; + case FilterField.AcceptFundOnPolygon: networkIds.push(NETWORK_IDS.POLYGON); return; @@ -822,27 +827,65 @@ export class ProjectResolver { @Arg('connectedWalletUserId', _type => Int, { nullable: true }) connectedWalletUserId: number, @Ctx() { req: { user } }: ApolloContext, + @Info() info: any, ) { + const fields = graphqlFields(info); + let query = this.projectRepository .createQueryBuilder('project') .where(`project.id=:id`, { id, }) - .leftJoinAndSelect('project.status', 'status') - .leftJoinAndSelect( - 'project.categories', - 'categories', - 'categories.isActive = :isActive', - { isActive: true }, - ) - .leftJoinAndSelect('categories.mainCategory', 'mainCategory') - .leftJoinAndSelect('project.addresses', 'addresses') - .leftJoinAndSelect('project.socialMedia', 'socialMedia') - .leftJoinAndSelect('project.anchorContracts', 'anchor_contract_address') - .leftJoinAndSelect('project.organization', 'organization') - .leftJoin('project.adminUser', 'user') - .addSelect(publicSelectionFields); // aliased selection - query = ProjectResolver.addUserReaction(query, connectedWalletUserId, user); + .leftJoinAndSelect('project.status', 'status'); + + if (fields.categories) { + query = query + .leftJoinAndSelect( + 'project.categories', + 'categories', + 'categories.isActive = :isActive', + { isActive: true }, + ) + .leftJoinAndSelect('categories.mainCategory', 'mainCategory'); + } + if (fields.organization) { + query = query.leftJoinAndSelect('project.organization', 'organization'); + } + if (fields.addresses) { + query = query.leftJoinAndSelect('project.addresses', 'addresses'); + } + if (fields.socialMedia) { + query = query.leftJoinAndSelect('project.socialMedia', 'socialMedia'); + } + if (fields.anchorContracts) { + query = query.leftJoinAndSelect( + 'project.anchorContracts', + 'anchor_contract_address', + ); + } + if (fields.adminUser) { + const adminUserFields = Object.keys(fields.adminUser).map( + field => `user.${field}`, + ); + const filterByPublicFields = publicSelectionFields.filter(field => + adminUserFields.includes(field), + ); + query = query + .leftJoin('project.adminUser', 'user') + .addSelect( + filterByPublicFields.length > 0 + ? filterByPublicFields + : publicSelectionFields, + ); // aliased selection + } + if (fields.reaction) { + query = ProjectResolver.addUserReaction( + query, + connectedWalletUserId, + user, + ); + } + const project = await query.getOne(); canUserVisitProject(project, user?.userId); @@ -961,7 +1004,11 @@ export class ProjectResolver { ); query = query .leftJoin('project.adminUser', 'user') - .addSelect(filterByPublicFields); // aliased selection + .addSelect( + filterByPublicFields.length > 0 + ? filterByPublicFields + : publicSelectionFields, + ); // aliased selection } if (fields.reaction) { query = ProjectResolver.addUserReaction( diff --git a/src/resolvers/projectVerificationFormResolver.test.ts b/src/resolvers/projectVerificationFormResolver.test.ts index 695e86d59..b14dc0b59 100644 --- a/src/resolvers/projectVerificationFormResolver.test.ts +++ b/src/resolvers/projectVerificationFormResolver.test.ts @@ -321,6 +321,16 @@ function updateProjectVerificationFormMutationTestCases() { networkId: NETWORK_IDS.ARBITRUM_SEPOLIA, title: 'test title', }, + { + address: generateRandomEtheriumAddress(), + networkId: NETWORK_IDS.BASE_MAINNET, + title: 'test title', + }, + { + address: generateRandomEtheriumAddress(), + networkId: NETWORK_IDS.BASE_SEPOLIA, + title: 'test title', + }, { address: generateRandomEtheriumAddress(), networkId: NETWORK_IDS.ETC, diff --git a/src/resolvers/qfRoundResolver.ts b/src/resolvers/qfRoundResolver.ts index 3201278c4..562921483 100644 --- a/src/resolvers/qfRoundResolver.ts +++ b/src/resolvers/qfRoundResolver.ts @@ -82,11 +82,24 @@ class QfArchivedRoundsArgs { orderBy: QfArchivedRoundsOrderBy; } +@Service() +@ArgsType() +export class QfRoundsArgs { + @Field(_type => String, { nullable: true }) + slug?: string; + + @Field(_type => Boolean, { nullable: true }) + activeOnly?: boolean; +} + @Resolver(_of => User) export class QfRoundResolver { @Query(_returns => [QfRound], { nullable: true }) - async qfRounds() { - return findAllQfRounds(); + async qfRounds( + @Args() + { slug, activeOnly }: QfRoundsArgs, + ) { + return findAllQfRounds({ slug, activeOnly }); } @Query(_returns => [QFArchivedRounds], { nullable: true }) diff --git a/src/server/adminJs/tabs/donationTab.ts b/src/server/adminJs/tabs/donationTab.ts index 5e4574756..ffc2b4f20 100644 --- a/src/server/adminJs/tabs/donationTab.ts +++ b/src/server/adminJs/tabs/donationTab.ts @@ -603,6 +603,8 @@ export const donationTab = { { value: NETWORK_IDS.CELO_ALFAJORES, label: 'Alfajores' }, { value: NETWORK_IDS.ARBITRUM_MAINNET, label: 'Arbitrum' }, { value: NETWORK_IDS.ARBITRUM_SEPOLIA, label: 'Arbitrum Sepolia' }, + { value: NETWORK_IDS.BASE_MAINNET, label: 'Base' }, + { value: NETWORK_IDS.BASE_SEPOLIA, label: 'Base Sepolia' }, ], isVisible: { list: true, diff --git a/src/server/adminJs/tabs/qfRoundTab.ts b/src/server/adminJs/tabs/qfRoundTab.ts index 7ac744ff8..3a6ed6eb6 100644 --- a/src/server/adminJs/tabs/qfRoundTab.ts +++ b/src/server/adminJs/tabs/qfRoundTab.ts @@ -121,6 +121,8 @@ const availableNetworkValues = [ }, { value: NETWORK_IDS.ARBITRUM_MAINNET, label: 'ARBITRUM MAINNET' }, { value: NETWORK_IDS.ARBITRUM_SEPOLIA, label: 'ARBITRUM SEPOLIA' }, + { value: NETWORK_IDS.BASE_MAINNET, label: 'BASE MAINNET' }, + { value: NETWORK_IDS.BASE_SEPOLIA, label: 'BASE SEPOLIA' }, { value: NETWORK_IDS.XDAI, label: 'XDAI' }, { value: NETWORK_IDS.BSC, label: 'BSC' }, ]; diff --git a/src/server/adminJs/tabs/tokenTab.ts b/src/server/adminJs/tabs/tokenTab.ts index b6a83f959..65360652f 100644 --- a/src/server/adminJs/tabs/tokenTab.ts +++ b/src/server/adminJs/tabs/tokenTab.ts @@ -122,6 +122,7 @@ export const createToken = async ( isGivbackEligible, mainnetAddress, name, + coingeckoId, networkId, symbol, organizations, @@ -133,6 +134,7 @@ export const createToken = async ( address: address?.toLowerCase(), mainnetAddress: mainnetAddress?.toLowerCase(), isGivbackEligible, + coingeckoId, decimals: Number(decimals), networkId: Number(networkId), }); @@ -197,6 +199,8 @@ export const generateTokenTab = async () => { }, { value: NETWORK_IDS.ARBITRUM_MAINNET, label: 'ARBITRUM MAINNET' }, { value: NETWORK_IDS.ARBITRUM_SEPOLIA, label: 'ARBITRUM SEPOLIA' }, + { value: NETWORK_IDS.BASE_MAINNET, label: 'BASE MAINNET' }, + { value: NETWORK_IDS.BASE_SEPOLIA, label: 'BASE SEPOLIA' }, { value: NETWORK_IDS.XDAI, label: 'XDAI' }, { value: NETWORK_IDS.BSC, label: 'BSC' }, { value: NETWORK_IDS.ETC, label: 'Ethereum Classic' }, diff --git a/src/services/chains/index.test.ts b/src/services/chains/index.test.ts index dd7958ac4..fc03fa910 100644 --- a/src/services/chains/index.test.ts +++ b/src/services/chains/index.test.ts @@ -540,6 +540,44 @@ function getTransactionDetailTestCases() { assert.equal(transactionInfo.amount, amount); }); + it('should return transaction detail for normal transfer on Base Mainnet', async () => { + // https://basescan.org/tx/0x1cbf53e5a9a0874b9ad97316e4f2e1782e24bec318bacd183d3f48052bfe1523 + + const amount = 0.0032; + const transactionInfo = await getTransactionInfoFromNetwork({ + txHash: + '0x1cbf53e5a9a0874b9ad97316e4f2e1782e24bec318bacd183d3f48052bfe1523', + symbol: 'ETH', + networkId: NETWORK_IDS.BASE_MAINNET, + fromAddress: '0xbaed383ede0e5d9d72430661f3285daa77e9439f', + toAddress: '0xa5401000d255dbb154deb756b82dd5105486d8c9', + amount, + timestamp: 1716445331, + }); + assert.isOk(transactionInfo); + assert.equal(transactionInfo.currency, 'ETH'); + assert.equal(transactionInfo.amount, amount); + }); + + it('should return transaction detail for normal transfer on Base Sepolia', async () => { + // https://sepolia.basescan.org/tx/0x66fdfe46de46fa1fbb77de642cc778cafc85943204039f69694aee6121f764f4 + + const amount = 0.001; + const transactionInfo = await getTransactionInfoFromNetwork({ + txHash: + '0x66fdfe46de46fa1fbb77de642cc778cafc85943204039f69694aee6121f764f4', + symbol: 'ETH', + networkId: NETWORK_IDS.BASE_SEPOLIA, + fromAddress: '0x9cab0c7ff1c6250e641f4dcd4d9cd9db83bffb71', + toAddress: '0xd7eedf8422ababfbcafc0797e809ceae742fc142', + amount, + timestamp: 1716445488, + }); + assert.isOk(transactionInfo); + assert.equal(transactionInfo.currency, 'ETH'); + assert.equal(transactionInfo.amount, amount); + }); + it('should return transaction detail for OP token transfer on optimistic', async () => { // https://optimistic.etherscan.io/tx/0xf11be189d967831bb8a76656882eeeac944a799bd222acbd556f2156fdc02db4 const amount = 0.453549908802477308; diff --git a/src/services/googleSheets.ts b/src/services/googleSheets.ts index abb340cd7..a888a32b6 100644 --- a/src/services/googleSheets.ts +++ b/src/services/googleSheets.ts @@ -159,9 +159,7 @@ export const addQfRoundDonationsSheetToSpreadsheet = async (params: { }): Promise => { try { const spreadSheet = await initQfRoundDonationsSpreadsheet(); - const currentDate = moment().toDate(); - const headers = [ 'projectName', 'addresses', @@ -178,14 +176,30 @@ export const addQfRoundDonationsSheetToSpreadsheet = async (params: { 'uniqueUserIdsAfterAnalysis', 'projectOwnerEmail', ]; + const { rows, qfRoundId } = params; const sheet = await spreadSheet.addSheet({ headerValues: headers, title: `QfRound -${qfRoundId} - ${currentDate.toDateString()} ${currentDate.getTime()}`, }); + + // Modify rows to truncate cells with more than 50000 characters and add "..." + const modifiedRows = rows.map(row => { + const modifiedRow = {}; + Object.keys(row).forEach(key => { + if (typeof row[key] === 'string' && row[key].length > 50000) { + // Truncate the string to the maximum allowed length and append "..." + modifiedRow[key] = row[key].substring(0, 49990) + '...'; + } else { + modifiedRow[key] = row[key]; + } + }); + return modifiedRow; + }); + logger.debug('addQfRoundDonationsSheetToSpreadsheet', params); - await sheet.addRows(rows); + await sheet.addRows(modifiedRows); } catch (e) { logger.error('addQfRoundDonationsSheetToSpreadsheet error', e); throw e; diff --git a/src/utils/networksConfig.ts b/src/utils/networksConfig.ts index e1cf9b752..80d27e3f2 100644 --- a/src/utils/networksConfig.ts +++ b/src/utils/networksConfig.ts @@ -37,6 +37,8 @@ const networksConfig = { }, '42161': { blockExplorer: 'https://arbiscan.io/' }, '421614': { blockExplorer: 'https://sepolia.arbiscan.io/' }, + '8453': { blockExplorer: 'https://basescan.org/' }, + '84532': { blockExplorer: 'https://sepolia.basescan.org/' }, }; export default networksConfig; diff --git a/src/utils/validators/graphqlQueryValidators.ts b/src/utils/validators/graphqlQueryValidators.ts index ea232be2b..d859eb73e 100644 --- a/src/utils/validators/graphqlQueryValidators.ts +++ b/src/utils/validators/graphqlQueryValidators.ts @@ -243,6 +243,8 @@ const managingFundsValidator = Joi.object({ NETWORK_IDS.CELO_ALFAJORES, NETWORK_IDS.ARBITRUM_MAINNET, NETWORK_IDS.ARBITRUM_SEPOLIA, + NETWORK_IDS.BASE_MAINNET, + NETWORK_IDS.BASE_SEPOLIA, NETWORK_IDS.OPTIMISTIC, NETWORK_IDS.OPTIMISM_SEPOLIA, NETWORK_IDS.XDAI, diff --git a/src/utils/validators/projectValidator.ts b/src/utils/validators/projectValidator.ts index e1027a2b4..bb3997f91 100644 --- a/src/utils/validators/projectValidator.ts +++ b/src/utils/validators/projectValidator.ts @@ -141,6 +141,8 @@ export const isWalletAddressSmartContract = async ( NETWORK_IDS.CELO_ALFAJORES, NETWORK_IDS.ARBITRUM_MAINNET, NETWORK_IDS.ARBITRUM_SEPOLIA, + NETWORK_IDS.BASE_MAINNET, + NETWORK_IDS.BASE_SEPOLIA, ]; const _isSmartContracts = await Promise.all( diff --git a/test/graphqlQueries.ts b/test/graphqlQueries.ts index 094a908d3..eed85dfca 100644 --- a/test/graphqlQueries.ts +++ b/test/graphqlQueries.ts @@ -1056,7 +1056,6 @@ export const fetchProjectBySlugQuery = ` sortingField createdAt updatedAt - } givbackFactor projectPower { diff --git a/test/pre-test-scripts.ts b/test/pre-test-scripts.ts index b33f1c2f8..a5c9e6dc5 100644 --- a/test/pre-test-scripts.ts +++ b/test/pre-test-scripts.ts @@ -185,6 +185,34 @@ async function seedTokens() { } await Token.create(tokenData as Token).save(); } + for (const token of SEED_DATA.TOKENS.base_mainnet) { + const tokenData = { + ...token, + networkId: NETWORK_IDS.BASE_MAINNET, + isGivbackEligible: true, + }; + if (token.symbol === 'GIV') { + // TODO I'm not sure whether we support GIV or not + (tokenData as any).order = 1; + } else if (token.symbol === 'ETH') { + (tokenData as any).order = 2; + } + await Token.create(tokenData as Token).save(); + } + for (const token of SEED_DATA.TOKENS.base_sepolia) { + const tokenData = { + ...token, + networkId: NETWORK_IDS.BASE_SEPOLIA, + isGivbackEligible: true, + }; + if (token.symbol === 'GIV') { + // TODO I'm not sure whether we support GIV or not + (tokenData as any).order = 1; + } else if (token.symbol === 'ETH') { + (tokenData as any).order = 2; + } + await Token.create(tokenData as Token).save(); + } for (const token of SEED_DATA.TOKENS.optimistic) { const tokenData = { ...token, diff --git a/test/testUtils.ts b/test/testUtils.ts index bff29abb5..8a6e5171d 100644 --- a/test/testUtils.ts +++ b/test/testUtils.ts @@ -1732,6 +1732,24 @@ export const SEED_DATA = { coingeckoId: 'weth', }, ], + base_mainnet: [ + { + name: 'Base ETH', + symbol: 'ETH', + address: '0x0000000000000000000000000000000000000000', + decimals: 18, + coingeckoId: 'ethereum', + }, + ], + base_sepolia: [ + { + name: 'Base Sepolia native token', + symbol: 'ETH', + address: '0x0000000000000000000000000000000000000000', + decimals: 18, + coingeckoId: 'ethereum', + }, + ], }, };