diff --git a/public/coin.svg b/public/coin.svg new file mode 100644 index 00000000..29cb602e --- /dev/null +++ b/public/coin.svg @@ -0,0 +1,4 @@ + + + + diff --git a/public/migrate-erc20.svg b/public/migrate-erc20.svg new file mode 100644 index 00000000..11c4c385 --- /dev/null +++ b/public/migrate-erc20.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/modules/common/utils/textGenerator/index.tsx b/src/modules/common/utils/textGenerator/index.tsx index 6ddec8fd..f7acc5e1 100644 --- a/src/modules/common/utils/textGenerator/index.tsx +++ b/src/modules/common/utils/textGenerator/index.tsx @@ -23,6 +23,8 @@ export const titleGenerator = (path: string): JSX.Element => { return ; case PATH.ASSET_WBTC: return ; + case PATH.MIGRATE: + return ; default: break; diff --git a/src/modules/env/index.ts b/src/modules/env/index.ts index 76507536..9b7d813e 100644 --- a/src/modules/env/index.ts +++ b/src/modules/env/index.ts @@ -21,6 +21,7 @@ export enum PATH { ASSET_BTC = '/asset/btc', ASSET_WBTC = '/asset/wbtc', METANODE_EARNERS = '/metanode-earners', + MIGRATE = '/migrate', } export enum LOCAL_STORAGE { @@ -109,3 +110,5 @@ export const NETWORK_INFO_FETCH_RATE = 300 * 1000; // 5 minutes in milliseconds export enum ADDRESS_RESOLVER { UD = 'UD', } + +export const BRIDGE_ADDRESS = process.env.NEXT_PUBLIC_BRIDGE_ADDRESS; diff --git a/src/modules/hooks/useToggleBridge/index.tsx b/src/modules/hooks/useToggleBridge/index.tsx index 84652a57..870ec8b8 100644 --- a/src/modules/hooks/useToggleBridge/index.tsx +++ b/src/modules/hooks/useToggleBridge/index.tsx @@ -23,7 +23,7 @@ export const useToggleBridge = (path: PATH) => { // Memo: Redirect to btc_skypool bridge useEffect(() => { // Memo: Multiple-bridge as default path for Root and Explorer - if (path !== PATH.ROOT && path !== PATH.EXPLORER) { + if (path !== PATH.ROOT && path !== PATH.EXPLORER && path !== PATH.MIGRATE) { if (params.bridge === '' || !SKYBRIDGE_BRIDGES.includes(params.bridge as SkybridgeBridge)) { router.push({ pathname: path, diff --git a/src/modules/i18n/files/en.json b/src/modules/i18n/files/en.json index 6f378641..fbd7e988 100644 --- a/src/modules/i18n/files/en.json +++ b/src/modules/i18n/files/en.json @@ -265,5 +265,7 @@ "asset.bitcoin.1": "Bitcoin is a cryptocurrency invented in 2008 by an unknown person or group of people using the name Satoshi Nakamoto and started in 2009 when its implementation was released as open-source software.", "asset.bitcoin.2": "It is a decentralized digital currency without a central bank or single administrator that can be sent from user to user on the peer-to-peer bitcoin network without the need for intermediaries. Transactions are verified by network nodes through cryptography and recorded in a public distributed ledger called a blockchain. Bitcoins are created as a reward for a process known as mining. They can be exchanged for other currencies, products, and services. Research produced by the University of Cambridge estimates that in 2017, there were 2.9 to 5.8 million unique users using a cryptocurrency wallet, most of them using bitcoin.", "asset.wrapped-bitcoin.1": "Wrapped Bitcoin (WBTC) is an ERC-20 token that represents Bitcoin (BTC) on the Ethereum blockchain. A key advantage of WBTC is its integration into the world of Ethereum wallets, dapps, and smart contracts. Through a WBTC partner, 1 Bitcoin can be converted to 1 Wrapped Bitcoin, and vice-versa.", - "asset.wrapped-bitcoin.2": " " + "asset.wrapped-bitcoin.2": " ", + "migrate.title": "Migrate SWINGBY BEP20 to ERC20", + "migrate.description": "Please note that this manual bridging process can take up to 8 hours." } diff --git a/src/modules/i18n/files/ja.json b/src/modules/i18n/files/ja.json index 98158d67..da5729e1 100644 --- a/src/modules/i18n/files/ja.json +++ b/src/modules/i18n/files/ja.json @@ -150,5 +150,6 @@ "asset.bitcoin.1": "Bitcoin is a cryptocurrency invented in 2008 by an unknown person or group of people using the name Satoshi Nakamoto and started in 2009 when its implementation was released as open-source software.", "asset.bitcoin.2": "It is a decentralized digital currency without a central bank or single administrator that can be sent from user to user on the peer-to-peer bitcoin network without the need for intermediaries. Transactions are verified by network nodes through cryptography and recorded in a public distributed ledger called a blockchain. Bitcoins are created as a reward for a process known as mining. They can be exchanged for other currencies, products, and services. Research produced by the University of Cambridge estimates that in 2017, there were 2.9 to 5.8 million unique users using a cryptocurrency wallet, most of them using bitcoin.", "asset.wrapped-bitcoin.1": "Wrapped Bitcoin (WBTC) is an ERC-20 token that represents Bitcoin (BTC) on the Ethereum blockchain. A key advantage of WBTC is its integration into the world of Ethereum wallets, dapps, and smart contracts. Through a WBTC partner, 1 Bitcoin can be converted to 1 Wrapped Bitcoin, and vice-versa.", - "asset.wrapped-bitcoin.2": " " + "asset.wrapped-bitcoin.2": " ", + "migrate.title": "SWINGBY BEP20をERC20に移行します" } diff --git a/src/modules/i18n/files/zh-TW.json b/src/modules/i18n/files/zh-TW.json index 2002ad90..54ad0834 100644 --- a/src/modules/i18n/files/zh-TW.json +++ b/src/modules/i18n/files/zh-TW.json @@ -151,5 +151,6 @@ "asset.bitcoin.1": "Bitcoin is a cryptocurrency invented in 2008 by an unknown person or group of people using the name Satoshi Nakamoto and started in 2009 when its implementation was released as open-source software.", "asset.bitcoin.2": "It is a decentralized digital currency without a central bank or single administrator that can be sent from user to user on the peer-to-peer bitcoin network without the need for intermediaries. Transactions are verified by network nodes through cryptography and recorded in a public distributed ledger called a blockchain. Bitcoins are created as a reward for a process known as mining. They can be exchanged for other currencies, products, and services. Research produced by the University of Cambridge estimates that in 2017, there were 2.9 to 5.8 million unique users using a cryptocurrency wallet, most of them using bitcoin.", "asset.wrapped-bitcoin.1": "Wrapped Bitcoin (WBTC) is an ERC-20 token that represents Bitcoin (BTC) on the Ethereum blockchain. A key advantage of WBTC is its integration into the world of Ethereum wallets, dapps, and smart contracts. Through a WBTC partner, 1 Bitcoin can be converted to 1 Wrapped Bitcoin, and vice-versa.", - "asset.wrapped-bitcoin.2": " " + "asset.wrapped-bitcoin.2": " ", + "migrate.title": "遷移 SWINGBY BEP20 到 ERC20" } diff --git a/src/modules/i18n/files/zh.json b/src/modules/i18n/files/zh.json index bbeb2ebc..c379ed81 100644 --- a/src/modules/i18n/files/zh.json +++ b/src/modules/i18n/files/zh.json @@ -151,5 +151,6 @@ "asset.bitcoin.1": "Bitcoin is a cryptocurrency invented in 2008 by an unknown person or group of people using the name Satoshi Nakamoto and started in 2009 when its implementation was released as open-source software.", "asset.bitcoin.2": "It is a decentralized digital currency without a central bank or single administrator that can be sent from user to user on the peer-to-peer bitcoin network without the need for intermediaries. Transactions are verified by network nodes through cryptography and recorded in a public distributed ledger called a blockchain. Bitcoins are created as a reward for a process known as mining. They can be exchanged for other currencies, products, and services. Research produced by the University of Cambridge estimates that in 2017, there were 2.9 to 5.8 million unique users using a cryptocurrency wallet, most of them using bitcoin.", "asset.wrapped-bitcoin.1": "Wrapped Bitcoin (WBTC) is an ERC-20 token that represents Bitcoin (BTC) on the Ethereum blockchain. A key advantage of WBTC is its integration into the world of Ethereum wallets, dapps, and smart contracts. Through a WBTC partner, 1 Bitcoin can be converted to 1 Wrapped Bitcoin, and vice-versa.", - "asset.wrapped-bitcoin.2": " " + "asset.wrapped-bitcoin.2": " ", + "migrate.title": "迁移 SWINGBY BEP20 到 ERC20" } diff --git a/src/modules/links/index.tsx b/src/modules/links/index.tsx index e3976b51..c7bdcb05 100644 --- a/src/modules/links/index.tsx +++ b/src/modules/links/index.tsx @@ -24,6 +24,11 @@ export const URL = { BecomeLiquidityProvider: 'https://skybridge-docs.swingby.network/getting-start/becoming-a-liquidity-provider', Fees: 'https://skybridge-docs.swingby.network/getting-start/network-fees', + + MigrateBep20: 'https://bscscan.com/address/0x71de20e0c4616e7fcbfdd3f875d568492cbe4739', + MigrateErc20: 'https://etherscan.io/token/0x8287c7b963b405b7b8d467db9d79eec40625b13a', + MigrateIn: 'https://bscscan.com/address/0x640534D32D015e4C80318ad5256Ec7962fDB155f', + MigrateOut: 'https://etherscan.io/address/0x640534D32D015e4C80318ad5256Ec7962fDB155f', }; export const Links = [ diff --git a/src/modules/scenes/Common/ExplorerMain/index.tsx b/src/modules/scenes/Common/ExplorerMain/index.tsx index 253dd3eb..cbb8ce29 100644 --- a/src/modules/scenes/Common/ExplorerMain/index.tsx +++ b/src/modules/scenes/Common/ExplorerMain/index.tsx @@ -19,6 +19,7 @@ import { BrowserPool, BrowserLiquidity, BrowserSwap, + Migrate, } from '../../Main'; import { ExplorerMainContainer, HeadLine, TitleH1 } from './styled'; @@ -56,6 +57,8 @@ export const ExplorerMain = () => { return ; case PATH.ASSET_WBTC: return ; + case PATH.MIGRATE: + return ; default: ; @@ -84,6 +87,8 @@ export const ExplorerMain = () => { return <>; case PATH.ASSET_WBTC: return <>; + case PATH.MIGRATE: + return <>; default: return ; diff --git a/src/modules/scenes/Main/Migrate/Migrate/index.tsx b/src/modules/scenes/Main/Migrate/Migrate/index.tsx new file mode 100644 index 00000000..1690cc71 --- /dev/null +++ b/src/modules/scenes/Main/Migrate/Migrate/index.tsx @@ -0,0 +1,87 @@ +import { Icon } from '@swingby-protocol/pulsar'; +import Head from 'next/head'; +import Image from 'next/image'; +import { FormattedMessage } from 'react-intl'; +import useCopy from '@react-hook/copy'; + +import { ButtonScale } from '../../../Common'; +import { BRIDGE_ADDRESS } from '../../../../../modules/env'; +import { URL } from '../../../../../modules/links'; +import { copyToClipboard, toastCopyAddress } from '../../../../../components/Toast'; + +import { + MigrateContainer, + MigrateChainContainer, + MigrateChain, + MigrateChainAnchor, + MigrateDiv, + MigratePanelContainer, + MigratePanel, + MigrateAddressContainer, + MigrateAddress, + MigrateAddressText, + MigrateQrCode, + MigrateQrCodeDescription, + MigrateAddressAnchor, +} from './styled'; + +export const Migrate = () => { + const { copy } = useCopy(BRIDGE_ADDRESS); + + return ( + <> + + Swingby Skybridge | Migrate SWINGBY BEP20 to ERC20 + + + + + + + + + + + BEP20 + + + + + ERC20 + + + + + + + + + + + copyToClipboard(copy, toastCopyAddress)} + > + + + {BRIDGE_ADDRESS} + + + + + IN + + + + OUT + + + + + + + + + ); +}; diff --git a/src/modules/scenes/Main/Migrate/Migrate/styled.tsx b/src/modules/scenes/Main/Migrate/Migrate/styled.tsx new file mode 100644 index 00000000..44db1ea4 --- /dev/null +++ b/src/modules/scenes/Main/Migrate/Migrate/styled.tsx @@ -0,0 +1,152 @@ +import { Card } from '@swingby-protocol/pulsar'; +import { rem } from 'polished'; +import styled from 'styled-components'; +import QRCodeSVG from 'qrcode.react'; + +import { ButtonScale } from '../../../Common'; +import { StylingConstants } from '../../../../styles'; + +const { media } = StylingConstants; + +export const MigrateContainer = styled.div` + display: grid; + padding-top: ${({ theme }) => rem(theme.pulsar.size.drawer)}; + padding-bottom: ${({ theme }) => rem(theme.pulsar.size.room)}; + padding-left: ${({ theme }) => rem(theme.pulsar.size.closet)}; + padding-right: ${({ theme }) => rem(theme.pulsar.size.closet)}; + @media (min-width: ${rem(media.sm)}) { + padding-top: 0; + padding-left: 0; + padding-right: 0; + } + @media (min-width: ${rem(media.md)}) { + padding-bottom: ${({ theme }) => rem(theme.pulsar.size.state)}; + } +`; + +export const MigrateDiv = styled(Card)` + display: flex; + flex-direction: column; + align-items: center; + position: relative; + + @media (min-width: ${rem(media.sm)}) { + padding-top: ${({ theme }) => rem(theme.pulsar.size.city)}; + padding-bottom: ${({ theme }) => rem(theme.pulsar.size.city)}; + background-color: ${({ theme }) => (theme.pulsar.id === 'PulsarLight' ? '#FFF' : '#2A3039')}; + } + @media (min-width: ${rem(media.md)}) { + min-height: ${rem(500)}; + } + @media (min-width: ${rem(media.lg)}) { + width: ${rem(980)}; + margin: 0 auto; + } + @media (min-width: ${rem(media.xl)}) { + width: ${rem(1100)}; + } +`; + +export const MigratePanelContainer = styled.div` + width: 100%; + display: flex; + flex-direction: column; + gap: 10px; + margin-bottom: ${({ theme }) => rem(theme.pulsar.size.house)}; + + @media (min-width: ${rem(media.sm)}) { + width: ${rem(445)}; + } +`; + +export const MigratePanel = styled.div` + position: relative; + width: 100%; + border: 1px solid ${({ theme }) => theme.pulsar.color.border.normal}; + border-radius: ${({ theme }) => rem(theme.pulsar.size.closet)}; + background-color: ${({ theme }) => theme.pulsar.color.bg.masked}; + padding: ${({ theme }) => rem(theme.pulsar.size.street)}; + overflow: hidden; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + text-align: center; + gap: ${({ theme }) => rem(theme.pulsar.size.street)}; + color: ${({ theme }) => theme.pulsar.color.text.normal}; +`; + +export const MigrateChainContainer = styled.div` + width: ${rem(262)}; + display: flex; + align-items: center; + justify-content: space-between; + flex-wrap: wrap; + gap: ${({ theme }) => rem(theme.pulsar.size.room)}; + + > :first-child { + margin-left: ${rem(20)} !important; + margin-right: ${rem(20)} !important; + } +`; + +export const MigrateChain = styled(ButtonScale)` + width: ${rem(100)}; + text-decoration: underline; +`; + +export const MigrateChainAnchor = styled.a` + cursor: pointer; +`; + +export const MigrateQrCode = styled(QRCodeSVG)` + background-color: ${({ theme }) => (theme.pulsar.id === 'PulsarLight' ? '#FFF' : '#FFF')}; + padding: ${({ theme }) => rem(theme.pulsar.size.street)}; + border: 1px solid ${({ theme }) => theme.pulsar.color.border.normal}; + border-radius: ${({ theme }) => rem(theme.pulsar.size.closet)}; +`; + +export const MigrateQrCodeDescription = styled.div` + font-size: ${({ theme }) => rem(theme.pulsar.size.closet)}; +`; + +export const MigrateAddressContainer = styled.div` + width: 100%; + display: flex; + align-items: center; + justify-content: space-between; + flex-wrap: wrap; + gap: ${({ theme }) => rem(theme.pulsar.size.room)}; + + @media (max-width: ${rem(media.sm - 1)}) { + max-width: calc(100vw - 4.5rem); + } +`; + +export const MigrateAddress = styled.div` + width: 100%; + display: flex; + align-items: center; + gap: ${({ theme }) => rem(theme.pulsar.size.room)}; + + > :first-child { + flex-shrink: 0; + } +`; + +export const MigrateAddressText = styled.div` + flex: 1; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +`; + +export const MigrateAddressAnchor = styled.a` + display: flex; + align-items: center; + gap: ${({ theme }) => rem(theme.pulsar.size.room)}; + color: ${({ theme }) => theme.pulsar.color.text.normal}; + font-size: ${({ theme }) => rem(theme.pulsar.size.closet)}; + text-decoration: none; + cursor: pointer; +`; diff --git a/src/modules/scenes/Main/Migrate/index.ts b/src/modules/scenes/Main/Migrate/index.ts new file mode 100644 index 00000000..ff690f70 --- /dev/null +++ b/src/modules/scenes/Main/Migrate/index.ts @@ -0,0 +1 @@ +export { Migrate } from './Migrate'; diff --git a/src/modules/scenes/Main/index.tsx b/src/modules/scenes/Main/index.tsx index 92fc5145..466e309f 100644 --- a/src/modules/scenes/Main/index.tsx +++ b/src/modules/scenes/Main/index.tsx @@ -12,6 +12,7 @@ export { BrowserFees } from './Fees/'; export { BrowserAsset } from './Asset'; export { BrowserSwapRewards } from './SwapRewards'; export { MetanodeEarners } from './MetanodeEarners'; +export { Migrate } from './Migrate'; export const Main = () => { return ( diff --git a/src/pages/migrate.tsx b/src/pages/migrate.tsx new file mode 100644 index 00000000..d6fbc1e2 --- /dev/null +++ b/src/pages/migrate.tsx @@ -0,0 +1,50 @@ +import { GetServerSideProps } from 'next'; +import { useEffect, useState } from 'react'; +import { useDispatch } from 'react-redux'; + +import { Layout } from '../components/Layout'; +import { NoServiceToUSModal } from '../components/NoServiceToUSModal'; +import { fetchVwap, IFetchUsd } from '../modules/explorer'; +import { getIpInfoFromRequest } from '../modules/ip-info'; +import { Main } from '../modules/scenes'; +import { fetchUsdPrice } from '../modules/store'; + +type Props = { shouldBlockIp: boolean; initialPriceUSD: IFetchUsd }; + +export default function Migrate({ shouldBlockIp, initialPriceUSD }: Props) { + const dispatch = useDispatch(); + const [isNoServiceToUSModalOpen, setIsNoServiceToUSModalOpen] = useState(shouldBlockIp); + + useEffect(() => { + dispatch(fetchUsdPrice(initialPriceUSD)); + }, [dispatch, initialPriceUSD]); + + return ( + + +
+ + ); +} + +export const getServerSideProps: GetServerSideProps = async ({ req }) => { + const initialPriceUSD = await (async (): Promise => { + try { + const results = await Promise.all([fetchVwap('btcUsd'), fetchVwap('swingbyUsd')]); + + const priceUSD = { + BTC: results[0], + SWINGBY: results[1], + }; + + return priceUSD; + } catch (e) { + console.log(e); + } + })(); + + return { props: { ...(await getIpInfoFromRequest({ req })), initialPriceUSD } }; +};