Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

⛑️ Revenue share amm restriction #6416

Merged
merged 3 commits into from
Jul 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,17 @@ import { BuyMarketTokenModal } from '@/components/_crt/BuyMarketTokenModal'

type BuyFromMarketButtonProps = {
tokenId: string
hasActiveRevenueShare?: boolean
isTokenLocked?: boolean
}

export const BuyFromMarketButton = ({ tokenId, hasActiveRevenueShare }: BuyFromMarketButtonProps) => {
export const BuyFromMarketButton = ({ tokenId, isTokenLocked }: BuyFromMarketButtonProps) => {
const [showModal, setShowModal] = useState(false)
return (
<>
<BuyMarketTokenModal tokenId={tokenId} show={showModal} onClose={() => setShowModal(false)} />
<ProtectedActionWrapper title="You want to buy tokens?" description="Sign in to buy">
<Button
variant={hasActiveRevenueShare ? 'warning' : 'primary'}
variant={isTokenLocked ? 'warning' : 'primary'}
size="large"
fullWidth
onClick={() => setShowModal(true)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ import { DialogProps } from '@/components/_overlays/Dialog'
import { DialogModal } from '@/components/_overlays/DialogModal'
import { absoluteRoutes } from '@/config/routes'
import { useDismissibleAction } from '@/hooks/useDismissibleAction'
import { useIsTokenInLockedMode } from '@/hooks/useIsTokenInLockedMode'
import { useMediaMatch } from '@/hooks/useMediaMatch'
import { useSegmentAnalytics } from '@/hooks/useSegmentAnalytics'
import { hapiBnToTokenNumber, tokenNumberToHapiBn } from '@/joystream-lib/utils'
import { useFee, useJoystream, useSubscribeAccountBalance } from '@/providers/joystream'
import { useJoystreamStore } from '@/providers/joystream/joystream.store'
import { useNetworkUtils } from '@/providers/networkUtils/networkUtils.hooks'
import { useSnackbar } from '@/providers/snackbars'
import { useTransaction } from '@/providers/transactions/transactions.hooks'
Expand Down Expand Up @@ -57,7 +57,6 @@ export const BuyMarketTokenModal = ({ tokenId, onClose: _onClose, show }: BuySal
const amountRef = useRef<number | null>(null)
const { control, watch, handleSubmit, reset, formState } = useForm<{ tokenAmount: number }>()
const tokenAmount = watch('tokenAmount') || 0
const currentBlockRef = useRef(useJoystreamStore((store) => store.currentBlock))
const { fullFee } = useFee('purchaseTokenOnMarketTx', ['1', '1', String(tokenAmount ?? 0), '1000000'])
const { data, loading } = useGetFullCreatorTokenQuery({
variables: {
Expand All @@ -67,8 +66,8 @@ export const BuyMarketTokenModal = ({ tokenId, onClose: _onClose, show }: BuySal
SentryLogger.error('Error while fetching creator token', 'BuyMarketTokenModal', error)
},
})
const activeRevenueShare = data?.creatorTokenById?.revenueShares.find((rS) => !rS.finalized)
const hasActiveRevenueShare = (activeRevenueShare?.endsAt ?? 0) > currentBlockRef.current
const isTokenLocked = useIsTokenInLockedMode(data?.creatorTokenById ?? undefined)

const { data: memberTokenAccount } = useGetCreatorTokenHoldersQuery({
variables: {
where: {
Expand Down Expand Up @@ -355,10 +354,10 @@ export const BuyMarketTokenModal = ({ tokenId, onClose: _onClose, show }: BuySal
if (activeStep === BUY_MARKET_TOKEN_STEPS.form) {
setPrimaryButtonProps({
text: 'Continue',
disabled: hasActiveRevenueShare,
variant: hasActiveRevenueShare ? 'warning' : undefined,
disabled: isTokenLocked,
variant: isTokenLocked ? 'warning' : undefined,
onClick: () => {
if (hasActiveRevenueShare) {
if (isTokenLocked) {
displaySnackbar({
iconType: 'error',
title: 'You cannot trade tokens during revenue share.',
Expand All @@ -385,7 +384,7 @@ export const BuyMarketTokenModal = ({ tokenId, onClose: _onClose, show }: BuySal
displaySnackbar,
handleSubmit,
hasAcceptedConditions,
hasActiveRevenueShare,
isTokenLocked,
onTransactionSubmit,
])

Expand All @@ -410,7 +409,7 @@ export const BuyMarketTokenModal = ({ tokenId, onClose: _onClose, show }: BuySal
confetti={activeStep === BUY_MARKET_TOKEN_STEPS.success && smMatch}
noContentPadding={activeStep === BUY_MARKET_TOKEN_STEPS.conditions}
additionalActionsNode={
hasActiveRevenueShare ? (
isTokenLocked ? (
<Tooltip text="During revenue share you are unable to trade on market. Please wait until it ends to make new transactions.">
<SvgAlertsWarning24 />
</Tooltip>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ import { ExpandButton } from '@/components/_buttons/ExpandButton'
import { BuyFromMarketButton } from '@/components/_crt/BuyFromMarketButton/BuyFromMarketButton'
import { SellOnMarketButton } from '@/components/_crt/SellOnMarketButton/SellOnMarketButton'
import { DetailsContent } from '@/components/_nft/NftTile'
import { useIsTokenInLockedMode } from '@/hooks/useIsTokenInLockedMode'
import { useMediaMatch } from '@/hooks/useMediaMatch'
import { hapiBnToTokenNumber } from '@/joystream-lib/utils'
import { useJoystreamStore } from '@/providers/joystream/joystream.store'
import { calcBuyMarketPricePerToken } from '@/utils/crts'
import { SentryLogger } from '@/utils/logs'
import { formatDate } from '@/utils/time'
Expand Down Expand Up @@ -110,9 +110,7 @@ const InactiveDetails = () => {
}

const MarketDetails = ({ token }: { token: FullCreatorTokenFragment }) => {
const currentBlockRef = useRef(useJoystreamStore((store) => store.currentBlock))
const activeRevenueShare = token.revenueShares.find((rS) => !rS.finalized)
const hasActiveRevenueShare = (activeRevenueShare?.endsAt ?? 0) > currentBlockRef.current
const isTokenLocked = useIsTokenInLockedMode(token)
const calculateSlippageAmount = useCallback(
(amount: number) => {
const currentAmm = token?.ammCurves.find((amm) => !amm.finalized)
Expand All @@ -136,8 +134,8 @@ const MarketDetails = ({ token }: { token: FullCreatorTokenFragment }) => {
tooltipText="Price of each incremental unit purchased or sold depends on overall quantity of tokens transacted, the actual average price per unit for the entire purchase or sale will differ from the price displayed for the first unit transacted."
/>
<FlexBox equalChildren width="100%" gap={2}>
<SellOnMarketButton hasActiveRevenueShare={hasActiveRevenueShare} tokenId={token.id} />
<BuyFromMarketButton hasActiveRevenueShare={hasActiveRevenueShare} tokenId={token.id} />
<SellOnMarketButton isTokenLocked={isTokenLocked} tokenId={token.id} />
<BuyFromMarketButton isTokenLocked={isTokenLocked} tokenId={token.id} />
</FlexBox>

<SupplyLine>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,17 @@ import { SellTokenModal } from '@/components/_crt/SellTokenModal'

type SellOnMarketButtonProps = {
tokenId: string
hasActiveRevenueShare?: boolean
isTokenLocked?: boolean
}

export const SellOnMarketButton = ({ tokenId, hasActiveRevenueShare }: SellOnMarketButtonProps) => {
export const SellOnMarketButton = ({ tokenId, isTokenLocked }: SellOnMarketButtonProps) => {
const [showModal, setShowModal] = useState(false)
return (
<>
<SellTokenModal tokenId={tokenId} show={showModal} onClose={() => setShowModal(false)} />
<ProtectedActionWrapper title="You want to sell tokens?" description="Sign in to sell">
<Button
variant={hasActiveRevenueShare ? 'warning-secondary' : 'secondary'}
variant={isTokenLocked ? 'warning-secondary' : 'secondary'}
fullWidth
size="large"
onClick={() => setShowModal(true)}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import BN from 'bn.js'
import { useCallback, useMemo, useRef, useState } from 'react'
import { useCallback, useMemo, useState } from 'react'
import { useForm } from 'react-hook-form'

import { useGetFullCreatorTokenQuery } from '@/api/queries/__generated__/creatorTokens.generated'
Expand All @@ -12,10 +12,10 @@ import { AmmModalSummaryTemplate } from '@/components/_crt/AmmModalTemplates/Amm
import { DialogModal } from '@/components/_overlays/DialogModal'
import { atlasConfig } from '@/config'
import { useGetTokenBalance } from '@/hooks/useGetTokenBalance'
import { useIsTokenInLockedMode } from '@/hooks/useIsTokenInLockedMode'
import { useSegmentAnalytics } from '@/hooks/useSegmentAnalytics'
import { hapiBnToTokenNumber, tokenNumberToHapiBn } from '@/joystream-lib/utils'
import { useFee, useJoystream } from '@/providers/joystream'
import { useJoystreamStore } from '@/providers/joystream/joystream.store'
import { useNetworkUtils } from '@/providers/networkUtils/networkUtils.hooks'
import { useSnackbar } from '@/providers/snackbars'
import { useTransaction } from '@/providers/transactions/transactions.hooks'
Expand All @@ -41,7 +41,6 @@ export const SellTokenModal = ({ tokenId, onClose: _onClose, show }: SellTokenMo
const { trackAMMTokensSold } = useSegmentAnalytics()
const { displaySnackbar } = useSnackbar()
const { fullFee } = useFee('sellTokenOnMarketTx', ['1', '1', '2', '10000000'])
const currentBlockRef = useRef(useJoystreamStore((store) => store.currentBlock))
const { data, loading } = useGetFullCreatorTokenQuery({
variables: {
id: tokenId,
Expand All @@ -50,8 +49,7 @@ export const SellTokenModal = ({ tokenId, onClose: _onClose, show }: SellTokenMo
SentryLogger.error('Failed to fetch token data', 'SellTokenModal', { error })
},
})
const activeRevenueShare = data?.creatorTokenById?.revenueShares.find((rS) => !rS.finalized)
const hasActiveRevenueShare = (activeRevenueShare?.endsAt ?? 0) > currentBlockRef.current
const isTokenLocked = useIsTokenInLockedMode(data?.creatorTokenById ?? undefined)

const currentAmm = data?.creatorTokenById?.currentAmmSale
const ammBalance = currentAmm ? +currentAmm.mintedByAmm - +currentAmm.burnedByAmm : 0
Expand Down Expand Up @@ -198,7 +196,7 @@ export const SellTokenModal = ({ tokenId, onClose: _onClose, show }: SellTokenMo
)

const onFormSubmit = () => {
if (hasActiveRevenueShare) {
if (isTokenLocked) {
displaySnackbar({
iconType: 'error',
title: 'You cannot trade tokens during revenue share.',
Expand Down Expand Up @@ -269,7 +267,7 @@ export const SellTokenModal = ({ tokenId, onClose: _onClose, show }: SellTokenMo
show={show}
onExitClick={onClose}
additionalActionsNode={
hasActiveRevenueShare ? (
isTokenLocked ? (
<Tooltip text="During revenue share you are unable to trade on market. Please wait until it ends to make new transactions.">
<SvgAlertsWarning24 />
</Tooltip>
Expand All @@ -282,8 +280,8 @@ export const SellTokenModal = ({ tokenId, onClose: _onClose, show }: SellTokenMo
primaryButton={{
text: isFormStep ? 'Continue' : `Sell $${title}`,
onClick: isFormStep ? onFormSubmit : onTransactionSubmit,
disabled: hasActiveRevenueShare,
variant: hasActiveRevenueShare ? 'warning' : undefined,
disabled: isTokenLocked,
variant: isTokenLocked ? 'warning' : undefined,
}}
>
{step === 'form' ? (
Expand Down
16 changes: 16 additions & 0 deletions packages/atlas/src/hooks/useIsTokenInLockedMode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// import { useRef } from 'react'
import { FullCreatorTokenFragment } from '@/api/queries/__generated__/fragments.generated'

// import { useJoystreamStore } from '@/providers/joystream/joystream.store'

export const useIsTokenInLockedMode = (token?: FullCreatorTokenFragment) => {
// const currentBlockRef = useRef(useJoystreamStore((store) => store.currentBlock))
// 1. Check if there is any unfinalized revenue share
const activeRevenueShare = token?.revenueShares.find((rS) => !rS.finalized)

// 2. If ending block is not yet came for a user, consider that the token is locked
// BUG: looks like runtime doesnt allow to make tx if the revenue share not finalized
// const hasActiveRevenueShare = (activeRevenueShare?.endsAt ?? 0) > currentBlockRef.current

return !!activeRevenueShare
}
Loading