From da8b83698030224766dbe1aae41b5a04288b939e Mon Sep 17 00:00:00 2001 From: kkatusic Date: Thu, 5 Dec 2024 18:53:00 +0100 Subject: [PATCH 01/14] adding config data --- src/config/production.tsx | 79 +++++++++++++++++++++++++++++++++++++++ src/types/config.ts | 6 ++- 2 files changed, 84 insertions(+), 1 deletion(-) diff --git a/src/config/production.tsx b/src/config/production.tsx index 3396524042..ca164f5382 100644 --- a/src/config/production.tsx +++ b/src/config/production.tsx @@ -580,6 +580,7 @@ const config: EnvConfig = { coingeckoChainName: 'celo', chainLogo: (logoSize = 24) => , }, + ARBITRUM_CONFIG: { ...arbitrum, chainType: ChainType.EVM, @@ -590,6 +591,7 @@ const config: EnvConfig = { coingeckoChainName: 'arbitrum', chainLogo: (logoSize = 24) => , }, + BASE_CONFIG: { ...base, chainType: ChainType.EVM, @@ -599,6 +601,83 @@ const config: EnvConfig = { subgraphAddress: '', coingeckoChainName: 'base', chainLogo: (logoSize = 24) => , + SUPER_FLUID_TOKENS: [ + { + underlyingToken: { + decimals: 6, + id: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', + name: 'USD Coin', + symbol: 'USDC', + coingeckoId: 'usd-coin', + }, + decimals: 18, + id: '0xD04383398dD2426297da660F9CCA3d439AF9ce1b', + name: 'Super USD Coin', + symbol: 'USDCx', + isSuperToken: true, + coingeckoId: 'usd-coin', + }, + { + underlyingToken: { + decimals: 18, + id: '0x0000000000000000000000000000000000000000', + name: 'Ethereum', + symbol: 'ETH', + coingeckoId: 'ethereum', + }, + decimals: 18, + id: '0x46fd5cfB4c12D87acD3a13e92BAa53240C661D93', + name: 'Super ETH', + symbol: 'ETHx', + isSuperToken: true, + coingeckoId: 'ethereum', + }, + { + underlyingToken: { + decimals: 18, + id: '0xcbB7C0000aB88B473b1f5aFd9ef808440eed33Bf', + name: 'Coinbase Wrapped BTC', + symbol: 'cbBTC', + coingeckoId: 'bitcoin', + }, + decimals: 18, + id: '0xDFd428908909CB5E24F5e79E6aD6BDE10bdf2327', + name: 'Coinbase wrapped BTC', + symbol: 'cbBTCx', + isSuperToken: true, + coingeckoId: 'bitcoin', + }, + { + underlyingToken: { + decimals: 18, + id: '0x50c5725949A6F0c72E6C4a641F24049A917DB0Cb', + name: 'Dai Stablecoin', + symbol: 'DAI', + coingeckoId: 'dai', + }, + decimals: 18, + id: '0x708169c8C87563Ce904E0a7F3BFC1F3b0b767f41', + name: 'Coinbase wrapped BTC', + symbol: 'DAIx', + isSuperToken: true, + coingeckoId: 'dai', + }, + { + underlyingToken: { + decimals: 18, + id: '0x4ed4E862860beD51a9570b96d89aF5E1B0Efefed', + name: 'Degen', + symbol: 'DEGEN', + coingeckoId: 'degen-base', + }, + decimals: 18, + id: '0x1efF3Dd78F4A14aBfa9Fa66579bD3Ce9E1B30529', + name: 'Super Degen', + symbol: 'DEGENx', + isSuperToken: true, + coingeckoId: 'degen-base', + }, + ], }, ZKEVM_CONFIG: { diff --git a/src/types/config.ts b/src/types/config.ts index 65e64c97e1..42862f5b97 100644 --- a/src/types/config.ts +++ b/src/types/config.ts @@ -172,6 +172,10 @@ export interface OptimismNetworkConfig extends NetworkConfig { GIVETH_ANCHOR_CONTRACT_ADDRESS: Address; } +export interface BaseNetworkConfig extends NetworkConfig { + SUPER_FLUID_TOKENS: Array; +} + interface MicroservicesConfig { authentication: string; notification: string; @@ -222,7 +226,7 @@ export interface EnvConfig { OPTIMISM_CONFIG: OptimismNetworkConfig; CELO_CONFIG: NetworkConfig; ARBITRUM_CONFIG: NetworkConfig; - BASE_CONFIG: NetworkConfig; + BASE_CONFIG: BaseNetworkConfig; ZKEVM_CONFIG: NetworkConfig; CLASSIC_CONFIG: NetworkConfig; BACKEND_LINK: string; From e79e8129268a46a05f8e85f323418b06a8a652a8 Mon Sep 17 00:00:00 2001 From: kkatusic Date: Thu, 5 Dec 2024 19:26:23 +0100 Subject: [PATCH 02/14] added changes to selecting tokens --- .../views/donate/Recurring/RecurringDonationCard.tsx | 4 +++- .../Recurring/SelectTokenModal/SelectTokenModal.tsx | 9 +++++++-- src/components/views/donate/WrongNetworkLayer.tsx | 3 ++- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/components/views/donate/Recurring/RecurringDonationCard.tsx b/src/components/views/donate/Recurring/RecurringDonationCard.tsx index 85c64d0b94..d6fa6b121c 100644 --- a/src/components/views/donate/Recurring/RecurringDonationCard.tsx +++ b/src/components/views/donate/Recurring/RecurringDonationCard.tsx @@ -762,7 +762,9 @@ export const RecurringDonationCard = () => { {showSelectTokenModal && ( )} - {(!chain || chain.id !== config.OPTIMISM_NETWORK_NUMBER) && ( + {(!chain || + (chain.id !== config.OPTIMISM_NETWORK_NUMBER && + chain.id !== config.BASE_NETWORK_NUMBER)) && ( )} {showRecurringDonationModal && ( diff --git a/src/components/views/donate/Recurring/SelectTokenModal/SelectTokenModal.tsx b/src/components/views/donate/Recurring/SelectTokenModal/SelectTokenModal.tsx index cf5fb3c854..d111d7f59c 100644 --- a/src/components/views/donate/Recurring/SelectTokenModal/SelectTokenModal.tsx +++ b/src/components/views/donate/Recurring/SelectTokenModal/SelectTokenModal.tsx @@ -45,11 +45,16 @@ export interface IBalances { [key: string]: bigint; } -const superTokens = config.OPTIMISM_CONFIG.SUPER_FLUID_TOKENS; - const SelectTokenInnerModal: FC = ({ setShowModal, }) => { + const { chain } = useAccount(); + + const superTokens = + chain?.id === config.OPTIMISM_NETWORK_NUMBER + ? config.OPTIMISM_CONFIG.SUPER_FLUID_TOKENS + : config.BASE_CONFIG.SUPER_FLUID_TOKENS; + const [tokens, setTokens] = useState([]); const [underlyingTokens, setUnderlyingTokens] = useState([]); const [balances, setBalances] = useState({}); diff --git a/src/components/views/donate/WrongNetworkLayer.tsx b/src/components/views/donate/WrongNetworkLayer.tsx index 28c2b4e3a1..7f13b51aca 100644 --- a/src/components/views/donate/WrongNetworkLayer.tsx +++ b/src/components/views/donate/WrongNetworkLayer.tsx @@ -36,7 +36,8 @@ export const WrongNetworkLayer = () => { if (isOnEVM) { switchChain && switchChain({ - chainId: config.OPTIMISM_NETWORK_NUMBER, + // chainId: config.OPTIMISM_NETWORK_NUMBER, + chainId: config.BASE_NETWORK_NUMBER, }); } else { await handleSingOutAndSignInWithEVM(); From 4b10aece69403d16cee4e5bafa50ce97cc0a91c0 Mon Sep 17 00:00:00 2001 From: kkatusic Date: Fri, 6 Dec 2024 11:28:04 +0100 Subject: [PATCH 03/14] adding test page --- pages/test2.tsx | 574 +++++++++++++++++++++++++++++++++++++----------- 1 file changed, 449 insertions(+), 125 deletions(-) diff --git a/pages/test2.tsx b/pages/test2.tsx index e607b757f8..fc6f6fb8e5 100644 --- a/pages/test2.tsx +++ b/pages/test2.tsx @@ -1,153 +1,477 @@ -import { useState } from 'react'; -import { useQuery, useQueryClient } from '@tanstack/react-query'; -import { useAccount } from 'wagmi'; -import { - PublicKey, - LAMPORTS_PER_SOL, - Transaction, - SystemProgram, -} from '@solana/web3.js'; -import BigNumber from 'bignumber.js'; -import { useConnection, useWallet } from '@solana/wallet-adapter-react'; -import FailedDonation, { - EDonationFailedType, -} from '@/components/modals/FailedDonation'; -import { getTotalGIVpower } from '@/helpers/givpower'; -import { formatWeiHelper } from '@/helpers/number'; -import { useFetchSubgraphDataForAllChains } from '@/hooks/useFetchSubgraphDataForAllChains'; +import React, { useEffect, useState } from 'react'; +import { ethers } from 'ethers'; +import { Framework, Operation } from '@superfluid-finance/sdk-core'; + +const GIVETH_HOUSE_ADDRESS = '0x567c4B141ED61923967cA25Ef4906C8781069a10'; + +const TOKEN_ADDRESSES = [ + { + name: 'USDCx', + address: '0xD04383398dD2426297da660F9CCA3d439AF9ce1b', + decimals: 18, + }, + { + name: 'USDC Coin', + address: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', + decimals: 6, + superToken: { + address: '0xD04383398dD2426297da660F9CCA3d439AF9ce1b', + }, + }, +]; + +const BASE_CHAIN_ID = 8453; const YourApp = () => { - const [failedModalType, setFailedModalType] = - useState(); - const queryClient = useQueryClient(); - const { address, chain } = useAccount(); - const subgraphValues = useFetchSubgraphDataForAllChains(); - - const { data } = useQuery({ - queryKey: ['interactedBlockNumber', chain?.id], - queryFn: () => 0, - staleTime: Infinity, - }); - - console.log('data', data); - - // Solana wallet hooks - const { - publicKey, - disconnect: solanaWalletDisconnect, - signMessage: solanaSignMessage, - sendTransaction: solanaSendTransaction, - connecting: solanaIsConnecting, - connected: solanaIsConnected, - } = useWallet(); - - const { connection: solanaConnection } = useConnection(); - - const donateToSolana = async () => { - if (!publicKey) { - console.error('Wallet is not connected'); - return; - } + const [tokens, setTokens] = useState< + { name: string; address: string; balance: string }[] + >([]); + const [selectedToken, setSelectedToken] = useState(''); + const [destinationAddress, setDestinationAddress] = + useState(GIVETH_HOUSE_ADDRESS); + const [loading, setLoading] = useState(true); + const [amount, setAmount] = useState('0.001'); // Initial amount + const [notification, setNotification] = useState(''); - console.log('Connection endpoint:', solanaConnection.rpcEndpoint); + const determineTokenType = async ( + sf: { + loadNativeAssetSuperToken: (arg0: any) => any; + loadWrapperSuperToken: (arg0: any) => any; + }, + tokenAddress: any, + ) => { + let superToken; - const to = 'B6bfJUMPnpL2ddngPPe3M7QNpvrv7hiYYiGtg9iCJDMS'; - const donationValue = 0.001; + // Check if it's a native super token + try { + superToken = await sf.loadNativeAssetSuperToken(tokenAddress); + console.log('Native Super Token detected.'); + return { type: 'native', superToken }; + } catch (error) { + console.log('Not a Native Super Token.'); + } + + // Check if it's a wrapper super token + try { + superToken = await sf.loadWrapperSuperToken(tokenAddress); + console.log('Wrapper Super Token detected.'); + return { type: 'wrapper', superToken }; + } catch (error) { + console.log('Not a Wrapper Super Token.'); + } - console.log('publicKey', publicKey); - console.log('Public Key string:', publicKey.toString()); + // If both checks fail, it's a regular ERC-20 token + console.log('Regular ERC-20 token detected.'); + return { type: 'erc20', superToken: null }; + }; - // Ensure the wallet has enough funds by requesting an airdrop if necessary - let balance = await solanaConnection.getBalance(publicKey); - console.log('Initial balance:', balance); - if (balance < LAMPORTS_PER_SOL) { - console.log('Airdropping 1 SOL for testing...'); - const airdropSignature = await solanaConnection.requestAirdrop( - publicKey, - LAMPORTS_PER_SOL, + // Function to check if a flow exists + const checkIfFlowExists = async ( + sf: { + cfaV1: { + getFlow: (arg0: { + superToken: any; + sender: any; + receiver: any; + providerOrSigner: any; + }) => any; + }; + }, + superTokenAddress: any, + senderAddress: any, + receiverAddress: any, + signer: any, + ) => { + try { + const flowInfo = await sf.cfaV1.getFlow({ + superToken: superTokenAddress, + sender: senderAddress, + receiver: receiverAddress, + providerOrSigner: signer, + }); + console.log( + `Existing flow found. Current flow rate: ${flowInfo.flowRate}`, ); - await solanaConnection.confirmTransaction(airdropSignature); - balance = await solanaConnection.getBalance(publicKey); - console.log('New balance:', balance); + console.log({ flowInfo }); + return { exists: true, flowRate: flowInfo.flowRate }; + } catch (error) { + console.log('No existing flow found.'); + return { exists: false, flowRate: '0' }; } + }; - const lamports = new BigNumber(donationValue) - .times(LAMPORTS_PER_SOL) - .toFixed(); + const handleApproveAndExecute = async () => { + try { + // Connect to MetaMask + if (!window.ethereum) { + alert('MetaMask not detected'); + return; + } - const transaction = new Transaction().add( - SystemProgram.transfer({ - fromPubkey: publicKey!, - toPubkey: new PublicKey(to), - lamports: BigInt(lamports), - }), - ); + const provider = new ethers.providers.Web3Provider(window.ethereum); + await provider.send('eth_requestAccounts', []); + const signer = provider.getSigner(); + const sf = await Framework.create({ + chainId: BASE_CHAIN_ID, + provider, + }); - console.log('Transaction', transaction); + console.log({ sf }); - console.log( - 'Fee Payer:', - transaction.feePayer ? transaction.feePayer.toBase58() : 'None', - ); + const address = await signer.getAddress(); - transaction.feePayer = publicKey; + // Get token details (decimals, etc.) + const token = TOKEN_ADDRESSES.find( + t => t.address === selectedToken, + ); + if (!token) { + alert('Invalid token selected.'); + return; + } + const tokenDecimals = token.decimals; - const simulationResult = - await solanaConnection.simulateTransaction(transaction); - console.log('Simulation Result:', simulationResult); + // Define the amount to approve (X.XX USDCx) + const amountToApprove = ethers.utils.parseUnits( + amount, + tokenDecimals, + ); - if (simulationResult.value.err) { - console.error('Simulation error:', simulationResult.value.err); - return; - } + const flowRatePerSecond = amountToApprove.div(30 * 24 * 60 * 60); // Convert monthly to per-second rate + console.log({ flowRatePerSecond }); + + // Determine the token type + const { type, superToken } = await determineTokenType( + sf, + selectedToken, + ); + + console.log('Selected token:', selectedToken); + console.log('Super type:', type); + console.log('Super Token:', superToken); + + if (type === 'native' || type === 'wrapper') { + console.log( + `${type.charAt(0).toUpperCase() + type.slice(1)} Super Token detected`, + ); + + // Attempt to check allowance (skip if it fails) + let allowance; + try { + allowance = await superToken.allowance({ + owner: await signer.getAddress(), + spender: destinationAddress, + providerOrSigner: signer, + }); + await allowance.wait(); + console.log(`Current allowance: ${allowance.toString()}`); + } catch (error) { + console.log( + 'Allowance does not exist or cannot be fetched. Proceeding to approve...', + ); + } + + // Approve if needed + if (ethers.BigNumber.from(allowance).lt(amountToApprove)) { + const approveOperation = superToken.approve({ + receiver: destinationAddress, + amount: amountToApprove.toString(), + }); + + const approveTxResponse = await signer.sendTransaction( + await approveOperation.getPopulatedTransactionRequest( + signer, + ), + ); + await approveTxResponse.wait(); + console.log(`Approved ${amount} ${type} super tokens.`); + } + + // Check for existing flow + const flowStatus = await checkIfFlowExists( + sf, + superToken.address, + address, + destinationAddress, + signer, + ); + + if (flowStatus.exists && flowStatus.flowRate !== '0') { + // Add new flow rate to existing flow rate + const newFlowRate = ethers.BigNumber.from( + flowStatus.flowRate, + ).add(flowRatePerSecond); + + // Update the flow + const updateFlowOperation = superToken.updateFlow({ + sender: address, + receiver: destinationAddress, + flowRate: newFlowRate.toString(), // New total flow rate + }); + + console.log('Updating existing flow...'); + const updateFlowTxResponse = await updateFlowOperation.exec( + signer, + // 70, + ); + await updateFlowTxResponse.wait(); + console.log('Flow updated successfully.'); + setNotification('Flow updated successfully!'); + } else { + // Create a new flow if none exists + const createFlowOperation = superToken.createFlow({ + sender: address, + receiver: destinationAddress, + flowRate: flowRatePerSecond.toString(), // New flow rate + }); + + console.log('Creating new flow...'); + const createFlowTxResponse = await createFlowOperation.exec( + signer, + // 2, + ); + await createFlowTxResponse.wait(); + console.log('Flow created successfully.'); + setNotification('Flow created successfully!'); + } + } else if (type === 'erc20') { + /** + * + * + * USDC native tokens + * + * + * + */ + console.log('Approving underlying ERC-20 token for upgrade...'); + + const operations: Operation[] = []; + + const underlyingToken = await sf.loadSuperToken(selectedToken); + const newSuperToken = await sf.loadWrapperSuperToken( + token.superToken?.address || '', + ); + + console.log({ underlyingToken }); + + const erc20Contract = new ethers.Contract( + selectedToken, // Underlying ERC-20 token address + [ + 'function approve(address spender, uint256 amount) public returns (bool)', + ], + signer, + ); + + // Approve the Super Token contract to spend the ERC-20 token + const approveTx = await underlyingToken.approve({ + receiver: newSuperToken.address, // Address of the Super Token + amount: amountToApprove.toString(), + }); + const approveTRANS = await approveTx.exec(signer); + await approveTRANS.wait(); // Wait for the transaction to be mined + console.log( + 'Underlying ERC-20 token approved for upgrade.', + approveTx, + ); + + console.log( + 'Upgrading ERC-20 token to Super Token...', + approveTRANS, + ); - const hash = await solanaSendTransaction(transaction, solanaConnection); + const amountToApproveNew = ethers.utils.parseUnits(amount, 18); + const flowRatePerSecondNew = amountToApproveNew.div( + 30 * 24 * 60 * 60, + ); // Convert monthly to per-second rate - console.log('hash', hash); + console.log('Upgrading......'); // THIS FAILING FIRST TIME + const upgradeTx = await newSuperToken.upgrade({ + amount: amountToApproveNew.toString(), + }); + const approveUPGRD = await upgradeTx.exec(signer); + await approveUPGRD.wait(); // Wait for the transaction to be mined + // operations.push(upgradeTx); + console.log('Upgrade to Super Token complete.', upgradeTx); + + // Create or update the stream + const flowStatus = await checkIfFlowExists( + sf, + newSuperToken.address, + address, + destinationAddress, + signer, + ); + + if (flowStatus.exists && flowStatus.flowRate !== '0') { + console.log('Updating existing flow...'); + const updateFlowOperation = newSuperToken.updateFlow({ + sender: address, + receiver: destinationAddress, + flowRate: flowRatePerSecondNew.toString(), // New flow rate + }); + // const flowTxResponse = + // await updateFlowOperation.exec(signer); + // await flowTxResponse.wait(); + + operations.push(updateFlowOperation); + + const batchOp = sf.batchCall(operations); + const txUpdate = await batchOp.exec(signer, 2); + + console.log('Flow updated successfully.', txUpdate); + setNotification('Flow updated successfully!'); + } else { + console.log('Creating new flow...'); + const createFlowOperation = newSuperToken.createFlow({ + sender: address, + receiver: destinationAddress, + flowRate: flowRatePerSecondNew.toString(), // New flow rate + }); + const flowTxResponse = await createFlowOperation.exec( + signer, + 2, + ); + await flowTxResponse.wait(); + // operations.push(createFlowOperation); + + // const batchOp = sf.batchCall(operations); + // const txCreate = await batchOp.exec(signer, 700); + + console.log('Flow created successfully.', flowTxResponse); + setNotification('Flow created successfully!'); + } + } + } catch (error) { + console.error('Error during approval or execution:', error); + setNotification( + 'Transaction failed! Please check the console for details.', + ); + } }; - return ( -
- - -
- -
+ + const balance = await contract.balanceOf(address); + const decimals = await contract.decimals(); + + return { + name: token.name, + address: token.address, + balance: ethers.utils.formatUnits( + balance, + decimals, + ), + }; + }), + ); + + setTokens(balances); + setSelectedToken(balances[0]?.address || ''); + setLoading(false); + } catch (error) { + console.error('Error fetching tokens:', error); + alert('An error occurred while fetching tokens.'); + } + }; + + fetchTokens(); + }, []); + + return ( +
+

Approve and Execute {amount} USDC

+

+ Network ID: {BASE_CHAIN_ID} Optimism Network +

+

+ Transaction to wallet: {destinationAddress} + Giveth House +

- {data} - - {chain?.id && ( -
- {failedModalType && ( - setFailedModalType(undefined)} - type={failedModalType} +
+
+

Enter Amount

+ setAmount(e.target.value)} + style={{ padding: '10px', width: '200px' }} + /> +
+
+
+

Destination Address

+ setDestinationAddress(e.target.value)} + style={{ padding: '10px', width: '500px' }} /> +
+
+ + {notification && ( +
+ {notification} +
)}
); From 32a6372b52d198a5fe851a1e3ea64249e6321a46 Mon Sep 17 00:00:00 2001 From: kkatusic Date: Mon, 9 Dec 2024 19:54:12 +0100 Subject: [PATCH 04/14] adding network switch options --- lang/ca.json | 2 +- lang/en.json | 2 +- lang/es.json | 2 +- .../Recurring/RecurringDonationCard.tsx | 3 +- .../RecurringDonationModal.tsx | 29 ++++--- .../views/donate/WrongNetworkLayer.tsx | 81 ++++++++++++++----- src/helpers/donate.ts | 26 +++++- 7 files changed, 107 insertions(+), 38 deletions(-) diff --git a/lang/ca.json b/lang/ca.json index cd977c7edb..2bf2679f80 100644 --- a/lang/ca.json +++ b/lang/ca.json @@ -864,7 +864,7 @@ "label.recipient_addresses": "adreces destinatàries", "label.recipient_addresses_cant": "Les adreces dels destinataris no poden estar buides", "label.recurring_donation": "Donació Recurrent", - "label.recurring_donations_currently_only_available_on_optimism": "Les donacions recurrents actualment només estan disponibles en Optimism", + "label.recurring_donations_currently_only_available_on_optimism_base": "Les donacions recurrents estan disponibles actualment només a les xarxes Optimism i Base.", "label.recurring_donation_card_subheader_1": "Transmeteu les vostres donacions al llarg del temps per proporcionar finançament continu.", "label.recurring_donation_card_subheader_2": "Decideix la quantitat de tokens a dipositar en el teu saldo de transmissió, o utilitza el/els teu(s) saldo(s) de transmissió existent(s). Estableix l'import de la donació mensual en tokens i comença a transmetre.", "label.recurring_donation_maximum": "Això supera el màxim que pots donar mensualment, recarrega el saldo del teu flux per donar més!", diff --git a/lang/en.json b/lang/en.json index 2349d08785..4de6e6207c 100644 --- a/lang/en.json +++ b/lang/en.json @@ -864,7 +864,7 @@ "label.recipient_addresses": "recipient addresses", "label.recipient_addresses_cant": "Recipient addresses can't be empty", "label.recurring_donation": "Recurring Donation", - "label.recurring_donations_currently_only_available_on_optimism": "Recurring donations are currently only available on Optimism", + "label.recurring_donations_currently_only_available_on_optimism_base": "Recurring donations are currently only available on Optimism and Base networks.", "label.recurring_donation_card_subheader_1": "Stream your donations over time to provide continuous funding.", "label.recurring_donation_card_subheader_2": "Decide the number of tokens to deposit in your stream balance, or utilize your existing stream balance(s). Set the monthly donation amount in tokens and begin streaming.", "label.recurring_donation_maximum": "This is over the maximum you can donate monthly, top-up your stream balance to donate more!", diff --git a/lang/es.json b/lang/es.json index 4be6f4ee4b..f017e04d76 100644 --- a/lang/es.json +++ b/lang/es.json @@ -864,7 +864,7 @@ "label.recipient_addresses": "direcciones de los destinatarios", "label.recipient_addresses_cant": "Las direcciones de los destinatarios no pueden estar vacías", "label.recurring_donation": "Donación Recurrente", - "label.recurring_donations_currently_only_available_on_optimism": "Las donaciones recurrentes actualmente solo están disponibles en Optimism", + "label.recurring_donations_currently_only_available_on_optimism_base": "Las donaciones recurrentes están actualmente disponibles solo en las redes Optimism y Base.", "label.recurring_donation_card_subheader_1": "Transmite tus donaciones con el tiempo para proporcionar financiamiento continuo.", "label.recurring_donation_card_subheader_2": "Decide la cantidad de tokens a depositar en tu saldo de transmisión, o utiliza tu(s) saldo(s) de transmisión existente(s). Establece el monto de la donación mensual en tokens y comienza a transmitir.", "label.recurring_donation_maximum": "¡Esto supera el máximo que puedes donar mensualmente, recarga el saldo de tu transmisión para donar más!", diff --git a/src/components/views/donate/Recurring/RecurringDonationCard.tsx b/src/components/views/donate/Recurring/RecurringDonationCard.tsx index d6fa6b121c..e0f671c643 100644 --- a/src/components/views/donate/Recurring/RecurringDonationCard.tsx +++ b/src/components/views/donate/Recurring/RecurringDonationCard.tsx @@ -113,8 +113,7 @@ export const RecurringDonationCard = () => { const [showAlloProtocolModal, setShowAlloProtocolModal] = useState(false); const { formatMessage } = useIntl(); - const { address } = useAccount(); - const { chain } = useAccount(); + const { address, chain } = useAccount(); const isSignedIn = useAppSelector(state => state.user.isSignedIn); const { modalCallback: signInThenDonate } = useModalCallback(() => setShowRecurringDonationModal(true), diff --git a/src/components/views/donate/Recurring/RecurringDonationModal/RecurringDonationModal.tsx b/src/components/views/donate/Recurring/RecurringDonationModal/RecurringDonationModal.tsx index 89863d004f..db441ec804 100644 --- a/src/components/views/donate/Recurring/RecurringDonationModal/RecurringDonationModal.tsx +++ b/src/components/views/donate/Recurring/RecurringDonationModal/RecurringDonationModal.tsx @@ -132,7 +132,8 @@ const RecurringDonationInnerModal: FC = ({ tokenStreams, setSuccessDonation, } = useDonateData(); - const { address } = useAccount(); + const { address, chain } = useAccount(); + const recurringNetworkID = chain?.id ?? 0; const tokenPrice = useTokenPrice(selectedRecurringToken?.token); const isSafeEnv = useIsSafeEnvironment(); const { formatMessage } = useIntl(); @@ -149,7 +150,7 @@ const RecurringDonationInnerModal: FC = ({ const onApprove = async () => { try { - await ensureCorrectNetwork(config.OPTIMISM_NETWORK_NUMBER); + await ensureCorrectNetwork(recurringNetworkID); console.log( 'amount', formatUnits( @@ -161,6 +162,7 @@ const RecurringDonationInnerModal: FC = ({ if (!address || !selectedRecurringToken) return; const superToken = findSuperTokenByTokenAddress( selectedRecurringToken.token.id, + recurringNetworkID, ); if (!superToken) throw new Error('SuperToken not found'); const approve = await approveERC20tokenTransfer( @@ -168,7 +170,7 @@ const RecurringDonationInnerModal: FC = ({ address, superToken.id, //superTokenAddress selectedRecurringToken?.token.id, //tokenAddress - config.OPTIMISM_CONFIG.id, + recurringNetworkID, isSafeEnv, ); if (approve) { @@ -183,7 +185,7 @@ const RecurringDonationInnerModal: FC = ({ const onDonate = async () => { try { - await ensureCorrectNetwork(config.OPTIMISM_NETWORK_NUMBER); + await ensureCorrectNetwork(recurringNetworkID); setStep(EDonationSteps.DONATING); const projectAnchorContract = findAnchorContractAddress( project?.anchorContracts, @@ -201,7 +203,10 @@ const RecurringDonationInnerModal: FC = ({ throw new Error('Provider or signer not found'); let _superToken = selectedRecurringToken.token; if (!_superToken.isSuperToken) { - const sp = findSuperTokenByTokenAddress(_superToken.id); + const sp = findSuperTokenByTokenAddress( + _superToken.id, + recurringNetworkID, + ); if (!sp) { throw new Error('Super token not found'); } else { @@ -210,7 +215,7 @@ const RecurringDonationInnerModal: FC = ({ } const _options = { - chainId: config.OPTIMISM_CONFIG.id, + chainId: recurringNetworkID, provider: provider, resolverAddress: isProduction ? undefined @@ -256,7 +261,7 @@ const RecurringDonationInnerModal: FC = ({ amount: newAmount.toString(), }); - //Upgrading ETHx is a special case and can't be batched + // Upgrading ETHx is a special case and can't be batched if (_superToken.symbol === 'ETHx') { await upgradeOperation.exec(signer); } else { @@ -340,7 +345,7 @@ const RecurringDonationInnerModal: FC = ({ const projectDraftDonationInfo: ICreateDraftRecurringDonation = { projectId: +project.id, anonymous, - chainId: config.OPTIMISM_NETWORK_NUMBER, + chainId: recurringNetworkID, flowRate: _flowRate, superToken: _superToken, isBatch, @@ -355,7 +360,7 @@ const RecurringDonationInnerModal: FC = ({ const givethDraftDonationInfo: ICreateDraftRecurringDonation = { projectId: config.GIVETH_PROJECT_ID, anonymous, - chainId: config.OPTIMISM_NETWORK_NUMBER, + chainId: recurringNetworkID, flowRate: givethFlowRate, superToken: _superToken, isBatch, @@ -368,7 +373,7 @@ const RecurringDonationInnerModal: FC = ({ ); } - await ensureCorrectNetwork(config.OPTIMISM_NETWORK_NUMBER); + await ensureCorrectNetwork(recurringNetworkID); if (isBatch) { const batchOp = sf.batchCall(operations); @@ -484,14 +489,14 @@ const RecurringDonationInnerModal: FC = ({ ], isRecurring: true, givBackEligible: true, - chainId: config.OPTIMISM_NETWORK_NUMBER, + chainId: recurringNetworkID, }); } else { setSuccessDonation({ txHash: [{ txHash: tx.hash, chainType: ChainType.EVM }], isRecurring: true, givBackEligible: true, - chainId: config.OPTIMISM_NETWORK_NUMBER, + chainId: recurringNetworkID, }); } } diff --git a/src/components/views/donate/WrongNetworkLayer.tsx b/src/components/views/donate/WrongNetworkLayer.tsx index 7f13b51aca..f28941af42 100644 --- a/src/components/views/donate/WrongNetworkLayer.tsx +++ b/src/components/views/donate/WrongNetworkLayer.tsx @@ -13,12 +13,23 @@ import { useSwitchChain } from 'wagmi'; import { useIntl } from 'react-intl'; import config from '@/configuration'; import { useGeneralWallet } from '@/providers/generalWalletProvider'; +import NetworkLogo from '@/components/NetworkLogo'; +import { ChainType } from '@/types/config'; export const WrongNetworkLayer = () => { const { switchChain } = useSwitchChain(); const { isOnEVM, handleSingOutAndSignInWithEVM } = useGeneralWallet(); const { formatMessage } = useIntl(); + // List of recurring networks for user to select + const networks = [ + { + name: config.OPTIMISM_CONFIG.name, + chainId: config.OPTIMISM_NETWORK_NUMBER, + }, + { name: config.BASE_CONFIG.name, chainId: config.BASE_NETWORK_NUMBER }, + ]; + return ( @@ -27,27 +38,39 @@ export const WrongNetworkLayer = () => { {formatMessage({ - id: 'label.recurring_donations_currently_only_available_on_optimism', + id: 'label.recurring_donations_currently_only_available_on_optimism_base', })} - { - if (isOnEVM) { - switchChain && - switchChain({ - // chainId: config.OPTIMISM_NETWORK_NUMBER, - chainId: config.BASE_NETWORK_NUMBER, - }); - } else { - await handleSingOutAndSignInWithEVM(); - } - }} - > - {formatMessage({ - id: 'label.switch_network', - })} - + {networks.map(network => ( + + { + if (isOnEVM) { + switchChain && + switchChain({ + chainId: network.chainId, + }); + } else { + await handleSingOutAndSignInWithEVM(); + } + }} + > + + + {formatMessage({ + id: 'label.switch_network', + })}{' '} + to {network.name} + + + + ))} {formatMessage( @@ -55,7 +78,12 @@ export const WrongNetworkLayer = () => { id: 'label.switch_to_network_to_continue_donating', }, { - network: {config.OPTIMISM_CONFIG.name}, + network: ( + <> + {config.OPTIMISM_CONFIG.name} or{' '} + {config.BASE_CONFIG.name} + + ), }, )} @@ -108,3 +136,18 @@ const Desc = styled(Caption)` margin-top: 8px; text-align: left; `; + +const NetworkWrapper = styled(Flex)` + width: 100%; +`; + +const SwitchButtonHolder = styled(SwitchButton)` + display: flex; + align-items: center; + gap: 8px; + margin-bottom: 8px; +`; + +const NetworkNameHolder = styled.div` + padding-right: 10px; +`; diff --git a/src/helpers/donate.ts b/src/helpers/donate.ts index e45dc72ed4..c4f6203060 100644 --- a/src/helpers/donate.ts +++ b/src/helpers/donate.ts @@ -3,8 +3,30 @@ import config from '@/configuration'; import { type ITokenStreams } from '@/context/donate.context'; import { ISuperfluidStream, IToken } from '@/types/superFluid'; -export const findSuperTokenByTokenAddress = (tokenAddress: Address) => { - return config.OPTIMISM_CONFIG.SUPER_FLUID_TOKENS.find( +/** + * Finds the corresponding SuperToken for a given token address within a specific network. + * We for now ONLY USE the Optimism network and the Base network. + * + * @param {Address} tokenAddress - The address of the underlying token to search for. + * @param {number} recurringNetworkID - The ID of the network where the search should occur. + * This can be either the Optimism network or the Base network. + * @returns {Object | undefined} - The matching SuperToken object if found, otherwise undefined. + * + * Logic: + * - If the recurring network ID matches the Optimism network, it searches within the + * Optimism configuration's SuperFluid tokens. + * - Otherwise, it defaults to searching within the Base configuration's SuperFluid tokens. + */ +export const findSuperTokenByTokenAddress = ( + tokenAddress: Address, + recurringNetworkID: number, +) => { + if (recurringNetworkID === config.OPTIMISM_NETWORK_NUMBER) { + return config.OPTIMISM_CONFIG.SUPER_FLUID_TOKENS.find( + token => token.underlyingToken.id === tokenAddress, + ); + } + return config.BASE_CONFIG.SUPER_FLUID_TOKENS.find( token => token.underlyingToken.id === tokenAddress, ); }; From 326d049e7dff2ce491dcaa65517a73a7c04f2ebb Mon Sep 17 00:00:00 2001 From: kkatusic Date: Tue, 10 Dec 2024 09:48:51 +0100 Subject: [PATCH 05/14] fixing build --- .../ModifySuperToken/DepositSuperToken.tsx | 13 +++--- .../ModifySuperTokenModal.tsx | 41 +++++++++++-------- .../Recurring/RecurringDonationCard.tsx | 1 + .../RecurringDonationModal.tsx | 3 ++ .../donationsTab/recurringTab/StreamRow.tsx | 1 + src/config/development.tsx | 17 ++++++++ 6 files changed, 54 insertions(+), 22 deletions(-) diff --git a/src/components/views/donate/Recurring/ModifySuperToken/DepositSuperToken.tsx b/src/components/views/donate/Recurring/ModifySuperToken/DepositSuperToken.tsx index fb79d0c5e0..9bbfbabf0e 100644 --- a/src/components/views/donate/Recurring/ModifySuperToken/DepositSuperToken.tsx +++ b/src/components/views/donate/Recurring/ModifySuperToken/DepositSuperToken.tsx @@ -11,7 +11,7 @@ import { IModifySuperTokenInnerModalProps } from './ModifySuperTokenModal'; import { DepositSteps } from './DepositSuperTokenSteps'; import { useTokenPrice } from '@/hooks/useTokenPrice'; import { approveERC20tokenTransfer } from '@/lib/stakingPool'; -import config, { isProduction } from '@/configuration'; +import { isProduction } from '@/configuration'; import { showToastError } from '@/lib/helpers'; import { useIsSafeEnvironment } from '@/hooks/useSafeAutoConnect'; import { StreamInfo } from './StreamInfo'; @@ -41,7 +41,8 @@ export const DepositSuperToken: FC = ({ }) => { const [amount, setAmount] = useState(0n); - const { address } = useAccount(); + const { address, chain } = useAccount(); + const recurringNetworkID = chain?.id ?? 0; const { formatMessage } = useIntl(); const { @@ -77,13 +78,13 @@ export const DepositSuperToken: FC = ({ if (!address || !superToken || !token) return; try { setStep(EModifySuperTokenSteps.APPROVING); - await ensureCorrectNetwork(config.OPTIMISM_NETWORK_NUMBER); + await ensureCorrectNetwork(recurringNetworkID); const approve = await approveERC20tokenTransfer( amount, address, superToken.id, //superTokenAddress token.id, //tokenAddress - config.OPTIMISM_CONFIG.id, + recurringNetworkID, isSafeEnv, ); if (approve) { @@ -100,7 +101,7 @@ export const DepositSuperToken: FC = ({ const onDeposit = async () => { try { setStep(EModifySuperTokenSteps.DEPOSITING); - await ensureCorrectNetwork(config.OPTIMISM_NETWORK_NUMBER); + await ensureCorrectNetwork(recurringNetworkID); if (!address) { throw new Error('address not found1'); } @@ -116,7 +117,7 @@ export const DepositSuperToken: FC = ({ throw new Error('Provider or signer not found'); const _options = { - chainId: config.OPTIMISM_CONFIG.id, + chainId: recurringNetworkID, provider: provider, resolverAddress: isProduction ? undefined diff --git a/src/components/views/donate/Recurring/ModifySuperToken/ModifySuperTokenModal.tsx b/src/components/views/donate/Recurring/ModifySuperToken/ModifySuperTokenModal.tsx index 39bc665f41..d1b6774d3c 100644 --- a/src/components/views/donate/Recurring/ModifySuperToken/ModifySuperTokenModal.tsx +++ b/src/components/views/donate/Recurring/ModifySuperToken/ModifySuperTokenModal.tsx @@ -16,6 +16,7 @@ interface IModifySuperTokenModalProps extends IModal { selectedToken: ISuperToken | IToken; tokenStreams: ISuperfluidStream[]; refreshBalance: () => void; + recurringNetworkID: number; } const headerTitleGenerator = (step: EModifySuperTokenSteps) => { @@ -97,22 +98,30 @@ const ModifySuperTokenInnerModal: FC< IModifySuperTokenInnerModalProps > = props => { const [tab, setTab] = useState(EModifyTabs.DEPOSIT); - const [token, superToken] = useMemo( - () => - props.selectedToken.isSuperToken - ? [ - props.selectedToken.underlyingToken || - config.OPTIMISM_CONFIG.SUPER_FLUID_TOKENS.find( - token => token.id === props.selectedToken.id, - )?.underlyingToken, - props.selectedToken as ISuperToken, - ] - : [ - props.selectedToken, - findSuperTokenByTokenAddress(props.selectedToken.id), - ], - [props.selectedToken], - ); + const [token, superToken] = useMemo(() => { + let superTokens: any[] = []; + if (props.recurringNetworkID === config.OPTIMISM_NETWORK_NUMBER) { + superTokens = config.OPTIMISM_CONFIG.SUPER_FLUID_TOKENS; + } else if (props.recurringNetworkID === config.POLYGON_NETWORK_NUMBER) { + superTokens = config.BASE_CONFIG.SUPER_FLUID_TOKENS; + } + + return props.selectedToken.isSuperToken + ? [ + props.selectedToken.underlyingToken || + superTokens.find( + token => token.id === props.selectedToken.id, + )?.underlyingToken, + props.selectedToken as ISuperToken, + ] + : [ + props.selectedToken, + findSuperTokenByTokenAddress( + props.selectedToken.id, + props.recurringNetworkID, + ), + ]; + }, [props.selectedToken, props.recurringNetworkID]); return ( diff --git a/src/components/views/donate/Recurring/RecurringDonationCard.tsx b/src/components/views/donate/Recurring/RecurringDonationCard.tsx index e0f671c643..5250b55dc0 100644 --- a/src/components/views/donate/Recurring/RecurringDonationCard.tsx +++ b/src/components/views/donate/Recurring/RecurringDonationCard.tsx @@ -788,6 +788,7 @@ export const RecurringDonationCard = () => { setShowModal={setShowTopUpModal} selectedToken={selectedRecurringToken?.token!} refreshBalance={refetch} + recurringNetworkID={chain?.id || 0} /> )} {showAlloProtocolModal && ( diff --git a/src/components/views/donate/Recurring/RecurringDonationModal/RecurringDonationModal.tsx b/src/components/views/donate/Recurring/RecurringDonationModal/RecurringDonationModal.tsx index db441ec804..9a7e5564eb 100644 --- a/src/components/views/donate/Recurring/RecurringDonationModal/RecurringDonationModal.tsx +++ b/src/components/views/donate/Recurring/RecurringDonationModal/RecurringDonationModal.tsx @@ -284,10 +284,13 @@ const RecurringDonationInnerModal: FC = ({ flowRate: _flowRate.toString(), }; + // isUpdating is local variable to check if we are updating/modifying the flow let projectFlowOp = isUpdating ? superToken.updateFlow(options) : superToken.createFlow(options); + // TODO if isUpdating is false we need to check if there is an existing flow in the network + operations.push(projectFlowOp); const isDonatingToGiveth = !isUpdating && donationToGiveth > 0; console.log( diff --git a/src/components/views/userProfile/donationsTab/recurringTab/StreamRow.tsx b/src/components/views/userProfile/donationsTab/recurringTab/StreamRow.tsx index 7df4fbd631..bb5bf9661a 100644 --- a/src/components/views/userProfile/donationsTab/recurringTab/StreamRow.tsx +++ b/src/components/views/userProfile/donationsTab/recurringTab/StreamRow.tsx @@ -122,6 +122,7 @@ export const StreamRow: FC = ({ tokenStream }) => { setShowModal={setShowModifyModal} selectedToken={superToken} refreshBalance={refetch} + recurringNetworkID={chainId || 0} /> )} diff --git a/src/config/development.tsx b/src/config/development.tsx index 11f737c951..848a610b34 100644 --- a/src/config/development.tsx +++ b/src/config/development.tsx @@ -424,6 +424,23 @@ const config: EnvConfig = { // Keep it empty for automatic configuration }, chainLogo: (logoSize?: number) => , + SUPER_FLUID_TOKENS: [ + { + underlyingToken: { + decimals: 18, + id: '0x6B0dacea6a72E759243c99Eaed840DEe9564C194', + name: 'fUSDC Fake Token', + symbol: 'USDC', + coingeckoId: 'usd-coin', + }, + decimals: 18, + id: '0x1650581F573eAd727B92073B5Ef8B4f5B94D1648', + name: 'Super fUSDC Fake Token', + symbol: 'fUSDCx', + isSuperToken: true, + coingeckoId: 'usd-coin', + }, + ], }, ZKEVM_CONFIG: { From 5936a0ac7ace99f4bd1f0cba9614a8c55e2a1424 Mon Sep 17 00:00:00 2001 From: kkatusic Date: Tue, 10 Dec 2024 11:09:40 +0100 Subject: [PATCH 06/14] wrong network modal refactoring --- lang/ca.json | 2 +- lang/en.json | 2 +- lang/es.json | 2 +- .../views/donate/WrongNetworkLayer.tsx | 103 +++++++----------- 4 files changed, 43 insertions(+), 66 deletions(-) diff --git a/lang/ca.json b/lang/ca.json index 2bf2679f80..27b4fbedbd 100644 --- a/lang/ca.json +++ b/lang/ca.json @@ -864,7 +864,7 @@ "label.recipient_addresses": "adreces destinatàries", "label.recipient_addresses_cant": "Les adreces dels destinataris no poden estar buides", "label.recurring_donation": "Donació Recurrent", - "label.recurring_donations_currently_only_available_on_optimism_base": "Les donacions recurrents estan disponibles actualment només a les xarxes Optimism i Base.", + "label.recurring_donations_currently_only_available_on_optimism_base": "Les donacions recurrents només estan disponibles actualment a Optimism o Base.", "label.recurring_donation_card_subheader_1": "Transmeteu les vostres donacions al llarg del temps per proporcionar finançament continu.", "label.recurring_donation_card_subheader_2": "Decideix la quantitat de tokens a dipositar en el teu saldo de transmissió, o utilitza el/els teu(s) saldo(s) de transmissió existent(s). Estableix l'import de la donació mensual en tokens i comença a transmetre.", "label.recurring_donation_maximum": "Això supera el màxim que pots donar mensualment, recarrega el saldo del teu flux per donar més!", diff --git a/lang/en.json b/lang/en.json index 4de6e6207c..1168f7cc31 100644 --- a/lang/en.json +++ b/lang/en.json @@ -864,7 +864,7 @@ "label.recipient_addresses": "recipient addresses", "label.recipient_addresses_cant": "Recipient addresses can't be empty", "label.recurring_donation": "Recurring Donation", - "label.recurring_donations_currently_only_available_on_optimism_base": "Recurring donations are currently only available on Optimism and Base networks.", + "label.recurring_donations_currently_only_available_on_optimism_base": "Recurring donations are currently only available on Optimism or Base.", "label.recurring_donation_card_subheader_1": "Stream your donations over time to provide continuous funding.", "label.recurring_donation_card_subheader_2": "Decide the number of tokens to deposit in your stream balance, or utilize your existing stream balance(s). Set the monthly donation amount in tokens and begin streaming.", "label.recurring_donation_maximum": "This is over the maximum you can donate monthly, top-up your stream balance to donate more!", diff --git a/lang/es.json b/lang/es.json index f017e04d76..173e238938 100644 --- a/lang/es.json +++ b/lang/es.json @@ -864,7 +864,7 @@ "label.recipient_addresses": "direcciones de los destinatarios", "label.recipient_addresses_cant": "Las direcciones de los destinatarios no pueden estar vacías", "label.recurring_donation": "Donación Recurrente", - "label.recurring_donations_currently_only_available_on_optimism_base": "Las donaciones recurrentes están actualmente disponibles solo en las redes Optimism y Base.", + "label.recurring_donations_currently_only_available_on_optimism_base": "Las donaciones recurrentes están disponibles actualmente solo en Optimism o Base.", "label.recurring_donation_card_subheader_1": "Transmite tus donaciones con el tiempo para proporcionar financiamiento continuo.", "label.recurring_donation_card_subheader_2": "Decide la cantidad de tokens a depositar en tu saldo de transmisión, o utiliza tu(s) saldo(s) de transmisión existente(s). Establece el monto de la donación mensual en tokens y comienza a transmitir.", "label.recurring_donation_maximum": "¡Esto supera el máximo que puedes donar mensualmente, recarga el saldo de tu transmisión para donar más!", diff --git a/src/components/views/donate/WrongNetworkLayer.tsx b/src/components/views/donate/WrongNetworkLayer.tsx index f28941af42..a103566297 100644 --- a/src/components/views/donate/WrongNetworkLayer.tsx +++ b/src/components/views/donate/WrongNetworkLayer.tsx @@ -1,35 +1,24 @@ import React from 'react'; import styled from 'styled-components'; import { - B, Caption, IconInfoFilled16, brandColors, neutralColors, Flex, FlexCenter, + Button, } from '@giveth/ui-design-system'; import { useSwitchChain } from 'wagmi'; import { useIntl } from 'react-intl'; import config from '@/configuration'; import { useGeneralWallet } from '@/providers/generalWalletProvider'; -import NetworkLogo from '@/components/NetworkLogo'; -import { ChainType } from '@/types/config'; export const WrongNetworkLayer = () => { const { switchChain } = useSwitchChain(); const { isOnEVM, handleSingOutAndSignInWithEVM } = useGeneralWallet(); const { formatMessage } = useIntl(); - // List of recurring networks for user to select - const networks = [ - { - name: config.OPTIMISM_CONFIG.name, - chainId: config.OPTIMISM_NETWORK_NUMBER, - }, - { name: config.BASE_CONFIG.name, chainId: config.BASE_NETWORK_NUMBER }, - ]; - return ( @@ -42,35 +31,6 @@ export const WrongNetworkLayer = () => { })} - {networks.map(network => ( - - { - if (isOnEVM) { - switchChain && - switchChain({ - chainId: network.chainId, - }); - } else { - await handleSingOutAndSignInWithEVM(); - } - }} - > - - - {formatMessage({ - id: 'label.switch_network', - })}{' '} - to {network.name} - - - - ))} {formatMessage( @@ -80,8 +40,40 @@ export const WrongNetworkLayer = () => { { network: ( <> - {config.OPTIMISM_CONFIG.name} or{' '} - {config.BASE_CONFIG.name} + { + if (isOnEVM) { + switchChain && + switchChain({ + chainId: + config + .OPTIMISM_CONFIG + .id, + }); + } else { + await handleSingOutAndSignInWithEVM(); + } + }} + />{' '} + or{' '} + { + if (isOnEVM) { + switchChain && + switchChain({ + chainId: + config.BASE_CONFIG + .id, + }); + } else { + await handleSingOutAndSignInWithEVM(); + } + }} + /> ), }, @@ -123,11 +115,11 @@ const Title = styled(Flex)` color: ${brandColors.giv[500]}; `; -const SwitchButton = styled(B)` - cursor: pointer; - color: ${brandColors.pinky[500]}; - &:hover { - color: ${brandColors.pinky[600]}; +const ButtonLinkHolder = styled(Button)` + display: inline-block !important; + padding: 0; + & span:hover { + color: ${neutralColors.gray[400]}; } `; @@ -136,18 +128,3 @@ const Desc = styled(Caption)` margin-top: 8px; text-align: left; `; - -const NetworkWrapper = styled(Flex)` - width: 100%; -`; - -const SwitchButtonHolder = styled(SwitchButton)` - display: flex; - align-items: center; - gap: 8px; - margin-bottom: 8px; -`; - -const NetworkNameHolder = styled.div` - padding-right: 10px; -`; From a333527755addf4de28d37571436639ce42f90c1 Mon Sep 17 00:00:00 2001 From: kkatusic Date: Tue, 10 Dec 2024 13:47:56 +0100 Subject: [PATCH 07/14] fixing additional flow check --- .../RecurringDonationModal.tsx | 35 +++++++++++++------ src/helpers/donate.ts | 35 +++++++++++++++++++ 2 files changed, 60 insertions(+), 10 deletions(-) diff --git a/src/components/views/donate/Recurring/RecurringDonationModal/RecurringDonationModal.tsx b/src/components/views/donate/Recurring/RecurringDonationModal/RecurringDonationModal.tsx index 9a7e5564eb..c764dd5052 100644 --- a/src/components/views/donate/Recurring/RecurringDonationModal/RecurringDonationModal.tsx +++ b/src/components/views/donate/Recurring/RecurringDonationModal/RecurringDonationModal.tsx @@ -24,6 +24,7 @@ import config, { isProduction } from '@/configuration'; import { findSuperTokenByTokenAddress, findUserActiveStreamOnSelectedToken, + checkIfRecurringFlowExist, } from '@/helpers/donate'; import { ONE_MONTH_SECONDS } from '@/lib/constants/constants'; import { RunOutInfo } from '../RunOutInfo'; @@ -255,8 +256,25 @@ const RecurringDonationInnerModal: FC = ({ .toBigInt(); } + // isUpdating is local variable to check if we are updating/modifying the flow + let willUpdateFlow = isUpdating; + + // if isUpdating is false we need to check if there is an existing flow in the network + if (willUpdateFlow === false) { + const existingFlow = await checkIfRecurringFlowExist( + sf, + _superToken.id, + address, + projectAnchorContract, + signer, + ); + if (existingFlow.exists && existingFlow.flowRate !== '0') { + willUpdateFlow = true; + } + } + // Upgrade the token to super token - if (!isUpdating && !selectedRecurringToken.token.isSuperToken) { + if (!willUpdateFlow && !selectedRecurringToken.token.isSuperToken) { const upgradeOperation = await superToken.upgrade({ amount: newAmount.toString(), }); @@ -284,19 +302,16 @@ const RecurringDonationInnerModal: FC = ({ flowRate: _flowRate.toString(), }; - // isUpdating is local variable to check if we are updating/modifying the flow - let projectFlowOp = isUpdating + let projectFlowOp = willUpdateFlow ? superToken.updateFlow(options) : superToken.createFlow(options); - // TODO if isUpdating is false we need to check if there is an existing flow in the network - operations.push(projectFlowOp); - const isDonatingToGiveth = !isUpdating && donationToGiveth > 0; + const isDonatingToGiveth = !willUpdateFlow && donationToGiveth > 0; console.log( 'isDonatingToGiveth', isDonatingToGiveth, - isUpdating, + willUpdateFlow, donationToGiveth > 0, ); let givethOldStream; @@ -352,7 +367,7 @@ const RecurringDonationInnerModal: FC = ({ flowRate: _flowRate, superToken: _superToken, isBatch, - isForUpdate: isUpdating, + isForUpdate: willUpdateFlow, }; // Save Draft Donation @@ -367,7 +382,7 @@ const RecurringDonationInnerModal: FC = ({ flowRate: givethFlowRate, superToken: _superToken, isBatch, - isForUpdate: isUpdating, + isForUpdate: willUpdateFlow, }; let givethDraftDonationId = 0; if (isDonatingToGiveth) { @@ -393,7 +408,7 @@ const RecurringDonationInnerModal: FC = ({ txHash: tx.hash, draftDonationId: projectDraftDonationId, }; - if (isUpdating) { + if (willUpdateFlow) { console.log('Start Update Project Donation Info'); projectDonationId = await updateRecurringDonation(projectDonationInfo); diff --git a/src/helpers/donate.ts b/src/helpers/donate.ts index c4f6203060..ec634671cf 100644 --- a/src/helpers/donate.ts +++ b/src/helpers/donate.ts @@ -62,3 +62,38 @@ export const countActiveStreams = (tokenStreams: ISuperfluidStream[]) => { 0 ); }; + +// Function to check if a flow exists +export const checkIfRecurringFlowExist = async ( + sf: { + cfaV1: { + getFlow: (arg0: { + superToken: any; + sender: any; + receiver: any; + providerOrSigner: any; + }) => any; + }; + }, + superTokenAddress: any, + senderAddress: any, + receiverAddress: any, + signer: any, +) => { + try { + const flowInfo = await sf.cfaV1.getFlow({ + superToken: superTokenAddress, + sender: senderAddress, + receiver: receiverAddress, + providerOrSigner: signer, + }); + console.log( + `Existing flow found. Current flow rate: ${flowInfo.flowRate}`, + ); + console.log({ flowInfo }); + return { exists: true, flowRate: flowInfo.flowRate }; + } catch (error) { + console.log('No existing flow found.'); + return { exists: false, flowRate: '0' }; + } +}; From 5091d99e9a442fad4b03ac539adef5565acbe78c Mon Sep 17 00:00:00 2001 From: kkatusic Date: Tue, 10 Dec 2024 14:06:52 +0100 Subject: [PATCH 08/14] removing console logs --- src/helpers/donate.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/helpers/donate.ts b/src/helpers/donate.ts index ec634671cf..a9f251d32a 100644 --- a/src/helpers/donate.ts +++ b/src/helpers/donate.ts @@ -87,13 +87,8 @@ export const checkIfRecurringFlowExist = async ( receiver: receiverAddress, providerOrSigner: signer, }); - console.log( - `Existing flow found. Current flow rate: ${flowInfo.flowRate}`, - ); - console.log({ flowInfo }); return { exists: true, flowRate: flowInfo.flowRate }; } catch (error) { - console.log('No existing flow found.'); return { exists: false, flowRate: '0' }; } }; From 9e56dbda96f738f4a1470f0ae5d929894312baa2 Mon Sep 17 00:00:00 2001 From: kkatusic Date: Fri, 13 Dec 2024 12:50:15 +0100 Subject: [PATCH 09/14] adding condition for base recurring for tab on donations --- src/components/views/donate/DonationCard.tsx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/components/views/donate/DonationCard.tsx b/src/components/views/donate/DonationCard.tsx index 46524157ee..9af4a87bf7 100644 --- a/src/components/views/donate/DonationCard.tsx +++ b/src/components/views/donate/DonationCard.tsx @@ -63,6 +63,13 @@ export const DonationCard: FC = ({ address.chainType === ChainType.EVM && address.networkId === config.OPTIMISM_NETWORK_NUMBER, ); + const hasBaseAddress = + addresses && + addresses.some( + address => + address.chainType === ChainType.EVM && + address.networkId === config.BASE_NETWORK_NUMBER, + ); const isEndaomentProject = project?.organization?.label === 'endaoment'; const isOwnerOnEVM = project?.adminUser?.walletAddress && @@ -173,7 +180,7 @@ export const DonationCard: FC = ({ })} {!disableRecurringDonations && - hasOpAddress && + (hasOpAddress || hasBaseAddress) && isOwnerOnEVM ? ( Date: Wed, 18 Dec 2024 00:56:03 +0100 Subject: [PATCH 10/14] fixing adding anchor contract --- .../create/AlloProtocol/AlloProtocolModal.tsx | 112 +++++++++--------- .../AlloProtocolFirstDonationModal.tsx | 110 ++++++++--------- .../ModifySuperToken/WithDrawSuperToken.tsx | 9 +- .../Recurring/RecurringDonationCard.tsx | 4 +- .../RecurringDonationModal.tsx | 1 + .../projectActionCard/AdminActions.tsx | 1 + .../ModifyStreamInnerModal.tsx | 3 +- .../UpdateStreamInnerModal.tsx | 3 +- .../projectsTab/ClaimWithdrawalModal.tsx | 32 +++-- .../projectsTab/ProjectActions.tsx | 1 + src/helpers/superfluid.ts | 7 +- 11 files changed, 157 insertions(+), 126 deletions(-) diff --git a/src/components/views/create/AlloProtocol/AlloProtocolModal.tsx b/src/components/views/create/AlloProtocol/AlloProtocolModal.tsx index ffd95248f0..532c2e14c7 100644 --- a/src/components/views/create/AlloProtocol/AlloProtocolModal.tsx +++ b/src/components/views/create/AlloProtocol/AlloProtocolModal.tsx @@ -122,64 +122,70 @@ const AlloProtocolModal: FC = ({ ? chain.id === config.OPTIMISM_NETWORK_NUMBER : false; + const isOnBase = chain ? chain.id === config.BASE_NETWORK_NUMBER : false; + const handleButtonClick = async () => { - if (!isOnOptimism) { - switchChain?.({ chainId: config.OPTIMISM_NETWORK_NUMBER }); - } else { - try { - setIsLoading(true); - const hash = await writeContract(wagmiConfig, { - address: config.OPTIMISM_CONFIG.anchorRegistryAddress, - functionName: 'createProfile', - abi: createProfileABI.abi, - chainId: config.OPTIMISM_NETWORK_NUMBER, - args: [ - generateRandomNonce(), //nonce - addedProjectState?.id!, - { - protocol: 1, - pointer: '', - }, - addedProjectState?.adminUser?.walletAddress, //admin user wallet address - [], - ], + try { + setIsLoading(true); + const hash = await writeContract(wagmiConfig, { + address: isOnOptimism + ? config.OPTIMISM_CONFIG.anchorRegistryAddress + : config.BASE_CONFIG.anchorRegistryAddress, + functionName: 'createProfile', + abi: createProfileABI.abi, + chainId: isOnOptimism + ? config.OPTIMISM_NETWORK_NUMBER + : config.BASE_NETWORK_NUMBER, + args: [ + generateRandomNonce(), //nonce + addedProjectState?.id!, + { + protocol: 1, + pointer: '', + }, + addedProjectState?.adminUser?.walletAddress, //admin user wallet address + [], + ], + }); + setTxResult(hash); + if (hash) { + const data = await waitForTransactionReceipt(wagmiConfig, { + hash: hash, + chainId: isOnOptimism + ? config.OPTIMISM_NETWORK_NUMBER + : config.BASE_NETWORK_NUMBER, }); - setTxResult(hash); - if (hash) { - const data = await waitForTransactionReceipt(wagmiConfig, { - hash: hash, - chainId: config.OPTIMISM_NETWORK_NUMBER, - }); - - const contractAddress = extractContractAddressFromString( - data.logs[0].data, + + const contractAddress = extractContractAddressFromString( + data.logs[0].data, + ); + //Call backend to update project + await client.mutate({ + mutation: CREATE_ANCHOR_CONTRACT_ADDRESS_QUERY, + variables: { + projectId: Number(addedProjectState.id), + networkId: isOnOptimism + ? config.OPTIMISM_NETWORK_NUMBER + : config.BASE_NETWORK_NUMBER, + address: contractAddress, + txHash: hash, + }, + }); + if (!isEditMode || (isEditMode && isDraft)) { + await router.push( + slugToSuccessView(addedProjectState.slug), + ); + } else { + await router.push( + slugToProjectView(addedProjectState.slug), ); - //Call backend to update project - await client.mutate({ - mutation: CREATE_ANCHOR_CONTRACT_ADDRESS_QUERY, - variables: { - projectId: Number(addedProjectState.id), - networkId: config.OPTIMISM_NETWORK_NUMBER, - address: contractAddress, - txHash: hash, - }, - }); - if (!isEditMode || (isEditMode && isDraft)) { - await router.push( - slugToSuccessView(addedProjectState.slug), - ); - } else { - await router.push( - slugToProjectView(addedProjectState.slug), - ); - } } - setShowModal(false); // Close the modal - } catch (error) { - console.error('Error Contract', error); - } finally { - setIsLoading(false); } + setShowModal(false); // Close the modal + } catch (error) { + console.error('Error Contract', error); + } finally { + setIsLoading(false); } }; diff --git a/src/components/views/donate/Recurring/AlloProtocolFirstDonationModal.tsx b/src/components/views/donate/Recurring/AlloProtocolFirstDonationModal.tsx index f0322bc7d7..70c35f8f1e 100644 --- a/src/components/views/donate/Recurring/AlloProtocolFirstDonationModal.tsx +++ b/src/components/views/donate/Recurring/AlloProtocolFirstDonationModal.tsx @@ -64,62 +64,66 @@ const AlloProtocolFirstDonationModal: FC = ({ : false; const handleButtonClick = async () => { - if (!isOnOptimism) { - switchChain?.({ chainId: config.OPTIMISM_NETWORK_NUMBER }); - } else { - try { - setIsLoading(true); - if ( - !project?.adminUser?.walletAddress || - !isAddress(project?.adminUser?.walletAddress) - ) { - throw new Error('Invalid Project Admin Address'); - } - const hash = await writeContract(wagmiConfig, { - address: config.OPTIMISM_CONFIG.anchorRegistryAddress, - functionName: 'createProfile', - abi: createProfileABI.abi, - chainId: config.OPTIMISM_NETWORK_NUMBER, - args: [ - generateRandomNonce(), //nonce - project?.id!, - { - protocol: 1, - pointer: '', - }, - project?.adminUser?.walletAddress, //admin user wallet address - [], - ], + try { + setIsLoading(true); + if ( + !project?.adminUser?.walletAddress || + !isAddress(project?.adminUser?.walletAddress) + ) { + throw new Error('Invalid Project Admin Address'); + } + const hash = await writeContract(wagmiConfig, { + address: isOnOptimism + ? config.OPTIMISM_CONFIG.anchorRegistryAddress + : config.BASE_CONFIG.anchorRegistryAddress, + functionName: 'createProfile', + abi: createProfileABI.abi, + chainId: isOnOptimism + ? config.OPTIMISM_NETWORK_NUMBER + : config.BASE_NETWORK_NUMBER, + args: [ + generateRandomNonce(), //nonce + project?.id!, + { + protocol: 1, + pointer: '', + }, + project?.adminUser?.walletAddress, //admin user wallet address + [], + ], + }); + setTxResult(hash); + if (hash) { + const data = await waitForTransactionReceipt(wagmiConfig, { + hash: hash, + chainId: isOnOptimism + ? config.OPTIMISM_NETWORK_NUMBER + : config.BASE_NETWORK_NUMBER, }); - setTxResult(hash); - if (hash) { - const data = await waitForTransactionReceipt(wagmiConfig, { - hash: hash, - chainId: config.OPTIMISM_NETWORK_NUMBER, - }); - const contractAddress = extractContractAddressFromString( - data.logs[0].data, - ); - //Call backend to update project - await client.mutate({ - mutation: CREATE_ANCHOR_CONTRACT_ADDRESS_QUERY, - variables: { - projectId: Number(project.id), - networkId: config.OPTIMISM_NETWORK_NUMBER, - address: contractAddress, - txHash: hash, - }, - }); - await fetchProject(); - onModalCompletion(); - } - setShowModal(false); // Close the modal - } catch (error) { - showToastError(error); - } finally { - setIsLoading(false); + const contractAddress = extractContractAddressFromString( + data.logs[0].data, + ); + //Call backend to update project + await client.mutate({ + mutation: CREATE_ANCHOR_CONTRACT_ADDRESS_QUERY, + variables: { + projectId: Number(project.id), + networkId: isOnOptimism + ? config.OPTIMISM_NETWORK_NUMBER + : config.BASE_NETWORK_NUMBER, + address: contractAddress, + txHash: hash, + }, + }); + await fetchProject(); + onModalCompletion(); } + setShowModal(false); // Close the modal + } catch (error) { + showToastError(error); + } finally { + setIsLoading(false); } }; diff --git a/src/components/views/donate/Recurring/ModifySuperToken/WithDrawSuperToken.tsx b/src/components/views/donate/Recurring/ModifySuperToken/WithDrawSuperToken.tsx index f0f1e5cd9e..8c3d1501db 100644 --- a/src/components/views/donate/Recurring/ModifySuperToken/WithDrawSuperToken.tsx +++ b/src/components/views/donate/Recurring/ModifySuperToken/WithDrawSuperToken.tsx @@ -11,7 +11,7 @@ import { IModifySuperTokenInnerModalProps } from './ModifySuperTokenModal'; import { ISuperToken, IToken } from '@/types/superFluid'; import { actionButtonLabel, EModifySuperTokenSteps } from './common'; import { ModifyWrapper, Wrapper } from './common.sc'; -import config, { isProduction } from '@/configuration'; +import { isProduction } from '@/configuration'; import { showToastError } from '@/lib/helpers'; import { Item } from '../RecurringDonationModal/Item'; import { RunOutInfo } from '../RunOutInfo'; @@ -36,7 +36,8 @@ export const WithDrawSuperToken: FC = ({ closeModal, }) => { const [amount, setAmount] = useState(0n); - const { address } = useAccount(); + const { address, chain } = useAccount(); + const recurringNetworkID = chain?.id ?? 0; const { formatMessage } = useIntl(); const tokenPrice = useTokenPrice(token); const [isWarning, setIsWarning] = useState(false); @@ -60,7 +61,7 @@ export const WithDrawSuperToken: FC = ({ const onWithdraw = async () => { setStep(EModifySuperTokenSteps.WITHDRAWING); try { - await ensureCorrectNetwork(config.OPTIMISM_NETWORK_NUMBER); + await ensureCorrectNetwork(recurringNetworkID); if (!address) { throw new Error('address not found1'); } @@ -76,7 +77,7 @@ export const WithDrawSuperToken: FC = ({ throw new Error('Provider or signer not found'); const _options = { - chainId: config.OPTIMISM_CONFIG.id, + chainId: recurringNetworkID, provider: provider, resolverAddress: isProduction ? undefined diff --git a/src/components/views/donate/Recurring/RecurringDonationCard.tsx b/src/components/views/donate/Recurring/RecurringDonationCard.tsx index 5250b55dc0..0a29355b58 100644 --- a/src/components/views/donate/Recurring/RecurringDonationCard.tsx +++ b/src/components/views/donate/Recurring/RecurringDonationCard.tsx @@ -163,8 +163,8 @@ export const RecurringDonationCard = () => { tokenStreams[selectedRecurringToken?.token.id.toLowerCase() || '']; const anchorContractAddress = useMemo( - () => findAnchorContractAddress(project.anchorContracts), - [project.anchorContracts], + () => findAnchorContractAddress(project.anchorContracts, chain?.id), + [project.anchorContracts, chain?.id], ); // otherStreamsPerSec is the total flow rate of all streams except the one to the project diff --git a/src/components/views/donate/Recurring/RecurringDonationModal/RecurringDonationModal.tsx b/src/components/views/donate/Recurring/RecurringDonationModal/RecurringDonationModal.tsx index c764dd5052..c4bb4c05aa 100644 --- a/src/components/views/donate/Recurring/RecurringDonationModal/RecurringDonationModal.tsx +++ b/src/components/views/donate/Recurring/RecurringDonationModal/RecurringDonationModal.tsx @@ -190,6 +190,7 @@ const RecurringDonationInnerModal: FC = ({ setStep(EDonationSteps.DONATING); const projectAnchorContract = findAnchorContractAddress( project?.anchorContracts, + recurringNetworkID, ); if (!projectAnchorContract) { throw new Error('Project anchor address not found'); diff --git a/src/components/views/project/projectActionCard/AdminActions.tsx b/src/components/views/project/projectActionCard/AdminActions.tsx index 2460486d83..bafef0f83c 100644 --- a/src/components/views/project/projectActionCard/AdminActions.tsx +++ b/src/components/views/project/projectActionCard/AdminActions.tsx @@ -67,6 +67,7 @@ export const AdminActions = () => { const anchorContractAddress = findAnchorContractAddress( project.anchorContracts, + chain?.id, ); const options: IOption[] = [ diff --git a/src/components/views/userProfile/donationsTab/recurringTab/ModifyStreamModal/ModifyStreamInnerModal.tsx b/src/components/views/userProfile/donationsTab/recurringTab/ModifyStreamModal/ModifyStreamInnerModal.tsx index 0ee6388caa..c27bb2f01f 100644 --- a/src/components/views/userProfile/donationsTab/recurringTab/ModifyStreamModal/ModifyStreamInnerModal.tsx +++ b/src/components/views/userProfile/donationsTab/recurringTab/ModifyStreamModal/ModifyStreamInnerModal.tsx @@ -62,7 +62,7 @@ export const ModifyStreamInnerModal: FC = ({ otherStreamsTotalFlowRate: 0n, }); const { formatMessage } = useIntl(); - const { address } = useAccount(); + const { address, chain } = useAccount(); // Get the balance of the super token const { data: balance } = useBalance({ @@ -117,6 +117,7 @@ export const ModifyStreamInnerModal: FC = ({ }; const anchorContractAddress = findAnchorContractAddress( donation.project.anchorContracts, + chain?.id, ); for (let i = 0; i < tokenStream.length; i++) { const ts = tokenStream[i]; diff --git a/src/components/views/userProfile/donationsTab/recurringTab/ModifyStreamModal/UpdateStreamInnerModal.tsx b/src/components/views/userProfile/donationsTab/recurringTab/ModifyStreamModal/UpdateStreamInnerModal.tsx index 0305bcde03..783c444c3c 100644 --- a/src/components/views/userProfile/donationsTab/recurringTab/ModifyStreamModal/UpdateStreamInnerModal.tsx +++ b/src/components/views/userProfile/donationsTab/recurringTab/ModifyStreamModal/UpdateStreamInnerModal.tsx @@ -51,7 +51,7 @@ export const UpdateStreamInnerModal: FC = ({ const [tx, setTx] = useState(''); const { formatMessage } = useIntl(); const tokenPrice = useTokenPrice(token); - const { address } = useAccount(); + const { address, chain } = useAccount(); const { refetchTokenStream } = useProfileDonateTabData(); const onDonate = async () => { @@ -60,6 +60,7 @@ export const UpdateStreamInnerModal: FC = ({ await ensureCorrectNetwork(config.OPTIMISM_NETWORK_NUMBER); const projectAnchorContract = findAnchorContractAddress( donation.project.anchorContracts, + chain?.id, ); if (!projectAnchorContract) { throw new Error('Project anchor address not found'); diff --git a/src/components/views/userProfile/projectsTab/ClaimWithdrawalModal.tsx b/src/components/views/userProfile/projectsTab/ClaimWithdrawalModal.tsx index a28cd8695d..d8de2ce4eb 100644 --- a/src/components/views/userProfile/projectsTab/ClaimWithdrawalModal.tsx +++ b/src/components/views/userProfile/projectsTab/ClaimWithdrawalModal.tsx @@ -10,6 +10,7 @@ import { Address, encodeFunctionData } from 'viem'; import { useState } from 'react'; import { useIntl } from 'react-intl'; import { writeContract, waitForTransactionReceipt } from '@wagmi/core'; +import { useAccount } from 'wagmi'; import { Modal } from '@/components/modals/Modal'; import { IModal } from '@/types/common'; import { useModalAnimation } from '@/hooks/useModalAnimation'; @@ -75,18 +76,29 @@ const ClaimWithdrawalModal = ({ useState(ClaimTransactionState.NOT_STARTED); const [txHash, setTxHash] = useState
(); const { formatMessage } = useIntl(); + const { chain } = useAccount(); + const recurringNetworkID = chain?.id ?? 0; const projectName = project.title || ''; - const optimismAddress = project.addresses?.find( - address => address.networkId === config.OPTIMISM_NETWORK_NUMBER, - )?.address; + let projectAddress = ''; + if (recurringNetworkID === config.OPTIMISM_NETWORK_NUMBER) { + projectAddress = + project.addresses?.find( + address => address.networkId === config.OPTIMISM_NETWORK_NUMBER, + )?.address || ''; + } else if (recurringNetworkID === config.BASE_NETWORK_NUMBER) { + projectAddress = + project.addresses?.find( + address => address.networkId === config.BASE_NETWORK_NUMBER, + )?.address || ''; + } const isETHx = selectedStream.token.symbol.toLowerCase() === 'ethx'; const handleConfirm = async () => { console.log('anchorContractAddress', anchorContractAddress); try { console.log('isETHx', isETHx); - await ensureCorrectNetwork(config.OPTIMISM_NETWORK_NUMBER); + await ensureCorrectNetwork(recurringNetworkID); const encodedDowngradeTo = isETHx ? encodeFunctionData({ abi: ISETH.abi, @@ -97,7 +109,7 @@ const ClaimWithdrawalModal = ({ abi: superTokenABI.abi, functionName: 'downgradeTo', args: [ - optimismAddress, + projectAddress, +selectedStream.balance.toString(), ], }); @@ -114,7 +126,7 @@ const ClaimWithdrawalModal = ({ abi: anchorContractABI.abi, address: anchorContractAddress, functionName: 'execute', - chainId: config.OPTIMISM_NETWORK_NUMBER, + chainId: recurringNetworkID, args: [selectedStream.token.id, '', encodedDowngradeTo], }); @@ -124,7 +136,7 @@ const ClaimWithdrawalModal = ({ wagmiConfig, { hash: tx, - chainId: config.OPTIMISM_NETWORK_NUMBER, + chainId: recurringNetworkID, }, ); @@ -141,9 +153,9 @@ const ClaimWithdrawalModal = ({ abi: anchorContractABI.abi, address: anchorContractAddress, functionName: 'execute', - chainId: config.OPTIMISM_NETWORK_NUMBER, + chainId: recurringNetworkID, args: [ - optimismAddress, + projectAddress, +selectedStream.balance.toString(), '', ], @@ -152,7 +164,7 @@ const ClaimWithdrawalModal = ({ if (transferEthTx) { await waitForTransactionReceipt(wagmiConfig, { hash: transferEthTx, - chainId: config.OPTIMISM_NETWORK_NUMBER, + chainId: recurringNetworkID, }); } setTransactionState(ClaimTransactionState.SUCCESS); diff --git a/src/components/views/userProfile/projectsTab/ProjectActions.tsx b/src/components/views/userProfile/projectsTab/ProjectActions.tsx index 10b897446b..176619f8d0 100644 --- a/src/components/views/userProfile/projectsTab/ProjectActions.tsx +++ b/src/components/views/userProfile/projectsTab/ProjectActions.tsx @@ -62,6 +62,7 @@ const ProjectActions: FC = ({ const anchorContractAddress = findAnchorContractAddress( project.anchorContracts, + chain?.id, ); const chainId = chain?.id; diff --git a/src/helpers/superfluid.ts b/src/helpers/superfluid.ts index 0c1dc054f7..83b80f23f1 100644 --- a/src/helpers/superfluid.ts +++ b/src/helpers/superfluid.ts @@ -14,7 +14,10 @@ export const findTokenByAddress = (address?: Address) => { export const findAnchorContractAddress = ( anchorContracts?: IAnchorContractData[], + chainId?: number, ) => { - if (!anchorContracts) return undefined; - return anchorContracts.find(contract => contract.isActive)?.address; + if (!anchorContracts || !chainId) return undefined; + return anchorContracts.find( + contract => contract.isActive && contract.networkId == chainId, + )?.address; }; From fa79c6cc03d2dbdf493f7204c7882fd1300111f0 Mon Sep 17 00:00:00 2001 From: kkatusic Date: Wed, 18 Dec 2024 01:02:13 +0100 Subject: [PATCH 11/14] adding superfluid anchor addresses --- src/config/production.tsx | 5 +++++ src/types/config.ts | 2 ++ 2 files changed, 7 insertions(+) diff --git a/src/config/production.tsx b/src/config/production.tsx index ac6b416890..b33e01dcfd 100644 --- a/src/config/production.tsx +++ b/src/config/production.tsx @@ -602,6 +602,11 @@ const config: EnvConfig = { subgraphAddress: '', coingeckoChainName: 'base', chainLogo: (logoSize = 24) => , + GIVETH_ANCHOR_CONTRACT_ADDRESS: + '0x5430757bc19c87ec562e4660e56af6cac324b50a', + superFluidSubgraph: + process.env.NEXT_PUBLIC_SUBGRAPH_SUPER_FLUID || + 'https://subgraph-endpoints.superfluid.dev/optimism-mainnet/protocol-v1', SUPER_FLUID_TOKENS: [ { underlyingToken: { diff --git a/src/types/config.ts b/src/types/config.ts index fc18f88341..7f641d3f5f 100644 --- a/src/types/config.ts +++ b/src/types/config.ts @@ -175,6 +175,8 @@ export interface OptimismNetworkConfig extends NetworkConfig { export interface BaseNetworkConfig extends NetworkConfig { SUPER_FLUID_TOKENS: Array; anchorRegistryAddress: Address; + GIVETH_ANCHOR_CONTRACT_ADDRESS: Address; + superFluidSubgraph: string; } interface MicroservicesConfig { From e1ace934d53318b057a4120ab543ad3c74e220ec Mon Sep 17 00:00:00 2001 From: kkatusic Date: Wed, 18 Dec 2024 09:30:58 +0100 Subject: [PATCH 12/14] fixing type error --- src/config/development.tsx | 5 +++++ src/config/production.tsx | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/config/development.tsx b/src/config/development.tsx index 4197243183..f51bbbf90e 100644 --- a/src/config/development.tsx +++ b/src/config/development.tsx @@ -425,6 +425,11 @@ const config: EnvConfig = { }, anchorRegistryAddress: '0x4AAcca72145e1dF2aeC137E1f3C5E3D75DB8b5f3', chainLogo: (logoSize?: number) => , + GIVETH_ANCHOR_CONTRACT_ADDRESS: + '0x5430757bc19c87ec562e4660e56af6cac324b50a', + superFluidSubgraph: + process.env.NEXT_PUBLIC_SUBGRAPH_SUPER_FLUID || + 'https://subgraph-endpoints.superfluid.dev/base-mainnet/protocol-v1', SUPER_FLUID_TOKENS: [ { underlyingToken: { diff --git a/src/config/production.tsx b/src/config/production.tsx index b33e01dcfd..4e940d3aca 100644 --- a/src/config/production.tsx +++ b/src/config/production.tsx @@ -606,7 +606,7 @@ const config: EnvConfig = { '0x5430757bc19c87ec562e4660e56af6cac324b50a', superFluidSubgraph: process.env.NEXT_PUBLIC_SUBGRAPH_SUPER_FLUID || - 'https://subgraph-endpoints.superfluid.dev/optimism-mainnet/protocol-v1', + 'https://subgraph-endpoints.superfluid.dev/base-mainnet/protocol-v1', SUPER_FLUID_TOKENS: [ { underlyingToken: { From ac1beef92f56de65917e2161781feee6e7894e95 Mon Sep 17 00:00:00 2001 From: kkatusic Date: Wed, 18 Dec 2024 10:03:40 +0100 Subject: [PATCH 13/14] fixing first donation modal --- .../Recurring/AlloProtocolFirstDonationModal.tsx | 14 ++++++-------- .../RecurringDonationModal.tsx | 7 ++++++- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/components/views/donate/Recurring/AlloProtocolFirstDonationModal.tsx b/src/components/views/donate/Recurring/AlloProtocolFirstDonationModal.tsx index 70c35f8f1e..1730fcf240 100644 --- a/src/components/views/donate/Recurring/AlloProtocolFirstDonationModal.tsx +++ b/src/components/views/donate/Recurring/AlloProtocolFirstDonationModal.tsx @@ -63,6 +63,8 @@ const AlloProtocolFirstDonationModal: FC = ({ ? chain.id === config.OPTIMISM_NETWORK_NUMBER : false; + const isOnBase = chain ? chain.id === config.BASE_NETWORK_NUMBER : false; + const handleButtonClick = async () => { try { setIsLoading(true); @@ -127,6 +129,8 @@ const AlloProtocolFirstDonationModal: FC = ({ } }; + const thereTitle = isOnOptimism ? 'Optimism' : isOnBase ? 'Base' : ''; + return ( = ({ id: 'label.there_will_be_one_extra_transaction_you_need_to_sign_to', })}{' '} - Optimism + {thereTitle} .


= ({ let givethFlowRate = 0n; if (isDonatingToGiveth) { const givethAnchorContract = - config.OPTIMISM_CONFIG.GIVETH_ANCHOR_CONTRACT_ADDRESS; + recurringNetworkID === config.OPTIMISM_NETWORK_NUMBER + ? config.OPTIMISM_CONFIG.GIVETH_ANCHOR_CONTRACT_ADDRESS + : config.BASE_CONFIG.GIVETH_ANCHOR_CONTRACT_ADDRESS; if (!givethAnchorContract) { throw new Error('Giveth wallet address not found'); @@ -337,6 +340,7 @@ const RecurringDonationInnerModal: FC = ({ _superToken, ); + // Update Giveth stream if it exists if (givethOldStream) { givethFlowRate = _newFlowRate + BigInt(givethOldStream.currentFlowRate); @@ -348,6 +352,7 @@ const RecurringDonationInnerModal: FC = ({ }); operations.push(givethFlowOp); } else { + // Create Giveth stream if it doesn't exist givethFlowRate = _newFlowRate; const givethFlowOp = superToken.createFlow({ sender: address, From de64843028e31ca91aa97de09f605461daeff0c1 Mon Sep 17 00:00:00 2001 From: kkatusic Date: Wed, 18 Dec 2024 13:26:25 +0100 Subject: [PATCH 14/14] adjusting modify and ends recurring donation --- .../recurringTab/EndStreamModal.tsx | 15 ++++++++++++--- .../ModifyStreamInnerModal.tsx | 6 ++++-- .../ModifyStreamModal/ModifyStreamModal.tsx | 18 ++++++++++++------ .../UpdateStreamInnerModal.tsx | 17 ++++++++++------- .../recurringTab/RecurringDonationsTable.tsx | 1 + .../recurringTab/StreamActionButton.tsx | 9 ++++++--- .../projectsTab/ClaimWithdrawalModal.tsx | 2 +- 7 files changed, 46 insertions(+), 22 deletions(-) diff --git a/src/components/views/userProfile/donationsTab/recurringTab/EndStreamModal.tsx b/src/components/views/userProfile/donationsTab/recurringTab/EndStreamModal.tsx index 2fd8130af4..a0505911f8 100644 --- a/src/components/views/userProfile/donationsTab/recurringTab/EndStreamModal.tsx +++ b/src/components/views/userProfile/donationsTab/recurringTab/EndStreamModal.tsx @@ -31,6 +31,7 @@ enum EEndStreamSteps { export interface IEndStreamModalProps extends IModal { donation: IWalletRecurringDonation; refetch: () => void; + recurringNetworkId: number; } export const EndStreamModal: FC = ({ ...props }) => { @@ -60,11 +61,13 @@ export const EndStreamModal: FC = ({ ...props }) => { interface IEndStreamInnerModalProps extends IEndStreamModalProps { closeModal: (refetch?: boolean) => void; + recurringNetworkId: number; } const EndStreamInnerModal: FC = ({ closeModal, donation, + recurringNetworkId, }) => { const [step, setStep] = useState(EEndStreamSteps.CONFIRM); const { formatMessage } = useIntl(); @@ -81,9 +84,15 @@ const EndStreamInnerModal: FC = ({ throw new Error('Please connect your wallet first'); } - const _superToken = config.OPTIMISM_CONFIG.SUPER_FLUID_TOKENS.find( - s => s.underlyingToken.symbol === donation.currency, - ); + const _superToken = + recurringNetworkId === config.OPTIMISM_NETWORK_NUMBER + ? config.OPTIMISM_CONFIG.SUPER_FLUID_TOKENS.find( + s => s.underlyingToken.symbol === donation.currency, + ) + : config.BASE_CONFIG.SUPER_FLUID_TOKENS.find( + s => s.underlyingToken.symbol === donation.currency, + ); + if (!_superToken) { throw new Error('SuperToken not found'); } diff --git a/src/components/views/userProfile/donationsTab/recurringTab/ModifyStreamModal/ModifyStreamInnerModal.tsx b/src/components/views/userProfile/donationsTab/recurringTab/ModifyStreamModal/ModifyStreamInnerModal.tsx index c27bb2f01f..1d8f9783e6 100644 --- a/src/components/views/userProfile/donationsTab/recurringTab/ModifyStreamModal/ModifyStreamInnerModal.tsx +++ b/src/components/views/userProfile/donationsTab/recurringTab/ModifyStreamModal/ModifyStreamInnerModal.tsx @@ -43,6 +43,7 @@ interface IModifyStreamInnerModalProps extends IModifyStreamModalProps { superToken: IToken; tokenStreams: ITokenStreams; setModifyInfo: Dispatch>; + recurringNetworkId: number; } interface IGeneralInfo { @@ -56,13 +57,14 @@ export const ModifyStreamInnerModal: FC = ({ setStep, tokenStreams, setModifyInfo, + recurringNetworkId, }) => { const [percentage, setPercentage] = useState(0); const [info, setInfo] = useState({ otherStreamsTotalFlowRate: 0n, }); const { formatMessage } = useIntl(); - const { address, chain } = useAccount(); + const { address } = useAccount(); // Get the balance of the super token const { data: balance } = useBalance({ @@ -117,7 +119,7 @@ export const ModifyStreamInnerModal: FC = ({ }; const anchorContractAddress = findAnchorContractAddress( donation.project.anchorContracts, - chain?.id, + recurringNetworkId, ); for (let i = 0; i < tokenStream.length; i++) { const ts = tokenStream[i]; diff --git a/src/components/views/userProfile/donationsTab/recurringTab/ModifyStreamModal/ModifyStreamModal.tsx b/src/components/views/userProfile/donationsTab/recurringTab/ModifyStreamModal/ModifyStreamModal.tsx index d245f04abc..09d333ce1a 100644 --- a/src/components/views/userProfile/donationsTab/recurringTab/ModifyStreamModal/ModifyStreamModal.tsx +++ b/src/components/views/userProfile/donationsTab/recurringTab/ModifyStreamModal/ModifyStreamModal.tsx @@ -28,6 +28,7 @@ export interface IModifyDonationInfo { export interface IModifyStreamModalProps extends IModal { donation: IWalletRecurringDonation; refetch: () => void; + recurringNetworkId: number; } export const ModifyStreamModal: FC = ({ @@ -39,13 +40,16 @@ export const ModifyStreamModal: FC = ({ const { formatMessage } = useIntl(); const { tokenStreams } = useUserStreams(); - const superToken = useMemo( - () => - config.OPTIMISM_CONFIG.SUPER_FLUID_TOKENS.find( + const superToken = useMemo(() => { + if (props.recurringNetworkId === config.OPTIMISM_NETWORK_NUMBER) { + return config.OPTIMISM_CONFIG.SUPER_FLUID_TOKENS.find( s => s.underlyingToken.symbol === props.donation.currency, - ), - [props.donation.currency], - ); + ); + } + return config.BASE_CONFIG.SUPER_FLUID_TOKENS.find( + s => s.underlyingToken.symbol === props.donation.currency, + ); + }, [props.recurringNetworkId, props.donation.currency]); const handleCloseModal = () => { if (step === EDonationSteps.SUCCESS) { @@ -71,6 +75,7 @@ export const ModifyStreamModal: FC = ({ tokenStreams={tokenStreams} superToken={superToken!} setModifyInfo={setModifyInfo} + recurringNetworkId={props.recurringNetworkId} /> ) : ( = ({ token={modifyInfo?.token!} closeModal={handleCloseModal} {...props} + recurringNetworkId={props.recurringNetworkId} /> )}
diff --git a/src/components/views/userProfile/donationsTab/recurringTab/ModifyStreamModal/UpdateStreamInnerModal.tsx b/src/components/views/userProfile/donationsTab/recurringTab/ModifyStreamModal/UpdateStreamInnerModal.tsx index 783c444c3c..a53f518f0e 100644 --- a/src/components/views/userProfile/donationsTab/recurringTab/ModifyStreamModal/UpdateStreamInnerModal.tsx +++ b/src/components/views/userProfile/donationsTab/recurringTab/ModifyStreamModal/UpdateStreamInnerModal.tsx @@ -10,7 +10,7 @@ import { Item } from '@/components/views/donate/Recurring/RecurringDonationModal import { IToken } from '@/types/superFluid'; import { RunOutInfo } from '@/components/views/donate/Recurring/RunOutInfo'; import { useTokenPrice } from '@/hooks/useTokenPrice'; -import config, { isProduction } from '@/configuration'; +import { isProduction } from '@/configuration'; import { getEthersProvider, getEthersSigner } from '@/helpers/ethers'; import { ONE_MONTH_SECONDS } from '@/lib/constants/constants'; import { showToastError } from '@/lib/helpers'; @@ -36,6 +36,7 @@ interface IModifyStreamInnerModalProps extends IModifyStreamModalProps { flowRatePerMonth: bigint; streamFlowRatePerMonth: bigint; closeModal: () => void; + recurringNetworkId: number; } export const UpdateStreamInnerModal: FC = ({ @@ -47,20 +48,21 @@ export const UpdateStreamInnerModal: FC = ({ flowRatePerMonth, streamFlowRatePerMonth, closeModal, + recurringNetworkId, }) => { const [tx, setTx] = useState(''); const { formatMessage } = useIntl(); const tokenPrice = useTokenPrice(token); - const { address, chain } = useAccount(); + const { address } = useAccount(); const { refetchTokenStream } = useProfileDonateTabData(); const onDonate = async () => { setStep(EDonationSteps.DONATING); try { - await ensureCorrectNetwork(config.OPTIMISM_NETWORK_NUMBER); + await ensureCorrectNetwork(recurringNetworkId); const projectAnchorContract = findAnchorContractAddress( donation.project.anchorContracts, - chain?.id, + recurringNetworkId, ); if (!projectAnchorContract) { throw new Error('Project anchor address not found'); @@ -75,7 +77,7 @@ export const UpdateStreamInnerModal: FC = ({ throw new Error('Provider or signer not found'); const _options = { - chainId: config.OPTIMISM_CONFIG.id, + chainId: recurringNetworkId, provider: provider, resolverAddress: isProduction ? undefined @@ -105,7 +107,7 @@ export const UpdateStreamInnerModal: FC = ({ recurringDonationId: donation.id, projectId: +donation.project.id, anonymous: donation.anonymous, - chainId: config.OPTIMISM_NETWORK_NUMBER, + chainId: recurringNetworkId, flowRate: _flowRatePerSec, superToken: token, isForUpdate: true, @@ -119,7 +121,8 @@ export const UpdateStreamInnerModal: FC = ({ setTx(tx.hash); let projectDonationId = 0; - // saving project donation to backend + + // Saving project donation to backend try { const projectDonationInfo = { ...projectDraftDonationInfo, diff --git a/src/components/views/userProfile/donationsTab/recurringTab/RecurringDonationsTable.tsx b/src/components/views/userProfile/donationsTab/recurringTab/RecurringDonationsTable.tsx index 7cd82360f0..e012bf6ae8 100644 --- a/src/components/views/userProfile/donationsTab/recurringTab/RecurringDonationsTable.tsx +++ b/src/components/views/userProfile/donationsTab/recurringTab/RecurringDonationsTable.tsx @@ -157,6 +157,7 @@ const RecurringDonationTable: FC = ({ diff --git a/src/components/views/userProfile/donationsTab/recurringTab/StreamActionButton.tsx b/src/components/views/userProfile/donationsTab/recurringTab/StreamActionButton.tsx index 1c89345535..e8f3064235 100644 --- a/src/components/views/userProfile/donationsTab/recurringTab/StreamActionButton.tsx +++ b/src/components/views/userProfile/donationsTab/recurringTab/StreamActionButton.tsx @@ -18,17 +18,18 @@ import { } from '@/apollo/types/types'; import { EndStreamModal } from './EndStreamModal'; import { ArchiveStreamModal } from './ArchiveStreamModal'; -import config from '@/configuration'; import { slugToProjectDonate } from '@/lib/routeCreators'; interface IStreamActionButtonProps { donation: IWalletRecurringDonation; refetch: () => void; + recurringNetworkId: number; } export const StreamActionButton: FC = ({ donation, refetch, + recurringNetworkId, }) => { const [showModify, setShowModify] = useState(false); const [showEnd, setShowEnd] = useState(false); @@ -101,9 +102,9 @@ export const StreamActionButton: FC = ({ return options.length > 0 ? ( { - if (chainId !== config.OPTIMISM_NETWORK_NUMBER) { + if (recurringNetworkId !== chainId) { switchChain?.({ - chainId: config.OPTIMISM_NETWORK_NUMBER, + chainId: recurringNetworkId, }); } }} @@ -119,6 +120,7 @@ export const StreamActionButton: FC = ({ setShowModal={setShowModify} donation={donation} refetch={refetch} + recurringNetworkId={recurringNetworkId} /> )} {showEnd && ( @@ -126,6 +128,7 @@ export const StreamActionButton: FC = ({ setShowModal={setShowEnd} donation={donation} refetch={refetch} + recurringNetworkId={recurringNetworkId} /> )} {showArchive && ( diff --git a/src/components/views/userProfile/projectsTab/ClaimWithdrawalModal.tsx b/src/components/views/userProfile/projectsTab/ClaimWithdrawalModal.tsx index d8de2ce4eb..216ff64273 100644 --- a/src/components/views/userProfile/projectsTab/ClaimWithdrawalModal.tsx +++ b/src/components/views/userProfile/projectsTab/ClaimWithdrawalModal.tsx @@ -219,7 +219,7 @@ const ClaimWithdrawalModal = ({