diff --git a/apps/frontend/package.json b/apps/frontend/package.json index 0478ecf66..9b9467811 100644 --- a/apps/frontend/package.json +++ b/apps/frontend/package.json @@ -6,6 +6,8 @@ "dependencies": { "@apollo/client": "3.7.1", "@apollo/react-hooks": "4.0.0", + "@gobob/bob-sdk": "^3.1.7-alpha0", + "@gobob/sats-wagmi": "^0.3.21-alpha1", "@loadable/component": "5.15.2", "@sovryn-zero/lib-base": "0.2.1", "@sovryn-zero/lib-ethers": "0.2.5", @@ -26,6 +28,7 @@ "@sovryn/tailwindcss-config": "*", "@sovryn/ui": "*", "@sovryn/utils": "0.0.2", + "@tanstack/react-query": "^5.59.0", "@uniswap/permit2-sdk": "1.2.0", "bitcoin-address-validation": "2.2.1", "chart.js": "4.1.1", diff --git a/apps/frontend/src/app/3_organisms/Header/Header.constants.tsx b/apps/frontend/src/app/3_organisms/Header/Header.constants.tsx index 78e8630e3..b30f3ff8c 100644 --- a/apps/frontend/src/app/3_organisms/Header/Header.constants.tsx +++ b/apps/frontend/src/app/3_organisms/Header/Header.constants.tsx @@ -69,4 +69,8 @@ export const menuItemsMapping: MenuItem[] = [ text: t(translations.header.nav.bitocracy), url: '/bitocracy', }, + { + text: t(translations.header.nav.bobGateway), + url: '/bob-gateway', + }, ]; diff --git a/apps/frontend/src/app/5_pages/BobGateway/BobGateway.constants.tsx b/apps/frontend/src/app/5_pages/BobGateway/BobGateway.constants.tsx new file mode 100644 index 000000000..d03184fd0 --- /dev/null +++ b/apps/frontend/src/app/5_pages/BobGateway/BobGateway.constants.tsx @@ -0,0 +1,64 @@ +import { GatewaySDK } from '@gobob/bob-sdk'; +import { QueryClient } from '@tanstack/react-query'; + +import React from 'react'; + +export const bobGateway = new GatewaySDK('bob'); + +export const strategies = [ + { + strategyAddress: '0x0A0A0F6d572488093763C13AF7aB55597477aBDB', + toToken: 'wBTC', + tokenA: 'UniBTC', + tokenB: 'SolvBTC.BBN', + category: 'Liquidity providing', + incentives: ( +
+ 20x/20x Spice + + Supply APR + + SolvXP + + Babylon Points + + Diamond +
+ ), + about: + 'Maximize your rewards with liquid Bitcoin staking. This pool facilitates seamless swaps between SolvBTC.BBN and UniBTC, two Liquid Staking Tokens (LSTs) representing BTC. With a 20x Spice multiplier, it offers high incentives for liquidity providers looking to optimize yield while staying fully exposed to BTC derivatives.', + }, + + { + strategyAddress: '0x2a4F027cb568F2F3f7b2F7008b92C3B0eFc8DCfD', + toToken: 'wBTC', + tokenA: 'WBTC', + tokenB: 'SolvBTC.BBN', + category: 'Liquidity providing', + incentives: ( +
+ 7x/20x Spice + + Supply APR + + SolvXP + + Babylon Points +
+ ), + about: + 'Combine wrapped BTC liquidity with staking rewards. This pool pairs wBTC with SolvBTC.BBN, allowing users to move between a widely-used BTC wrapper and an interest-bearing LST. Liquidity providers earn a 7x Spice multiplier on wBTC and a 20x multiplier on SolvBTC.BBN, making it an attractive option for BTC holders looking to gain exposure to liquid staking rewards.', + }, + + { + strategyAddress: '0x9509e42a304b408A17403a0a439692DBe8b68F6c', + toToken: 'wBTC', + tokenA: 'WBTC', + tokenB: 'UniBTC', + category: 'Liquidity providing', + incentives: ( +
+ 7x/20x Spice + + Supply APR + + Diamond +
+ ), + about: + 'Combine wrapped BTC liquidity with staking rewards. This pool pairs wBTC with UniBTC, allowing users to move between a widely-used BTC wrapper and an interest-bearing LST. Liquidity providers earn a 7x Spice multiplier on wBTC and a 20x multiplier on UniBTC, making it an attractive option for BTC holders looking to gain exposure to liquid staking rewards.', + }, +]; + +export const queryClient = new QueryClient(); diff --git a/apps/frontend/src/app/5_pages/BobGateway/BobGateway.tsx b/apps/frontend/src/app/5_pages/BobGateway/BobGateway.tsx new file mode 100644 index 000000000..d93adf664 --- /dev/null +++ b/apps/frontend/src/app/5_pages/BobGateway/BobGateway.tsx @@ -0,0 +1,45 @@ +import { Network, SatsWagmiConfig } from '@gobob/sats-wagmi'; +import { QueryClientProvider } from '@tanstack/react-query'; + +import React, { FC } from 'react'; + +import { t } from 'i18next'; +import { Helmet } from 'react-helmet-async'; + +import { Heading, Paragraph, ParagraphSize } from '@sovryn/ui'; + +import { translations } from '../../../locales/i18n'; +import { queryClient } from './BobGateway.constants'; +import { BobGatewayForm } from './components/BobGatewayForm/BobGatewayForm'; +import { BobGatewayOrders } from './components/BobGatewayOrders/BobGatewayOrders'; + +const BobGateway: FC = () => ( + <> + + {t(translations.bobGatewayPage.meta.title)} + + +
+ + {t(translations.bobGatewayPage.meta.title)} + + + + {t(translations.bobGatewayPage.description)} + + + + +
+ + +
+
+
+
+ +); +export default BobGateway; diff --git a/apps/frontend/src/app/5_pages/BobGateway/components/BitcoinWallet/BitcoinWallet.tsx b/apps/frontend/src/app/5_pages/BobGateway/components/BitcoinWallet/BitcoinWallet.tsx new file mode 100644 index 000000000..9f025aabf --- /dev/null +++ b/apps/frontend/src/app/5_pages/BobGateway/components/BitcoinWallet/BitcoinWallet.tsx @@ -0,0 +1,111 @@ +import { useAccount, useConnect, useDisconnect } from '@gobob/sats-wagmi'; + +import React, { FC, useCallback, useEffect } from 'react'; + +import { t } from 'i18next'; +import { nanoid } from 'nanoid'; + +import { + Button, + ButtonSize, + ButtonStyle, + Dialog, + DialogBody, + DialogHeader, + NotificationType, + WalletIdentity, +} from '@sovryn/ui'; + +import { useNotificationContext } from '../../../../../contexts/NotificationContext'; +import { translations } from '../../../../../locales/i18n'; +import { getBitcoinWalletIcon } from './BitcoinWallet.utils'; + +type BitcoinWalletProps = { + isOpen: boolean; + setIsOpen: (isOpen: boolean) => void; +}; + +export const BitcoinWallet: FC = ({ + isOpen, + setIsOpen, +}) => { + const { addNotification } = useNotificationContext(); + const { connectors, connect } = useConnect(); + const { address: btcAddress } = useAccount(); + const { disconnect } = useDisconnect(); + + const onCopyAddress = useCallback(() => { + addNotification({ + type: NotificationType.success, + title: t(translations.copyAddress), + content: '', + dismissible: true, + id: nanoid(), + }); + }, [addNotification]); + + useEffect(() => { + if (btcAddress && isOpen) { + setIsOpen(false); + } + }, [btcAddress, isOpen, setIsOpen]); + + if (!btcAddress) { + return ( + <> +