diff --git a/lang/ca.json b/lang/ca.json index cd977c7edb..b798215e6a 100644 --- a/lang/ca.json +++ b/lang/ca.json @@ -181,6 +181,7 @@ "label.archived_rounds": "Rondes arxivades", "label.archive_donation": "Arxivar donació", "label.archive_stream": "Arxiva el Stream", + "label.archive_switch": "Mostrar Donacions Arxivades", "label.are_eligible_to_be_matched": "són elegibles per ser aparellats.", "label.are_you_sure": "Estàs segur?", "label.ask_us_a_question": "Fes-nos una pregunta", @@ -386,8 +387,8 @@ "label.email": "correu electrònic", "label.email_address": "Adreça electrònica", "label.email_verified": "Correu electrònic verificat", - "label.email_verify": "Verifica el correu electrònic", - "label.email_already_verified": "El teu correu electrònic ha estat verificat. Ara pots desar la informació del teu perfil.", + "label.email_verify": "Verifica el correu electrònic", + "label.email_already_verified": "El teu correu electrònic ha estat verificat. Ara pots desar la informació del teu perfil.", "label.email_used": "Aquesta adreça de correu electrònic s'utilitzarà per enviar-te comunicacions importants.", "label.email_used_another": "Aquest correu electrònic ja ha estat verificat en un altre perfil!", "label.email_sent_to": "Codi de verificació enviat a {email}", @@ -864,7 +865,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 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!", @@ -1297,6 +1298,7 @@ "label.your_project_is_now_submitted": "El teu projecte ha estat enviat, el nostre equip revisarà la teva sol·licitud.", "label.your_project_is_now_verified_so_the_donors_may_have_givbacks": "El teu projecte ara és elegible per a GIVbacks, per la qual cosa els donants poden rebre GIVbacks per les seves donacions al teu projecte.", "label.your_project_is_set_up_to_receive_recurring_donations": "Aquest projecte ja està configurat per rebre donacions recurrents.", + "label.this_project_is_now_set_up_publish_and_finalize_it": "Aquest projecte ara està configurat per rebre donacions recurrents a {network}. Publica el projecte per finalitzar la integració. ", "label.your_project_is_verified_now": "El teu projecte ara és elegible per a GIVbacks", "label.your_stream_balance": "El teu Saldo de Transmissió de", "label.your_tokens_will_be_locked_for_the_remainder": "Els teus tokens estaran bloquejats pel que queda de la ronda actual +", diff --git a/lang/en.json b/lang/en.json index 2349d08785..5a0d395709 100644 --- a/lang/en.json +++ b/lang/en.json @@ -181,6 +181,7 @@ "label.archived_rounds": "Archived Rounds", "label.archive_donation": "Archive donation", "label.archive_stream": "Archive Stream", + "label.archive_switch": "Show Archived Donations", "label.are_eligible_to_be_matched": "are eligible to be matched.", "label.are_you_sure": "Are you sure?", "label.ask_us_a_question": "Ask us a Question", @@ -612,6 +613,7 @@ "label.learn_more": "Learn more", "label.learn_more_about": "Learn more about the benefits.", "label.learn_more_about_donating_on_giveth": "Learn more about donating on Giveth", + "label.this_project_is_now_set_up_publish_and_finalize_it": "This project is now set up to receive recurring donations on {network}. Publish the project to finalize the integration. ", "label.learn_more_about_giv": "Learn more about GIV", "label.learn_more_recurring_donations": "Learn more about recurring donations on Giveth", "label.learn_the_basics": "Learn the basics", @@ -864,7 +866,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 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 4be6f4ee4b..004713cc82 100644 --- a/lang/es.json +++ b/lang/es.json @@ -179,6 +179,7 @@ "label.archived_rounds": "Rondas Archivadas", "label.archive_donation": "Archivar donación", "label.archive_stream": "Archivar Transmisión", + "label.archive_switch": "Mostrar Donaciones Archivadas", "label.are_eligible_to_be_matched": "son elegibles para ser complementadas.", "label.are_you_sure": "¿Estás seguro?", "label.ask_us_a_question": "Haznos una pregunta", @@ -384,8 +385,8 @@ "label.email": "Email", "label.email_address": "Dirección de Email", "label.email_verified": "Correo electrónico verificado", - "label.email_verify": "Verificar correo electrónico", - "label.email_already_verified": "Tu correo electrónico ha sido verificado. Ahora puedes guardar la información de tu perfil.", + "label.email_verify": "Verificar correo electrónico", + "label.email_already_verified": "Tu correo electrónico ha sido verificado. Ahora puedes guardar la información de tu perfil.", "label.email_used": "Esta dirección de correo electrónico se utilizará para enviarte comunicaciones importantes.", "label.email_used_another": "¡Este correo electrónico ya ha sido verificado en otro perfil!", "label.email_sent_to": "Código de verificación enviado a {email}", @@ -864,7 +865,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 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!", @@ -1297,6 +1298,7 @@ "label.your_project_is_now_submitted": "Tu proyecto ha sido enviado, nuestro equipo revisará tu solicitud.", "label.your_project_is_now_verified_so_the_donors_may_have_givbacks": "Tu proyecto ahora es elegible para GIVbacks, por lo que los donantes pueden recibir GIVbacks por sus donaciones a tu proyecto.", "label.your_project_is_set_up_to_receive_recurring_donations": "Este proyecto ya está configurado para recibir donaciones recurrentes.", + "label.this_project_is_now_set_up_publish_and_finalize_it": "Este proyecto ahora está configurado para recibir donaciones recurrentes en {network}. Publica el proyecto para finalizar la integración. ", "label.your_project_is_verified_now": "Tu proyecto ahora es elegible para GIVbacks", "label.your_stream_balance": "Tu Saldo de Transmisión de ", "label.your_tokens_will_be_locked_for_the_remainder": "Tus tokens estarán bloqueados por el restante de la ronda actual +", diff --git a/package.json b/package.json index 8d6eeda1f3..a97a93c7cf 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "givethdapp", - "version": "2.34.0", + "version": "2.35.0", "private": true, "scripts": { "build": "next build", 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} +
)}
); diff --git a/public/images/tokens/USDCx.svg b/public/images/tokens/USDCx.svg new file mode 100644 index 0000000000..f0409e0259 --- /dev/null +++ b/public/images/tokens/USDCx.svg @@ -0,0 +1,28 @@ + + + + + + diff --git a/src/apollo/gql/gqlProjects.ts b/src/apollo/gql/gqlProjects.ts index 6546c7d2c0..edcf834f83 100644 --- a/src/apollo/gql/gqlProjects.ts +++ b/src/apollo/gql/gqlProjects.ts @@ -55,6 +55,7 @@ export const PROJECT_CARD_FIELDS = gql` anchorContracts { address isActive + networkId } } `; @@ -196,6 +197,7 @@ export const FETCH_PROJECT_BY_SLUG_DONATION = gql` anchorContracts { address isActive + networkId } } } @@ -294,6 +296,7 @@ export const FETCH_PROJECT_BY_SLUG_SINGLE_PROJECT = gql` anchorContracts { address isActive + networkId } } } @@ -332,6 +335,7 @@ export const FETCH_PROJECT_BY_ID = gql` anchorContracts { address isActive + networkId } } } diff --git a/src/apollo/gql/gqlSuperfluid.ts b/src/apollo/gql/gqlSuperfluid.ts index 864833e4b9..3021fb4ed9 100644 --- a/src/apollo/gql/gqlSuperfluid.ts +++ b/src/apollo/gql/gqlSuperfluid.ts @@ -55,12 +55,14 @@ export const CREATE_ANCHOR_CONTRACT_ADDRESS_QUERY = gql` $projectId: Int! $networkId: Int! $address: String! + $recipientAddress: String $txHash: String! ) { addAnchorContractAddress( projectId: $projectId networkId: $networkId address: $address + recipientAddress: $recipientAddress txHash: $txHash ) { id diff --git a/src/apollo/gql/gqlUser.ts b/src/apollo/gql/gqlUser.ts index 975eb9da1b..ea5210f53a 100644 --- a/src/apollo/gql/gqlUser.ts +++ b/src/apollo/gql/gqlUser.ts @@ -125,6 +125,7 @@ export const FETCH_USER_RECURRING_DONATIONS = gql` $userId: Int! $filteredTokens: [String!] $includeArchived: Boolean + $networkId: Int ) { recurringDonationsByUserId( take: $take @@ -135,6 +136,7 @@ export const FETCH_USER_RECURRING_DONATIONS = gql` finishStatus: $finishStatus filteredTokens: $filteredTokens includeArchived: $includeArchived + networkId: $networkId ) { recurringDonations { id @@ -154,6 +156,7 @@ export const FETCH_USER_RECURRING_DONATIONS = gql` anchorContracts { address isActive + networkId } } finished diff --git a/src/apollo/types/types.ts b/src/apollo/types/types.ts index 5187903452..3524bbfbd7 100644 --- a/src/apollo/types/types.ts +++ b/src/apollo/types/types.ts @@ -32,6 +32,14 @@ export interface IEstimatedMatching { export interface IAnchorContractData { address: Address; isActive: boolean; + networkId: number; +} + +export interface IAnchorContractBasicData { + contractAddress?: Address; + recipientAddress: Address; + hash?: string; + enabled?: boolean; } export interface IProject { diff --git a/src/components/views/create/AddressInterface.tsx b/src/components/views/create/AddressInterface.tsx index c6a2e251fc..a78be92d33 100644 --- a/src/components/views/create/AddressInterface.tsx +++ b/src/components/views/create/AddressInterface.tsx @@ -1,5 +1,7 @@ +import { useState } from 'react'; import { useFormContext } from 'react-hook-form'; import { useIntl } from 'react-intl'; +import { useAccount, useSwitchChain } from 'wagmi'; import styled, { css } from 'styled-components'; import { B, @@ -23,13 +25,20 @@ import { getChainName } from '@/lib/network'; import { IChainType } from '@/types/config'; import { findAddressByChain } from '@/lib/helpers'; import { useGeneralWallet } from '@/providers/generalWalletProvider'; -import { IAnchorContractData } from '@/apollo/types/types'; +import { + IAnchorContractBasicData, + IAnchorContractData, + IProject, +} from '@/apollo/types/types'; import { IconWithTooltip } from '@/components/IconWithToolTip'; import { EInputs } from './types'; import links from '@/lib/constants/links'; +import { saveAnchorContract } from './AlloProtocol/AlloProtocolModal'; +import { useAppSelector } from '@/features/hooks'; interface IAddressInterfaceProps extends IChainType { networkId: number; + project?: IProject; onButtonClick?: () => void; anchorContractData?: IAnchorContractData; isEditMode?: boolean; @@ -41,32 +50,62 @@ interface IconContainerProps { const AddressInterface = ({ networkId, + project, onButtonClick, chainType, anchorContractData, isEditMode, }: IAddressInterfaceProps) => { + const { chain } = useAccount(); + const { userData } = useAppSelector(state => state.user); + const { switchChain } = useSwitchChain(); const { setValue, watch } = useFormContext(); const { formatMessage } = useIntl(); const { isOnEVM } = useGeneralWallet(); - const inputName = EInputs.addresses; - const alloProtocolRegistry = watch(EInputs.alloProtocolRegistry) as boolean; + const DO_RECURRING_SETUP_ON_ENABLE = true; + + const [hasAnchorContract, setHasAnchorContract] = useState( + anchorContractData?.isActive || false, + ); + const isOnOptimism = chain + ? chain.id === config.OPTIMISM_NETWORK_NUMBER + : false; + const isOnBase = chain ? chain.id === config.BASE_NETWORK_NUMBER : false; + + const inputName = EInputs.addresses; const value = watch(inputName); const isOptimism = networkId === config.OPTIMISM_NETWORK_NUMBER; + const isBase = networkId === config.BASE_NETWORK_NUMBER; + + const alloContract = isBase + ? EInputs.baseAnchorContract + : EInputs.opAnchorContract; + const alloProtocolRegistry = watch( + alloContract, + ) as IAnchorContractBasicData; const addressObj = findAddressByChain(value, networkId, chainType); const walletAddress = addressObj?.address; const hasAddress = !!walletAddress; - const hasAnchorContract = !!anchorContractData?.isActive; + const hasOptimismAddress = !!findAddressByChain( value, config.OPTIMISM_NETWORK_NUMBER, chainType, ); + const hasBaseAddress = !!findAddressByChain( + value, + config.BASE_NETWORK_NUMBER, + chainType, + ); + const isRecurringOnOptimismReady = isOptimism && hasOptimismAddress; + const isRecurringOnBaseReady = isBase && hasBaseAddress; + const isRecurringDonationsReady = + isRecurringOnBaseReady || isRecurringOnOptimismReady; return ( @@ -117,7 +156,7 @@ const AddressInterface = ({ {hasAddress ? walletAddress : 'No address added yet!'} {hasAddress && - (hasAnchorContract && isOptimism ? ( + (hasAnchorContract && (isOptimism || isBase) ? ( ))} - {isOptimism && isOnEVM && ( - // Render this section only on Optimism + {(isOptimism || isBase) && isOnEVM && ( + // Render this section only on Optimism and Base - +
{hasAnchorContract && isEditMode @@ -173,9 +207,20 @@ const AddressInterface = ({ ? formatMessage({ id: 'label.your_project_is_set_up_to_receive_recurring_donations', }) - : formatMessage({ - id: 'label.do_you_want_this_project_to_be_setup_to_receive_recurring_donations', - })} + : hasAnchorContract + ? formatMessage( + { + id: 'label.this_project_is_now_set_up_publish_and_finalize_it', + }, + { + network: isOptimism + ? 'Optimism' + : 'Base', + }, + ) + : formatMessage({ + id: 'label.do_you_want_this_project_to_be_setup_to_receive_recurring_donations', + })}
- {hasAnchorContract && isEditMode ? ( + {hasAnchorContract ? ( + ) : DO_RECURRING_SETUP_ON_ENABLE ? ( + +