Skip to content
Merged
2 changes: 1 addition & 1 deletion .pnpmfile.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const approvedList = new Map([
'wyvern-js',
['git+https://github.com/ProjectOpenSea/wyvern-js.git#v3.2.1', 'github:ProjectOpenSea/wyvern-js#semver:^3.2.1'],
],
['wyvern-schemas', 'git+https://github.com/ProjectOpenSea/wyvern-schemas.git#v0.11.1'],
['wyvern-schemas', 'git+https://github.com/ProjectOpenSea/wyvern-schemas.git#v0.13.1'],
['bignumber.js', 'git+https://github.com/frozeman/bignumber.js-nolookahead.git'],
/* cspell:disable-next-line */
['html-parse-stringify2', 'github:locize/html-parse-stringify2'],
Expand Down
4 changes: 2 additions & 2 deletions packages/mask/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@
"@masknet/shared-base": "workspace:*",
"@masknet/theme": "workspace:*",
"@masknet/web3-contracts": "workspace:*",
"@masknet/web3-providers": "workspace:*",
"@masknet/web3-shared-base": "workspace:*",
"@masknet/web3-shared-evm": "workspace:*",
"@masknet/web3-providers": "workspace:*",
"@msgpack/msgpack": "^2.7.1",
"@servie/events": "^3.0.0",
"@sinonjs/text-encoding": "^0.7.1",
Expand Down Expand Up @@ -90,7 +90,7 @@
"lodash-es": "npm:lodash@^4.17.11",
"millify": "^4.0.0",
"next-tick": "^1.0.0",
"opensea-js": "^1.1.11",
"opensea-js": "^1.2.7",
"promievent": "^0.1.4",
"protobufjs": "^6.11.2",
"react-draggable": "^4.4.4",
Expand Down
1 change: 1 addition & 0 deletions packages/mask/shared-ui/locales/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -578,6 +578,7 @@
"plugin_collectible_you": "You",
"plugin_collectible_done": "Done",
"plugin_collectible_retry": "Retry",
"plugin_collectible_get_more_token": "Get more {{token}}",
"plugin_collectible_sell": "Sell",
"plugin_collectible_checkout": "Checkout",
"plugin_collectible_place_bid": "Place Bid",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
} from '@mui/material'
import { makeStyles } from '@masknet/theme'
import { Trans } from 'react-i18next'
import { useAccount } from '@masknet/web3-shared-evm'
import { EthereumTokenType, useAccount, useFungibleTokenWatched } from '@masknet/web3-shared-evm'
import { InjectedDialog } from '../../../components/shared/InjectedDialog'
import { UnreviewedWarning } from './UnreviewedWarning'
import { useI18N } from '../../../utils'
Expand All @@ -24,6 +24,8 @@ import { PluginTraderMessages } from '../../Trader/messages'
import { CheckoutOrder } from './CheckoutOrder'
import type { useAsset } from '../../EVM/hooks/useAsset'
import type { useAssetOrder } from '../hooks/useAssetOrder'
import type { Coin } from '../../Trader/types'
import { isGreaterThan } from '@masknet/web3-shared-base'

const useStyles = makeStyles()((theme) => {
return {
Expand Down Expand Up @@ -62,16 +64,18 @@ export interface CheckoutDialogProps {

export function CheckoutDialog(props: CheckoutDialogProps) {
const { asset, open, onClose, order } = props
const isAuction = asset?.value?.is_auction ?? false
const isVerified = asset?.value?.is_verified ?? false
const { t } = useI18N()
const { classes } = useStyles()

const account = useAccount()

const [unreviewedChecked, setUnreviewedChecked] = useState(false)
const [ToS_Checked, setToS_Checked] = useState(false)

const [insufficientBalance, setInsufficientBalance] = useState(false)
const { token, balance } = useFungibleTokenWatched({
type: EthereumTokenType.Native,
address: order.value?.paymentTokenContract?.address ?? '',
})
const onCheckout = useCallback(async () => {
if (!asset?.value) return
if (!asset.value.token_id || !asset.value.token_address) return
Expand All @@ -84,13 +88,33 @@ export function CheckoutDialog(props: CheckoutDialogProps) {
})
}, [asset?.value, account, order?.value])

const { openDialog: openSwapDialog } = useRemoteControlledDialog(PluginTraderMessages.swapDialogUpdated)
const { setDialog: openSwapDialog } = useRemoteControlledDialog(PluginTraderMessages.swapDialogUpdated)

const onConvertClick = useCallback(() => {
if (!token?.value) return
openSwapDialog({
open: true,
traderProps: {
coin: {
id: token.value.address,
name: token.value.name ?? '',
symbol: token.value.symbol ?? '',
contract_address: token.value.address,
decimals: token.value.decimals,
} as Coin,
},
})
}, [token.value, openSwapDialog])

const validationMessage = useMemo(() => {
if (isGreaterThan(order?.value?.basePrice ?? 0, balance.value ?? 0)) {
setInsufficientBalance(true)
return t('plugin_collectible_insufficient_balance')
}
if (!isVerified && !unreviewedChecked) return t('plugin_collectible_ensure_unreviewed_item')
if (!isVerified && !ToS_Checked) return t('plugin_collectible_check_tos_document')
return ''
}, [isVerified, unreviewedChecked, ToS_Checked])
}, [isVerified, unreviewedChecked, ToS_Checked, order.value])

return (
<InjectedDialog title={t('plugin_collectible_checkout')} open={open} onClose={onClose}>
Expand Down Expand Up @@ -172,13 +196,15 @@ export function CheckoutDialog(props: CheckoutDialogProps) {
completeOnClick={onClose}
failedOnClick="use executor"
/>
{asset?.value?.isOrderWeth ? (
{asset?.value?.isOrderWeth || insufficientBalance ? (
<ActionButton
className={classes.button}
variant="contained"
size="large"
onClick={openSwapDialog}>
{t('plugin_collectible_convert_eth')}
onClick={onConvertClick}>
{insufficientBalance
? t('plugin_collectible_get_more_token', { token: token.value?.symbol })
: t('plugin_collectible_convert_eth')}
</ActionButton>
) : null}
</Box>
Expand Down
22 changes: 16 additions & 6 deletions packages/mask/src/plugins/Collectible/SNSAdaptor/CheckoutOrder.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { Table, TableHead, TableBody, TableRow, TableCell, Typography, Link } from '@mui/material'
import { makeStyles } from '@masknet/theme'
import { Image } from '../../../components/shared/Image'
import { useChainId } from '@masknet/web3-shared-evm'
import { ERC20TokenDetailed, useChainId, formatBalance } from '@masknet/web3-shared-evm'
import { resolveAssetLinkOnOpenSea } from '../pipes'
import { useI18N } from '../../../utils'
import type { useAsset } from '../../EVM/hooks/useAsset'
import type { useAssetOrder } from '../hooks/useAssetOrder'
import type { Order } from 'opensea-js/lib/types'

const useStyles = makeStyles()((theme) => ({
itemInfo: {
Expand All @@ -24,14 +25,23 @@ export interface CheckoutOrderProps {

export function CheckoutOrder(props: CheckoutOrderProps) {
const { t } = useI18N()
const { asset } = props
const order = asset?.value?.desktopOrder
const { asset, assetOrder } = props
const order = assetOrder?.value ?? asset?.value?.desktopOrder
const { classes } = useStyles()
const chainId = useChainId()

if (!asset?.value) return null
if (!order) return null

const price = (order as Order).currentPrice ?? asset.value.current_price
const getPrice = () => {
if (!price) return 'error'
const decimal = asset.value?.response_.collection.payment_tokens.find((item: ERC20TokenDetailed) => {
return item.symbol === asset.value?.current_symbol
})?.decimals
if (!decimal) return 'error'
return formatBalance(price, decimal) ?? 'error'
}

return (
<Table size="small">
<TableHead>
Expand Down Expand Up @@ -67,7 +77,7 @@ export function CheckoutOrder(props: CheckoutOrderProps) {
</TableCell>
<TableCell align="right">
<Typography>
{asset.value.current_price} {asset.value.current_symbol}
{getPrice()} {asset.value.current_symbol}
</Typography>
</TableCell>
</TableRow>
Expand All @@ -77,7 +87,7 @@ export function CheckoutOrder(props: CheckoutOrderProps) {
</TableCell>
<TableCell align="right">
<Typography>
{asset.value.current_price} {asset.value.current_symbol}
{getPrice()} {asset.value.current_symbol}
</Typography>
</TableCell>
</TableRow>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ export function MakeOfferDialog(props: MakeOfferDialogProps) {
const [expirationDateTime, setExpirationDateTime] = useState(new Date())
const [unreviewedChecked, setUnreviewedChecked] = useState(false)
const [ToS_Checked, setToS_Checked] = useState(false)
const [insufficientBalance, setInsufficientBalance] = useState(false)

const { amount, token, balance, setAmount, setToken } = useFungibleTokenWatched(selectedPaymentToken)

Expand Down Expand Up @@ -137,10 +138,14 @@ export function MakeOfferDialog(props: MakeOfferDialogProps) {
}, [open])

const validationMessage = useMemo(() => {
setInsufficientBalance(false)
const amount_ = rightShift(amount, token.value?.decimals)
const balance_ = new BigNumber(balance.value ?? '0')
if (amount_.isNaN() || amount_.isZero()) return t('plugin_collectible_enter_a_price')
if (balance_.isZero() || amount_.isGreaterThan(balance_)) return t('plugin_collectible_insufficient_balance')
if (balance_.isZero() || amount_.isGreaterThan(balance_)) {
setInsufficientBalance(true)
return t('plugin_collectible_insufficient_balance')
}
if (!isAuction && expirationDateTime.getTime() - Date.now() <= 0)
return t('plugin_collectible_invalid_expiration_date')
if (!isVerified && !unreviewedChecked) return t('plugin_collectible_ensure_unreviewed_item')
Expand Down Expand Up @@ -260,13 +265,16 @@ export function MakeOfferDialog(props: MakeOfferDialogProps) {
completeOnClick={onClose}
failedOnClick="use executor"
/>
{(isAuction ? asset.value?.isCollectionWeth : asset.value?.isOrderWeth) ? (
{(isAuction ? asset.value?.isCollectionWeth : asset.value?.isOrderWeth) ||
insufficientBalance ? (
<ActionButton
className={classes.button}
variant="contained"
size="large"
onClick={onConvertClick}>
Convert ETH
{insufficientBalance
? t('plugin_collectible_get_more_token', { token: token.value?.symbol })
: t('plugin_collectible_convert_eth')}
</ActionButton>
) : null}
</Box>
Expand Down
22 changes: 13 additions & 9 deletions packages/mask/src/plugins/Collectible/hooks/useAssetOrder.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,32 @@
import { unreachable } from '@dimensiondev/kit'
import { getOrderUnitPrice } from '@masknet/web3-providers'
import { ONE } from '@masknet/web3-shared-base'
import { ZERO } from '@masknet/web3-shared-base'
import { NonFungibleAssetProvider } from '@masknet/web3-shared-evm'
import { head } from 'lodash-unified'
import type { Order } from 'opensea-js/lib/types'
import { useAsyncRetry } from 'react-use'
import { PluginCollectibleRPC } from '../messages'
import type { CollectibleToken } from '../types'
import type { AssetOrder, CollectibleToken } from '../types'

export function useAssetOrder(provider: NonFungibleAssetProvider, token?: CollectibleToken) {
return useAsyncRetry(async () => {
if (!token) return
switch (provider) {
case NonFungibleAssetProvider.OPENSEA:
const openSeaResponse = await PluginCollectibleRPC.getAssetFromSDK(token.contractAddress, token.tokenId)
const getPrice = (order: Order) =>
getOrderUnitPrice(
order.currentPrice?.toFixed(),
order.paymentTokenContract?.decimals ?? 0,
order.quantity.toFixed(),
) ?? ONE
const getPrice = (order: Order | AssetOrder) => {
const _order = order as AssetOrder
return (
getOrderUnitPrice(
_order.currentPrice,
_order.paymentTokenContract?.decimals,
_order.quantity,
) ?? ZERO
)
}

const sellOrders = openSeaResponse.sellOrders ?? []
const desktopOrder = head(sellOrders.sort((a, b) => getPrice(a).toNumber() - getPrice(b).toNumber()))

return desktopOrder
case NonFungibleAssetProvider.RARIBLE:
return
Expand Down
2 changes: 2 additions & 0 deletions packages/mask/src/plugins/Collectible/types/opensea.ts
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,8 @@ export interface AssetOrder {
expiration_time: number
order_hash: string
base_price?: string
currentPrice?: string
paymentTokenContract?: OpenSeaFungibleToken
}

export interface OpenSeaResponse extends Asset {
Expand Down
Loading