Skip to content

Commit

Permalink
feat(ethPNT): add support to ethPNT in swaps
Browse files Browse the repository at this point in the history
  • Loading branch information
envin3 committed Jan 29, 2024
1 parent 74a5aa8 commit 6d2530f
Show file tree
Hide file tree
Showing 12 changed files with 227 additions and 51 deletions.
43 changes: 37 additions & 6 deletions src/components/organisms/assetInfo/AssetInfo.jsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,36 @@
import React, { useState, useEffect, useCallback } from 'react'
import styled from 'styled-components'
import PropTypes from 'prop-types'
import React, { useState, useEffect, useCallback } from 'react'
import { Row, Col } from 'react-bootstrap'
import ReactTooltip from 'react-tooltip'
import Icon from '../../atoms/icon/Icon'
import { copyToClipboard } from '../../../utils/utils'
import { registerToken } from '../../../utils/wallet'
import { getBase64Image } from '../../../utils/image'
import styled from 'styled-components'

import { ETHPNT_ON_ETH_MAINNET } from '../../../constants'
import { useProvider } from '../../../hooks/use-provider'
import { capitalizeAllLettersExceptFirst } from '../../../utils/capitalize'
import { getBase64Image } from '../../../utils/image'
import { copyToClipboard } from '../../../utils/utils'
import { registerToken } from '../../../utils/wallet'
import Icon from '../../atoms/icon/Icon'

const InfoEta = styled.div`
margin-top: 30px;
padding: 20px;
margin-bottom: 10px;
background: #66b8ff40;
border: 0.5px solid ${({ theme }) => theme.blue};
border-radius: 10px;
color: ${({ theme }) => theme.blue};
text-align: center;
`

const InflationInfo = styled(InfoEta)`
width: 100%;
margin-top: 10px;
margin-bottom: 0px;
margin-right: 10px;
margin-left: 10px;
padding: 5px;
`

const ContainerAssetInfo = styled(Col)`
margin-top: 10px;
Expand Down Expand Up @@ -120,6 +142,15 @@ const AssetInfo = ({ asset, wallet }) => {
</Token>
</ContainerOptions>
</Row>
{asset.id === ETHPNT_ON_ETH_MAINNET ? (
<Row>
<InflationInfo>
ethPNT is an extension of the PNT token with cross-chain functionality, maintaining the same token economy
and functionalities as PNT-on-Ethereum. ethPNT grants the same DAO governance power of PNT, inheriting its
full value.
</InflationInfo>
</Row>
) : null}
<ReactTooltip
getContent={(_dataTip) =>
_dataTip === 'Add to MetaMask' || _dataTip === 'Connect MetaMask to add the token'
Expand Down
13 changes: 10 additions & 3 deletions src/components/organisms/assetListModal/AssetListModal.jsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
import PropTypes from 'prop-types'
import React, { useState, useCallback, useEffect, useMemo, useRef } from 'react'
import { Col, Row, Spinner } from 'react-bootstrap'
import PropTypes from 'prop-types'
import styled from 'styled-components'

import {
useAssetsWithouDefault,
useSearchAssets,
useAssetsGroupedByGivenStrategy,
useSortPntInflationToken,
} from '../../../hooks/use-assets'
import { getAssetFromSymbol } from '../../../utils/maps'
import { useAssetsWithouDefault, useSearchAssets, useAssetsGroupedByGivenStrategy } from '../../../hooks/use-assets'
import Icon from '../../atoms/icon/Icon'
import Modal from '../../molecules/modal/Modal'

Expand Down Expand Up @@ -166,7 +172,8 @@ const StyledSpinner = styled(Spinner)`
const AssetListModal = ({ show: showModal, title, onClose, onSelect, assets: _assets, defaultAssets }) => {
const [assetsWithoutDefault] = useAssetsWithouDefault(_assets)
const [filteredAssets, setSearchWord] = useSearchAssets(assetsWithoutDefault)
const [assets] = useAssetsGroupedByGivenStrategy(filteredAssets)
const [groupedAssets] = useAssetsGroupedByGivenStrategy(filteredAssets)
const assets = useSortPntInflationToken(groupedAssets)
const [show, setShow] = useState([])
const inputSearchRef = useRef(null)

Expand Down
61 changes: 55 additions & 6 deletions src/components/organisms/swapLine/SwapLine.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,27 @@ import PropTypes from 'prop-types'
import React, { useState, useEffect, useMemo } from 'react'
import { Row, Col } from 'react-bootstrap'
import Skeleton from 'react-loading-skeleton'
import 'react-loading-skeleton/dist/skeleton.css'
import { NumericFormat } from 'react-number-format'
import styled from 'styled-components'

import { ETHPNT_ON_ETH_MAINNET, PNT_ON_ETH_MAINNET } from '../../../constants'
import { getDecimalSeparator, getThousandSeparator } from '../../../utils/amount-utils'
import { capitalizeAllLettersExceptFirst } from '../../../utils/capitalize'
import Icon from '../../atoms/icon/Icon'
import Switch from '../../atoms/switch/Switch'
import AssetInfo from '../assetInfo/AssetInfo'

import 'react-loading-skeleton/dist/skeleton.css'
const SelectCol = styled(Col)`
text-align: center;
font-weight: 500;
padding-top: 10px;
margin-left: 6px;
color: ${({ theme }) => theme.text1};
@media (max-width: 767.98px) {
font-size: 12px;
}
`

const SwapLineContainer = styled.div`
border-radius: 20px;
Expand Down Expand Up @@ -198,6 +210,7 @@ const Arrow = styled(Icon)`

const SwapLine = ({
asset,
assets,
amount,
address,
defaultImage,
Expand All @@ -211,22 +224,50 @@ const SwapLine = ({
onMax,
withTitleLabel,
disableInput,
selectFrom = () => null,
selectTo = () => null,
migration = false,
inputType = 'number',
inputPlaceholder = '0',
prefix = '',
..._props
}) => {
const [showInfo, setShowInfo] = useState(false)
const [id, setId] = useState(false)
const [selectEthPNT, setSelectEthPNT] = useState(false)

// NOTE: avoid to close show info when asset is reloaded with the balance
useEffect(() => {
if (asset && asset.id !== id) {
if (asset && asset.id !== id && asset.id !== ETHPNT_ON_ETH_MAINNET) {
setShowInfo(false)
setId(asset.id)
}
}, [asset, id])

useEffect(() => {
if (asset && asset.id === ETHPNT_ON_ETH_MAINNET) {
setSelectEthPNT(true)
setShowInfo(true)
} else setSelectEthPNT(false)
}, [asset, id])

// This switch provides the ability to use ethPNT or PNT alternatively.
// When pressed the selected asset switch between ethPNt or PNT.
const switchPNT = () => {
if (migration) return
if (asset.id === ETHPNT_ON_ETH_MAINNET) {
const pnt = assets.find((asset) => asset.id === PNT_ON_ETH_MAINNET)
if (!address && address !== '') selectFrom(pnt)
} else {
const ethPnt = assets.find((asset) => asset.id === ETHPNT_ON_ETH_MAINNET)
if (!address && address !== '') selectFrom(ethPnt)
}
}

const isPNTcase = asset?.id === PNT_ON_ETH_MAINNET || asset?.id === ETHPNT_ON_ETH_MAINNET

const showPntSwitch = asset && isPNTcase && !migration && !address && address !== ''

const formattedTitle = useMemo(() => {
if (!withTitleLabel || !asset || !asset.titleLabel) return title

Expand All @@ -237,7 +278,7 @@ const SwapLine = ({
<SwapLineContainer {..._props}>
<ContainerTypeAndBalance>
<ContainerTitle xs={6}>{formattedTitle}</ContainerTitle>
{asset && asset.formattedBalance !== '-' ? (
{asset && asset.formattedBalance && asset.formattedBalance !== '-' ? (
<Col xs={6} className="text-right my-auto">
<ContainerBalance>
<BalanceLabel>{`Balance: ${asset.formattedBalance} ${
Expand All @@ -254,12 +295,15 @@ const SwapLine = ({
<Row>
<ContainerImageAndMaxButton xs={4} className="my-auto">
<ContainerImage onClick={() => onClickImage && onClickImage()}>
<Image src={asset ? asset.image : defaultImage} onClick={() => onClickImage && onClickImage()} />
<Image
src={asset ? (isPNTcase ? './assets/svg/PNT.svg' : asset.image) : defaultImage}
onClick={() => onClickImage && onClickImage()}
/>
{(asset && asset.withMiniImage) || (!asset && defaultMiniImage) ? (
<MiniImage src={!asset ? defaultMiniImage : asset.miniImage} />
<MiniImage src={asset ? (isPNTcase ? './assets/svg/ETH.svg' : asset.miniImage) : defaultMiniImage} />
) : null}
</ContainerImage>{' '}
{asset && asset.formattedBalance !== '-' && !hideMaxButton ? (
{asset && asset.formattedBalance && asset.formattedBalance !== '-' && !hideMaxButton ? (
<ContainerMaxButton>
<MaxButton onClick={onMax}>MAX</MaxButton>
</ContainerMaxButton>
Expand Down Expand Up @@ -287,6 +331,11 @@ const SwapLine = ({
</Col>
</Row>
<Row>
{showPntSwitch ? (
<SelectCol data-tip={'Use ethPNT'} data-for="tooltip-gasless" xs={2}>
<Switch height={15} width={30} checked={selectEthPNT} disabled={false} onChange={switchPNT} />
</SelectCol>
) : null}
<ExpandContainer>
<Expand onClick={() => setShowInfo(!showInfo)}>
{asset && asset.address ? (
Expand Down
21 changes: 12 additions & 9 deletions src/components/pages/migration/Migration.jsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
import React from 'react'
import styled from 'styled-components'
import PropTypes from 'prop-types'
import React from 'react'
import { Row, Col, Container } from 'react-bootstrap'
import SwapLine from '../../organisms/swapLine/SwapLine'
import { useMigration } from '../../../hooks/use-migration'
import styled from 'styled-components'

import { PBTC_ON_ETH_MAINNET_V2_MIGRATION, PNT_ON_ETH_MAINNET } from '../../../constants'
import { useAssets } from '../../../hooks/use-assets'
import { useMigration } from '../../../hooks/use-migration'
import Button from '../../atoms/button/Button'
import Progress from '../../molecules/progress/Progress'
import InfoModal from '../../organisms/infoModal/InfoModal'
import MigrationInfo from '../../organisms/migrationInfo/MigrationInfo'
import SwapLine from '../../organisms/swapLine/SwapLine'
import {
OuterContainerSwap,
ContainerSwap,
Expand All @@ -13,11 +19,6 @@ import {
ArrowContainer,
SortIcon,
} from '../swap/Swap'
import Button from '../../atoms/button/Button'
import Progress from '../../molecules/progress/Progress'
import InfoModal from '../../organisms/infoModal/InfoModal'
import MigrationInfo from '../../organisms/migrationInfo/MigrationInfo'
import { PBTC_ON_ETH_MAINNET_V2_MIGRATION, PNT_ON_ETH_MAINNET } from '../../../constants'

const ArrowIcon = styled(SortIcon)`
cursor: normal !important;
Expand Down Expand Up @@ -91,6 +92,7 @@ const Migration = ({
asset={from}
amount={fromAmount}
wallet={fromWallet}
migration={true}
onChangeAmount={onChangeFromAmount}
onMax={onFromMax}
withTitleLabel
Expand All @@ -106,6 +108,7 @@ const Migration = ({
amount={toAmount}
address={address}
wallet={toWallet}
migration={true}
inputType={'text'}
onChangeAmount={onChangeToAmount}
onChangeAddress={setAddress}
Expand Down
37 changes: 21 additions & 16 deletions src/components/pages/swap/Swap.jsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,27 @@
import React, { useCallback, useEffect, useState } from 'react'
import styled from 'styled-components'
import PropTypes from 'prop-types'
import BigNumber from 'bignumber.js'
import PropTypes from 'prop-types'
import React, { useCallback, useEffect, useState } from 'react'
import { Row, Col, Container } from 'react-bootstrap'
import AssetListModal from '../../organisms/assetListModal/AssetListModal'
import Progress from '../../molecules/progress/Progress'
import ReactTooltip from 'react-tooltip'
import styled from 'styled-components'

import TermsOfService from '../../../components/molecules/popup/TermsOfService'
import { MAX_IMPACT, PBTC_ON_ETH_MAINNET_V1_MIGRATION } from '../../../constants'
import { sendEvent } from '../../../ga4'
import { useAssets } from '../../../hooks/use-assets'
import { useSwap } from '../../../hooks/use-swap'
import SwapLine from '../../organisms/swapLine/SwapLine'
import DepositAddressModal from '../../organisms/depositAddressModal/DepositAddressModal'
import SwapInfo from '../../organisms/swapInfo/SwapInfo'
import defaultAssets from '../../../settings/swap-assets'
import { useAssets } from '../../../hooks/use-assets'
import Button from '../../atoms/button/Button'
import Icon from '../../atoms/icon/Icon'
import InfoModal from '../../organisms/infoModal/InfoModal'
import TermsOfService from '../../../components/molecules/popup/TermsOfService'
import Switch from '../../atoms/switch/Switch'
import AddressWarning from '../../molecules/popup/AddressWarning'
import WarningPopup from '../../molecules/popup/Warning'
import Switch from '../../atoms/switch/Switch'
import Button from '../../atoms/button/Button'
import { MAX_IMPACT, PBTC_ON_ETH_MAINNET_V1_MIGRATION } from '../../../constants'
import { sendEvent } from '../../../ga4'
import ReactTooltip from 'react-tooltip'
import Progress from '../../molecules/progress/Progress'
import AssetListModal from '../../organisms/assetListModal/AssetListModal'
import DepositAddressModal from '../../organisms/depositAddressModal/DepositAddressModal'
import InfoModal from '../../organisms/infoModal/InfoModal'
import SwapInfo from '../../organisms/swapInfo/SwapInfo'
import SwapLine from '../../organisms/swapLine/SwapLine'

export const OuterContainerSwap = styled.div`
@media (max-width: 767.98px) {
Expand Down Expand Up @@ -342,9 +343,11 @@ const Swap = ({
defaultImage="./assets/svg/BTC.svg"
title="From"
asset={from}
assets={assets.length === 0 ? defaultAssets : assets}
amount={fromAmount}
wallet={fromWallet}
disableInput={disableFromInput}
selectFrom={onSelectFrom}
onChangeAmount={onChangeFromAmount}
onClickImage={() => setShowModalFrom(true)}
onMax={onFromMax}
Expand All @@ -358,10 +361,12 @@ const Swap = ({
defaultMiniImage="./assets/svg/ETH.svg"
title="To"
asset={to}
assets={assets.length === 0 ? defaultAssets : assets}
amount={toAmount}
address={address}
wallet={toWallet}
disableInput={disableToInput}
selectTo={onSelectTo}
onChangeAmount={onChangeToAmount}
onClickImage={() => setShowModalTo(true)}
onChangeAddress={setAddress}
Expand Down
29 changes: 28 additions & 1 deletion src/hooks/use-assets.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,26 @@ const useAssetsGroupedByGivenStrategy = (_assets) => {
}, [_assets])
}

/*
* This function is used to manage ethPNT as an extension of PNT and not as a standalone token in the Modal List.
*
* ethPNT is an extension of PNT so it must be removed from the modal list somehow. The easiest way found in order to not
* disrupt every other function which uses `swap-assets.js` list structure is to manipulate the array in the very
* component that displays the list.
*/
const useSortPntInflationToken = (_assets) => {
return useMemo(() => {
const pntExtendingTokens = Object.values(_assets)
.flatMap((array) => array)
.filter((asset) => asset.extendsPnt === true)
if (pntExtendingTokens)
return Object.fromEntries(
Object.entries(_assets).filter(([key]) => !pntExtendingTokens.some((token) => token.nativeSymbol === key))
)
return _assets
}, [_assets])
}

const useSearchAssets = (_assets) => {
const [searchWord, setSearchWord] = useState('')

Expand Down Expand Up @@ -100,4 +120,11 @@ const updateAsset = (_asset) => ({
miniImage: `./assets/svg/${_asset.miniImage || _asset.blockchain}.svg`,
})

export { useAssets, useAssetsWithouDefault, usePtoken, useAssetsGroupedByGivenStrategy, useSearchAssets }
export {
useAssets,
useAssetsWithouDefault,
usePtoken,
useAssetsGroupedByGivenStrategy,
useSearchAssets,
useSortPntInflationToken,
}
Loading

0 comments on commit 6d2530f

Please sign in to comment.