Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

1810 usdglo token #4795

Closed
wants to merge 17 commits into from
Closed
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion next-env.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
/// <reference types="next/image-types/global" />

// NOTE: This file should not be edited
// see https://nextjs.org/docs/basic-features/typescript for more information.
// see https://nextjs.org/docs/pages/building-your-application/configuring/typescript for more information.
8 changes: 4 additions & 4 deletions src/apollo/gql/gqlProjects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,8 +143,8 @@ export const FETCH_PROJECT_BY_SLUG_DONATION = gql`
slug
descriptionSummary
verified
isGivbackEligible
totalDonations
isGivbackEligible
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

Missing isGivbackEligible in FETCH_PROJECT_BY_SLUG_DONATION Query

The isGivbackEligible field is not present in the FETCH_PROJECT_BY_SLUG_DONATION query as expected. Please ensure that this field is included and correctly handled in the frontend components consuming this query.

🔗 Analysis chain

Ensure consistent inclusion of isGivbackEligible in queries.

The isGivbackEligible field has been re-added to the FETCH_PROJECT_BY_SLUG_DONATION query. Please verify that this field is necessary for the donation flow and that it is correctly handled in the frontend components consuming this query.

To confirm consistent usage of isGivbackEligible across the codebase, you can run the following script:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Find all occurrences of `isGivbackEligible` in GraphQL queries and their usage in the codebase.

# Search for the field in GraphQL query files.
rg --type ts 'isGivbackEligible' src/apollo/gql/

# Search for components using the `FETCH_PROJECT_BY_SLUG_DONATION` query.
rg --type ts 'FETCH_PROJECT_BY_SLUG_DONATION' src/

Length of output: 984


Script:

#!/bin/bash
# Description: Verify the inclusion of `isGivbackEligible` in the `FETCH_PROJECT_BY_SLUG_DONATION` GraphQL query.

# Use ast-grep to search for the `isGivbackEligible` field within the `FETCH_PROJECT_BY_SLUG_DONATION` query in gqlProjects.ts
ast-grep --lang javascript --pattern $'export const FETCH_PROJECT_BY_SLUG_DONATION = gql`$\n  query FetchProjectBySlugDonation($_: String!) {$$\n    project($_: $_) {$$\n      $$$\n      isGivbackEligible\n      $$$\n    }$$\n  }$$`' src/apollo/gql/gqlProjects.ts

Length of output: 257

sumDonationValueUsdForActiveQfRound
countUniqueDonorsForActiveQfRound
categories {
Expand Down Expand Up @@ -213,8 +213,8 @@ export const FETCH_PROJECT_BY_SLUG_SINGLE_PROJECT = gql`
image
slug
verified
isGivbackEligible
totalDonations
isGivbackEligible
description
addresses {
address
Expand Down Expand Up @@ -598,8 +598,8 @@ export const ADD_RECIPIENT_ADDRESS_TO_PROJECT = gql`
listed
reviewStatus
verified
isGivbackEligible
slugHistory
isGivbackEligible
creationDate
adminUserId
walletAddress
Expand Down Expand Up @@ -689,8 +689,8 @@ export const PROJECT_ACCEPTED_TOKENS = gql`
name
decimals
mainnetAddress
isGivbackEligible
order
isGivbackEligible
isStableCoin
coingeckoId
isQR
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import { useGeneralWallet } from '@/providers/generalWalletProvider';
import { wagmiConfig } from '@/wagmiConfigs';
import { ChainType } from '@/types/config';
import { getBalanceForToken } from './services';
import { fetchTokenBalances } from '@/services/token';
import { fetchEVMTokenBalances } from '@/services/token';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

Update error logs to use fetchEVMTokenBalances instead of fetchTokenBalances.

Residual usage of fetchTokenBalances found in error logging may lead to confusion and should be updated for consistency.

  • File: src/components/views/donate/OneTime/SelectTokenModal/SelectTokenModal.tsx
    • Line 29: console.error('error on fetchTokenBalances', { error });
🔗 Analysis chain

Verify impact on non-EVM chains and add explanatory comment.

The import statement has been changed from fetchTokenBalances to fetchEVMTokenBalances. While this change seems to align with EVM-specific functionality, it's important to ensure that this doesn't negatively impact support for non-EVM chains.

To verify the impact, please run the following script:

Consider adding a comment explaining why this change was made, for example:

// Import EVM-specific token balance fetching function
import { fetchEVMTokenBalances } from '@/services/token';
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for any remaining usage of fetchTokenBalances
rg "fetchTokenBalances" --type typescript

# Check if there are any non-EVM chain specific balance fetching functions
rg "fetch.*TokenBalances" --type typescript

Length of output: 245


Script:

#!/bin/bash
# Search for any remaining usage of fetchTokenBalances
rg "fetchTokenBalances" --type ts

# Check if there are any non-EVM chain specific balance fetching functions
rg "fetch[A-Za-z]*TokenBalances" --type ts

Length of output: 980

import { Spinner } from '@/components/Spinner';

export interface ISelectTokenModalProps extends IModal {
Expand Down Expand Up @@ -181,7 +181,7 @@ const SelectTokenInnerModal: FC<ISelectTokenModalProps> = ({
try {
setBalanceIsLoading(true);
const balances = isOnEVM
? await fetchTokenBalances(filteredTokens, walletAddress)
? await fetchEVMTokenBalances(filteredTokens, walletAddress)
: await Promise.all(
filteredTokens.map(async token => {
return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { Modal } from '@/components/modals/Modal';
import { useModalAnimation } from '@/hooks/useModalAnimation';
import config from '@/configuration';
import { TokenInfo } from './TokenInfo';
import { fetchBalance } from '@/services/token';
import { fetchBalance, fetchEVMTokenBalances } from '@/services/token';
import { ISuperToken, IToken } from '@/types/superFluid';
import { StreamInfo } from './StreamInfo';
import { useDonateData } from '@/context/donate.context';
Expand Down Expand Up @@ -87,18 +87,13 @@ const SelectTokenInnerModal: FC<ISelectTokenModalProps> = ({
return acc;
}, [] as IToken[]);

// Create an array of promises for each token balance fetch
const balancePromises = _allTokens.map(token =>
fetchTokenBalance(token),
);

// Wait for all promises to settle
const results = await Promise.all(balancePromises);
const results = await fetchEVMTokenBalances(_allTokens, address);

// Process results into a new balances object
const newBalances = results.reduce((acc, { symbol, balance }) => {
const newBalances = results.reduce((acc, { token, balance }) => {
if (balance !== undefined) {
acc[symbol] = balance;
acc[token.symbol] = balance;
}
return acc;
}, {} as IBalances);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add error handling for fetchEVMTokenBalances to manage exceptions

In the fetchAllBalances function, consider adding a try/catch block when calling fetchEVMTokenBalances to handle any potential errors that may occur during the fetch operation. This will prevent unhandled exceptions and improve the robustness of the application.

Apply this diff to add error handling:

 const fetchAllBalances = async () => {
+    try {
       const _allTokens = superTokens.reduce((acc, token) => {
         acc.push(token);
         acc.push(token.underlyingToken);
         return acc;
       }, [] as IToken[]);

       const results = await fetchEVMTokenBalances(_allTokens, address);

       // Process results into a new balances object
       const newBalances = results.reduce((acc, { token, balance }) => {
         if (balance !== undefined) {
           acc[token.symbol] = balance;
         }
         return acc;
       }, {} as IBalances);

       const filteredTokens = superTokens.filter(
         token => !(newBalances[token.symbol] > 0n),
       );

       setTokens(filteredTokens);

       // Update the state with the new balances
       setBalances(newBalances);
+    } catch (error) {
+      console.error('Error fetching EVM token balances:', error);
+      // Optionally handle the error, e.g., set an error state or notify the user
+    }
   };

Committable suggestion was skipped due to low confidence.

Expand Down Expand Up @@ -131,6 +126,8 @@ const SelectTokenInnerModal: FC<ISelectTokenModalProps> = ({
},
);

console.log('token', tokens);

return (
<>
<Wrapper>
Expand All @@ -148,6 +145,11 @@ const SelectTokenInnerModal: FC<ISelectTokenModalProps> = ({
const token = superTokens.find(
token => token.id === tokenId,
) as IToken;
if (!token?.symbol) {
console.log('token', token);
return;
}

return (
<StreamInfo
key={tokenId}
Expand Down
18 changes: 16 additions & 2 deletions src/config/production.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,7 @@ const EVM_CHAINS = [

const NON_EVM_CHAINS: NonEVMChain[] = [STELLAR_NETWORK, SOLANA_NETWORK];

const BASE_ROUTE =
process.env.NEXT_PUBLIC_BASE_ROUTE || 'https://mainnet.serve.giveth.io';
const BASE_ROUTE = 'https://mainnet.serve.giveth.io';
const BACKEND_LINK =
process.env.NEXT_PUBLIC_BACKEND_LINK || `${BASE_ROUTE}/graphql`;
const FRONTEND_LINK =
Expand Down Expand Up @@ -537,6 +536,21 @@ const config: EnvConfig = {
isSuperToken: true,
coingeckoId: 'usd-coin',
},
{
underlyingToken: {
decimals: 18,
id: '0x4F604735c1cF31399C6E711D5962b2B3E0225AD3',
name: 'Glo Dollar',
symbol: 'USDGLO',
coingeckoId: 'glo-dollar',
},
decimals: 18,
id: '0x9F41d0AA24E599fd8D0c180Ee3C0F609dc41c622',
name: 'Super Glo Dollar',
symbol: 'USDGLOx',
isSuperToken: true,
coingeckoId: 'glo-dollar',
},
],
},

Expand Down
44 changes: 30 additions & 14 deletions src/services/token.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
FETCH_MAINNET_TOKEN_PRICES,
} from '@/apollo/gql/gqlPrice';
import { IProjectAcceptedToken } from '@/apollo/types/gqlTypes';
import { IToken } from '@/types/superFluid';

export const fetchPrice = async (
chainId: number | ChainType,
Expand Down Expand Up @@ -56,27 +57,42 @@ export const fetchBalance = async (
}
};

export const fetchTokenBalances = async (
tokens: IProjectAcceptedToken[],
export const fetchEVMTokenBalances = async <
T extends IProjectAcceptedToken | IToken,
>(
tokens: T[], // Generic type constrained to IProjectAcceptedToken or IToken
walletAddress: string | null,
) => {
): Promise<{ token: T; balance: bigint | undefined }[]> => {
if (!walletAddress || !tokens || tokens.length === 0) return [];

// Filter out native tokens
const erc20Tokens: IProjectAcceptedToken[] = [];
const nativeTokens: IProjectAcceptedToken[] = [];
const erc20Tokens: T[] = [];
const nativeTokens: T[] = [];

// Use the correct property name based on the generic token type
const addressLabel = 'address' in tokens[0] ? 'address' : 'id';

tokens.forEach(token => {
token.address !== AddressZero
? erc20Tokens.push(token)
: nativeTokens.push(token);
const tokenAddress = token[addressLabel as keyof T] as string;

if (tokenAddress !== AddressZero) {
erc20Tokens.push(token);
} else {
nativeTokens.push(token);
}
});

const erc20Calls = erc20Tokens.map(token => ({
address: token.address,
abi: erc20Abi,
functionName: 'balanceOf',
args: [walletAddress],
}));
const erc20Calls = erc20Tokens.map(token => {
const tokenAddress = token[addressLabel as keyof T] as string;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider refactoring to eliminate code duplication.

The line const tokenAddress = token[addressLabel as keyof T] as string; is used in both the token separation loop and the erc20Calls mapping. Extracting this logic into a helper function or a utility method can reduce code duplication and improve readability.

Apply this refactor to create a helper function:

+const getTokenAddress = (token: T): string => token[addressLabel as keyof T] as string;

 // In the token separation loop
-const tokenAddress = token[addressLabel as keyof T] as string;
+const tokenAddress = getTokenAddress(token);

 // In the erc20Calls mapping
-const tokenAddress = token[addressLabel as keyof T] as string;
+const tokenAddress = getTokenAddress(token);

Committable suggestion was skipped due to low confidence.

// Ensure the tokenAddress is cast as Address (format starting with 0x)
return {
address: tokenAddress as Address, // Cast to wagmi Address type
abi: erc20Abi,
functionName: 'balanceOf',
args: [walletAddress],
};
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Validate tokenAddress before casting to Address.

Casting tokenAddress to Address assumes it is a valid Ethereum address starting with 0x. To prevent potential runtime errors, consider adding a validation step to ensure that tokenAddress conforms to the expected format.

You can use a regular expression or a utility function to validate the Ethereum address format. For example:

 // Ensure the tokenAddress is cast as Address (format starting with 0x)
 const tokenAddress = getTokenAddress(token);

+// Validate the token address format
+if (!/^0x[a-fA-F0-9]{40}$/.test(tokenAddress)) {
+  throw new Error(`Invalid token address: ${tokenAddress}`);
+}

 return {
   address: tokenAddress as Address,
   abi: erc20Abi,
   functionName: 'balanceOf',
   args: [walletAddress],
 };

Committable suggestion was skipped due to low confidence.


try {
// Fetch balances for ERC20 tokens via multicall
Expand Down