diff --git a/src/components/views/donate/Recurring/ModifySuperToken/DepositSuperToken.tsx b/src/components/views/donate/Recurring/ModifySuperToken/DepositSuperToken.tsx index 7396e7cb30..fb79d0c5e0 100644 --- a/src/components/views/donate/Recurring/ModifySuperToken/DepositSuperToken.tsx +++ b/src/components/views/donate/Recurring/ModifySuperToken/DepositSuperToken.tsx @@ -2,6 +2,7 @@ import { useState, type FC, useEffect } from 'react'; import { Button, Flex } from '@giveth/ui-design-system'; import { useAccount, useBalance } from 'wagmi'; import { useIntl } from 'react-intl'; +import { ethers } from 'ethers'; import { Framework } from '@superfluid-finance/sdk-core'; import { ISuperToken, IToken } from '@/types/superFluid'; import { AddressZero } from '@/lib/constants/constants'; @@ -125,6 +126,7 @@ export const DepositSuperToken: FC = ({ // EThx is not a Wrapper Super Token and should load separately let superTokenAsset; + let newAmount = amount; if (superToken.symbol === 'ETHx') { superTokenAsset = await sf.loadNativeAssetSuperToken( superToken.id, @@ -132,10 +134,18 @@ export const DepositSuperToken: FC = ({ } else { superTokenAsset = await sf.loadWrapperSuperToken(superToken.id); } + if (token && token.decimals === 6) { + const divisor = BigInt(10 ** token.decimals); + const currentAmount = Number(amount) / Number(divisor); + newAmount = ethers.utils + .parseUnits(currentAmount.toString(), 18) + .toBigInt(); + } + console.log('token', token); + console.log('supertoken', superToken); const upgradeOperation = await superTokenAsset.upgrade({ - amount: amount.toString(), + amount: newAmount.toString(), }); - const tx = await upgradeOperation.exec(signer); const res = await tx.wait(); if (!res.status) { @@ -165,7 +175,6 @@ export const DepositSuperToken: FC = ({ closeModal(); } }; - return ( {step === EModifySuperTokenSteps.MODIFY ? ( diff --git a/src/components/views/donate/Recurring/ModifySuperToken/ModifySuperTokenModal.tsx b/src/components/views/donate/Recurring/ModifySuperToken/ModifySuperTokenModal.tsx index a5a02b3812..39bc665f41 100644 --- a/src/components/views/donate/Recurring/ModifySuperToken/ModifySuperTokenModal.tsx +++ b/src/components/views/donate/Recurring/ModifySuperToken/ModifySuperTokenModal.tsx @@ -13,7 +13,7 @@ import { EModifySuperTokenSteps } from './common'; import config from '@/configuration'; interface IModifySuperTokenModalProps extends IModal { - selectedToken: IToken; + selectedToken: ISuperToken | IToken; tokenStreams: ISuperfluidStream[]; refreshBalance: () => void; } diff --git a/src/components/views/donate/Recurring/ModifySuperToken/WithDrawSuperToken.tsx b/src/components/views/donate/Recurring/ModifySuperToken/WithDrawSuperToken.tsx index 4c9e2dbe3d..f0f1e5cd9e 100644 --- a/src/components/views/donate/Recurring/ModifySuperToken/WithDrawSuperToken.tsx +++ b/src/components/views/donate/Recurring/ModifySuperToken/WithDrawSuperToken.tsx @@ -187,7 +187,7 @@ export const WithDrawSuperToken: FC = ({ title='Withdraw from this stream balance' amount={amount} price={tokenPrice} - token={token!} + token={superToken!} /> { if (selectedRecurringToken.token.isSuperToken) { setAmount(balance.value || 0n); } + if (selectedRecurringToken.token.decimals === 6) { + setAmount(0n); + setPerMonthAmount(0n); + } }, [selectedRecurringToken, balance]); const underlyingToken = selectedRecurringToken?.token.underlyingToken; + // Introduce a scaling factor to handle tokens with different decimals + const scaleFactor = + selectedRecurringToken?.token.decimals === 6 ? 10000n : 1n; + // total means project + giveth - const totalPerSec = perMonthAmount / ONE_MONTH_SECONDS; + const totalPerSec = perMonthAmount / (ONE_MONTH_SECONDS / scaleFactor); const projectPerMonth = (perMonthAmount * BigInt(100 - donationToGiveth)) / 100n; const givethPerMonth = perMonthAmount - projectPerMonth; const tokenBalance = balance?.value; - const tokenStream = tokenStreams[selectedRecurringToken?.token.id || '']; + const tokenStream = + tokenStreams[selectedRecurringToken?.token.id.toLowerCase() || '']; const anchorContractAddress = useMemo( () => findAnchorContractAddress(project.anchorContracts), @@ -168,7 +177,8 @@ export const RecurringDonationCard = () => { 0n, ) || 0n; const totalStreamPerSec = totalPerSec + otherStreamsPerSec; - const totalStreamPerMonth = totalStreamPerSec * ONE_MONTH_SECONDS; + const totalStreamPerMonth = + totalStreamPerSec * (ONE_MONTH_SECONDS / scaleFactor); const streamRunOutInMonth = totalStreamPerSec > 0 ? amount / totalStreamPerMonth : 0n; const isTotalStreamExceed = @@ -767,7 +777,9 @@ export const RecurringDonationCard = () => { {showTopUpModal && selectedRecurringToken && ( = ({ {limitFraction( - formatUnits( - amount, - token.underlyingToken?.decimals || 18, - ), + formatUnits(amount, token.decimals || 18), )} -  {token.symbol} +  {token.underlyingToken?.symbol || token.symbol} {subtext} @@ -47,7 +44,7 @@ export const Item: FC = ({ .multipliedBy(amount.toString()) .toFixed(0), ), - token.underlyingToken?.decimals || 18, + token.decimals || 18, ), 2, )} diff --git a/src/components/views/donate/Recurring/RecurringDonationModal/RecurringDonationModal.tsx b/src/components/views/donate/Recurring/RecurringDonationModal/RecurringDonationModal.tsx index 76021e47e1..89863d004f 100644 --- a/src/components/views/donate/Recurring/RecurringDonationModal/RecurringDonationModal.tsx +++ b/src/components/views/donate/Recurring/RecurringDonationModal/RecurringDonationModal.tsx @@ -10,6 +10,7 @@ import { Framework, type Operation } from '@superfluid-finance/sdk-core'; import { useAccount } from 'wagmi'; import { useIntl } from 'react-intl'; import { formatUnits } from 'viem'; +import { ethers } from 'ethers'; import { Modal } from '@/components/modals/Modal'; import { useModalAnimation } from '@/hooks/useModalAnimation'; import { IModal } from '@/types/common'; @@ -227,10 +228,32 @@ const RecurringDonationInnerModal: FC = ({ const operations: Operation[] = []; + let newAmount = amount; + let newPerMonthAmount = perMonthAmount; + + // This is a special case with tokens that have 6 decimals + // We need to convert the amount to 18 decimals for the upgrade operation + // And also for the flow rate calculation + if (selectedRecurringToken.token.decimals === 6) { + const divisor = BigInt( + 10 ** selectedRecurringToken.token.decimals, + ); + const currentAmount = Number(amount) / Number(divisor); + newAmount = ethers.utils + .parseUnits(currentAmount.toString(), 18) + .toBigInt(); + + const currentPerMonth = + Number(perMonthAmount) / Number(divisor); + newPerMonthAmount = ethers.utils + .parseUnits(currentPerMonth.toString(), 18) + .toBigInt(); + } + // Upgrade the token to super token if (!isUpdating && !selectedRecurringToken.token.isSuperToken) { const upgradeOperation = await superToken.upgrade({ - amount: amount.toString(), + amount: newAmount.toString(), }); //Upgrading ETHx is a special case and can't be batched @@ -245,8 +268,8 @@ const RecurringDonationInnerModal: FC = ({ throw new Error('Project wallet address not found'); } - const _flowRate = - (perMonthAmount * BigInt(100 - donationToGiveth)) / + let _flowRate = + (newPerMonthAmount * BigInt(100 - donationToGiveth)) / 100n / ONE_MONTH_SECONDS; @@ -279,7 +302,7 @@ const RecurringDonationInnerModal: FC = ({ } const _newFlowRate = - (perMonthAmount * BigInt(donationToGiveth)) / + (newPerMonthAmount * BigInt(donationToGiveth)) / 100n / ONE_MONTH_SECONDS; diff --git a/src/components/views/donate/Recurring/SelectTokenModal/SelectTokenModal.tsx b/src/components/views/donate/Recurring/SelectTokenModal/SelectTokenModal.tsx index b6aa89e915..a841587642 100644 --- a/src/components/views/donate/Recurring/SelectTokenModal/SelectTokenModal.tsx +++ b/src/components/views/donate/Recurring/SelectTokenModal/SelectTokenModal.tsx @@ -51,6 +51,7 @@ const SelectTokenInnerModal: FC = ({ setShowModal, }) => { const [tokens, setTokens] = useState([]); + const [underlyingTokens, setUnderlyingTokens] = useState([]); const [balances, setBalances] = useState({}); const { formatMessage } = useIntl(); @@ -84,11 +85,12 @@ const SelectTokenInnerModal: FC = ({ return acc; }, {} as IBalances); - const filteredTokens = superTokens.filter( - token => !(newBalances[token.symbol] > 0n), - ); + const filteredTokens = superTokens.filter(token => { + return !(newBalances[token.underlyingToken.symbol] > 0n); + }); setTokens(filteredTokens); + setUnderlyingTokens(superTokens); // Update the state with the new balances setBalances(newBalances); @@ -127,12 +129,14 @@ const SelectTokenInnerModal: FC = ({ {Object.keys(tokenStreams).map(tokenId => { const token = superTokens.find( - token => token.id === tokenId, + token => + token.id.toLowerCase() === + tokenId.toLowerCase(), ) as IToken; return token ? ( = ({ ) : null; })} {superTokens.map(token => - tokenStreams[token.id] || + tokenStreams[token.id.toLowerCase()] || balances[token.symbol] === 0n ? null : ( = ({ id: 'label.superfluid_eligible_tokens_description', })} - {tokens.length > 0 ? ( - tokens.map(token => ( - { - setSelectedRecurringToken({ - token: token.underlyingToken, - balance: - balances[ - token.underlyingToken.symbol - ], - }); - setShowModal(false); - }} - /> + {underlyingTokens.length > 0 ? ( + underlyingTokens.map(token => ( + <> + { + setSelectedRecurringToken({ + token: token.underlyingToken, + balance: + balances[ + token.underlyingToken + .symbol + ], + }); + setShowModal(false); + }} + /> + )) ) : ( diff --git a/src/components/views/userProfile/donationsTab/recurringTab/StreamRow.tsx b/src/components/views/userProfile/donationsTab/recurringTab/StreamRow.tsx index 353678be1c..7df4fbd631 100644 --- a/src/components/views/userProfile/donationsTab/recurringTab/StreamRow.tsx +++ b/src/components/views/userProfile/donationsTab/recurringTab/StreamRow.tsx @@ -1,4 +1,4 @@ -import { useState, type FC } from 'react'; +import { useState, useMemo, type FC } from 'react'; import styled from 'styled-components'; import { P, brandColors, semanticColors } from '@giveth/ui-design-system'; import { formatUnits } from 'viem'; @@ -8,7 +8,7 @@ import { TokenIcon } from '@/components/views/donate/TokenIcon/TokenIcon'; import { TableCell } from './ActiveStreamsSection'; import { ISuperfluidStream } from '@/types/superFluid'; import { ONE_MONTH_SECONDS } from '@/lib/constants/constants'; -import { limitFraction } from '@/helpers/number'; +import { limitFraction, formatDonation } from '@/helpers/number'; import config from '@/configuration'; import { countActiveStreams } from '@/helpers/donate'; import { findTokenByAddress } from '@/helpers/superfluid'; @@ -19,6 +19,13 @@ interface IStreamRowProps { } export const StreamRow: FC = ({ tokenStream }) => { + const superToken = useMemo( + () => + config.OPTIMISM_CONFIG.SUPER_FLUID_TOKENS.find( + s => s.id === tokenStream[0].token.id, + ), + [tokenStream], + ); const [showModifyModal, setShowModifyModal] = useState(false); const { address, chain } = useAccount(); const { switchChain } = useSwitchChain(); @@ -39,7 +46,7 @@ export const StreamRow: FC = ({ tokenStream }) => { 0n, ); const monthlyFlowRate = totalFlowRate * ONE_MONTH_SECONDS; - const { symbol, decimals } = tokenStream[0].token; + // const { symbol } = tokenStream[0].token; const runOutMonth = monthlyFlowRate > 0 && balance?.value ? balance?.value / monthlyFlowRate @@ -57,12 +64,12 @@ export const StreamRow: FC = ({ tokenStream }) => { ) : '0'}

-

{symbol}

+

{superToken?.symbol}

- {limitFraction( - formatUnits(monthlyFlowRate || 0n, decimals), + {formatDonation( + limitFraction(formatUnits(BigInt(monthlyFlowRate), 18)), )}   {underlyingSymbol} @@ -109,11 +116,11 @@ export const StreamRow: FC = ({ tokenStream }) => { Deposit/Withdraw - {showModifyModal && ( + {showModifyModal && superToken && ( )} diff --git a/src/config/production.tsx b/src/config/production.tsx index d394f547a6..3396524042 100644 --- a/src/config/production.tsx +++ b/src/config/production.tsx @@ -522,31 +522,46 @@ const config: EnvConfig = { isSuperToken: true, coingeckoId: 'dai', }, - // { - // underlyingToken: { - // decimals: 6, - // id: '0x7f5c764cbc14f9669b88837ca1490cca17c31607', - // name: 'USD Coin', - // symbol: 'USDC', - // coingeckoId: 'usd-coin', - // }, - // decimals: 18, - // id: '0x8430f084b939208e2eded1584889c9a66b90562f', - // name: 'Super USD Coin', - // symbol: 'USDCx', - // isSuperToken: true, - // coingeckoId: 'usd-coin', - // }, + { + underlyingToken: { + decimals: 6, + id: '0x7f5c764cbc14f9669b88837ca1490cca17c31607', + name: 'Bridged USD Coin', + symbol: 'USDC.e', + coingeckoId: 'usd-coin', + }, + decimals: 18, + id: '0x8430f084b939208e2eded1584889c9a66b90562f', + name: 'Super Bridged USD Coin', + symbol: 'USDC.ex', + isSuperToken: true, + coingeckoId: 'usd-coin', + }, + { + underlyingToken: { + decimals: 6, + id: '0x0b2c639c533813f4aa9d7837caf62653d097ff85', + name: 'USD Coin', + symbol: 'USDC', + coingeckoId: 'usd-coin', + }, + decimals: 18, + id: '0x35adeb0638eb192755b6e52544650603fe65a006', + name: 'Super USD Coin', + symbol: 'USDCx', + isSuperToken: true, + coingeckoId: 'usd-coin', + }, { underlyingToken: { decimals: 18, - id: '0x4F604735c1cF31399C6E711D5962b2B3E0225AD3', + id: '0x4f604735c1cf31399c6e711d5962b2b3e0225ad3', name: 'Glo Dollar', symbol: 'USDGLO', coingeckoId: 'glo-dollar', }, decimals: 18, - id: '0x9F41d0AA24E599fd8D0c180Ee3C0F609dc41c622', + id: '0x9f41d0aa24e599fd8d0c180ee3c0f609dc41c622', name: 'Super Glo Dollar', symbol: 'USDGLOx', isSuperToken: true,