diff --git a/apps/web/src/app/components/StellarSponsorshipModal/index.tsx b/apps/web/src/app/components/StellarSponsorshipModal/index.tsx new file mode 100644 index 000000000..2518624af --- /dev/null +++ b/apps/web/src/app/components/StellarSponsorshipModal/index.tsx @@ -0,0 +1,154 @@ +import React from 'react'; + +import { StellarXService, useXService } from '@balancednetwork/xwagmi'; +import { BASE_FEE, Networks, Operation, TransactionBuilder } from '@balancednetwork/xwagmi'; +import { Trans } from '@lingui/macro'; +import axios from 'axios'; +import { Flex } from 'rebass'; + +import { Typography } from '@/app/theme'; +import { AnimatePresence, motion } from 'framer-motion'; +import { TextButton } from '../Button'; +import { StyledButton } from '../Button/StyledButton'; +import { UnderlineText } from '../DropdownText'; +import Modal from '../Modal'; +import ModalContent from '../ModalContent'; +import Spinner from '../Spinner'; + +const SPONSOR_URL = 'https://ciihnqaqiomjdoicuy5rgwmy5m0vxanz.lambda-url.us-east-1.on.aws'; +const SPONSORING_ADDRESS = 'GCV5PJ4H57MZFRH5GM3E3CNFLWQURNFNIHQOYGRQ7JHGWJLAR2SFVZO6'; + +type StellarSponsorshipModalProps = { + address: string; + text: string; +}; + +const StellarSponsorshipModal = ({ text, address }: StellarSponsorshipModalProps) => { + const stellarXService = useXService('STELLAR') as unknown as StellarXService; + const [isLoading, setLoading] = React.useState(false); + const [isOpen, setOpen] = React.useState(false); + const [initiated, setInitiated] = React.useState(false); + const [success, setSuccess] = React.useState(false); + const handleDismiss = () => { + setOpen(false); + }; + + const handleToggle = () => { + setOpen(!isOpen); + }; + + const requestSponsorship = async () => { + if (!stellarXService) { + console.error('Stellar service not available'); + return; + } + try { + const client = axios.create({ + baseURL: SPONSOR_URL, + headers: { + 'Content-Type': 'application/json', + }, + }); + + //Sponsoring account + const sourceAccount = await stellarXService.server.loadAccount(SPONSORING_ADDRESS); + + //Create the transaction to sponsor the user account creation + const transaction = new TransactionBuilder(sourceAccount, { + fee: BASE_FEE, + networkPassphrase: Networks.PUBLIC, + }) + .addOperation( + Operation.beginSponsoringFutureReserves({ + source: SPONSORING_ADDRESS, + sponsoredId: address, + }), + ) + .addOperation( + Operation.createAccount({ + destination: address, + startingBalance: '0', + }), + ) + .addOperation( + Operation.endSponsoringFutureReserves({ + source: address, + }), + ) + .setTimeout(180) + .build(); + + const { signedTxXdr: signedTx } = await stellarXService.walletsKit.signTransaction(transaction.toXDR()); + + setLoading(true); + setInitiated(true); + const response = await client.post('/', { data: signedTx }); + + if (response.statusText === 'OK' && response.data) { + setSuccess(true); + setTimeout(() => { + handleDismiss(); + }, 2000); + } + } catch (error) { + console.error('Error fetching Stellar sponsor transaction:', error); + throw error; + } finally { + setLoading(false); + } + }; + + return ( + <> + + {text} + + + + + Activate Stellar wallet? + + + + Sign a transaction to activate your wallet for free. + + + + {initiated && ( + + + + )} + + + + {!success && ( + + + + {isLoading ? Close : Cancel} + + + {isLoading ? Activating : Activate wallet} + + + + )} + + + + + ); +}; + +export default StellarSponsorshipModal; diff --git a/apps/web/src/app/pages/trade/bridge/_components/BridgeTransferForm.tsx b/apps/web/src/app/pages/trade/bridge/_components/BridgeTransferForm.tsx index 5ed65dbcd..7bc337807 100644 --- a/apps/web/src/app/pages/trade/bridge/_components/BridgeTransferForm.tsx +++ b/apps/web/src/app/pages/trade/bridge/_components/BridgeTransferForm.tsx @@ -11,6 +11,7 @@ import { AutoColumn } from '@/app/components/Column'; import CurrencyInputPanel from '@/app/components/CurrencyInputPanel'; import { BrightPanel } from '@/app/components/Panel'; import { CurrencySelectionType, SelectorType } from '@/app/components/SearchModal/CurrencySearch'; +import StellarSponsorshipModal from '@/app/components/StellarSponsorshipModal'; import { handleConnectWallet } from '@/app/components/WalletModal/WalletItem'; import { Typography } from '@/app/theme'; import FlipIcon from '@/assets/icons/horizontal-flip.svg'; @@ -202,9 +203,9 @@ export default function BridgeTransferForm({ openModal }) { )} - {stellarValidation?.ok === false && stellarValidation.error && ( - - {stellarValidation.error} + {stellarValidation?.ok === false && stellarValidation.error && recipient && ( + + )} diff --git a/apps/web/src/app/pages/trade/xswap/_components/SwapPanel.tsx b/apps/web/src/app/pages/trade/xswap/_components/SwapPanel.tsx index 1962109a4..ac2601bc8 100644 --- a/apps/web/src/app/pages/trade/xswap/_components/SwapPanel.tsx +++ b/apps/web/src/app/pages/trade/xswap/_components/SwapPanel.tsx @@ -10,6 +10,7 @@ import { AutoColumn } from '@/app/components/Column'; import CurrencyInputPanel from '@/app/components/CurrencyInputPanel'; import { BrightPanel } from '@/app/components/Panel'; import { SelectorType } from '@/app/components/SearchModal/CurrencySearch'; +import StellarSponsorshipModal from '@/app/components/StellarSponsorshipModal'; import { Typography } from '@/app/theme'; import FlipIcon from '@/assets/icons/flip.svg'; import { PRICE_IMPACT_WARNING_THRESHOLD } from '@/constants/misc'; @@ -240,9 +241,9 @@ export default function SwapPanel() { /> - {stellarValidation?.ok === false && stellarValidation.error && ( - - {stellarValidation.error} + {stellarValidation?.ok === false && stellarValidation.error && recipient && ( + + )} diff --git a/packages/xwagmi/src/index.ts b/packages/xwagmi/src/index.ts index 39e0cc76a..39371bf8c 100644 --- a/packages/xwagmi/src/index.ts +++ b/packages/xwagmi/src/index.ts @@ -23,3 +23,5 @@ export type * from './xcall/types'; export { useAccount, useSwitchChain } from 'wagmi'; export { useSignTransaction, useCurrentAccount, useCurrentWallet, useSuiClient } from '@mysten/dapp-kit'; + +export { BASE_FEE, Networks, Operation, TransactionBuilder } from '@stellar/stellar-sdk'; diff --git a/packages/xwagmi/src/xchains/stellar/utils.ts b/packages/xwagmi/src/xchains/stellar/utils.ts index 353479677..365086102 100644 --- a/packages/xwagmi/src/xchains/stellar/utils.ts +++ b/packages/xwagmi/src/xchains/stellar/utils.ts @@ -123,7 +123,7 @@ export function useValidateStellarAccount(address?: string | null): UseQueryResu await stellarService.server.loadAccount(address); return { ok: true }; } catch (e) { - return { ok: false, error: `Stellar wallet inactive. Add at least 1 XLM from an external source.` }; + return { ok: false, error: `Stellar wallet inactive. Add at least 1 XLM from an external source` }; } }, });