Skip to content

Commit

Permalink
Merge pull request #300 from reservoirprotocol/pedro/grwth-3094-add-o…
Browse files Browse the repository at this point in the history
…n-chain-royalties-logic-to-batch-listings

Add onChainRoyalties to BatchListing
  • Loading branch information
pedromcunha committed Aug 22, 2023
2 parents 5d343c5 + ea7a733 commit 1977081
Show file tree
Hide file tree
Showing 7 changed files with 203 additions and 23 deletions.
1 change: 1 addition & 0 deletions components/buttons/List.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ const List: FC<Props> = ({
collectionId={contract}
tokenId={tokenId}
currencies={listingCurrencies}
enableOnChainRoyalties={true}
onClose={(data, stepData, currentStep) => {
if (mutate && currentStep == ListStep.Complete) mutate()
}}
Expand Down
26 changes: 23 additions & 3 deletions components/portfolio/BatchListModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ import { UserToken } from 'pages/portfolio/[[...address]]'
import { FC, useCallback, useEffect, useState } from 'react'
import { useNetwork, useWalletClient, useSwitchNetwork } from 'wagmi'
import { ApprovalCollapsible } from './ApprovalCollapsible'
import { parseUnits, zeroAddress } from 'viem'
import { formatUnits, parseUnits, zeroAddress } from 'viem'
import useOnChainRoyalties, {
OnChainRoyaltyReturnType,
} from 'hooks/useOnChainRoyalties'

enum BatchListStep {
Approving,
Expand All @@ -43,6 +46,7 @@ type Props = {
disabled: boolean
currency: Currency
selectedMarketplaces: Marketplace[]
onChainRoyalties: ReturnType<typeof useOnChainRoyalties>['data']
onCloseComplete?: () => void
}

Expand All @@ -51,6 +55,7 @@ const BatchListModal: FC<Props> = ({
disabled,
currency,
selectedMarketplaces,
onChainRoyalties,
onCloseComplete,
}) => {
const [open, setOpen] = useState(false)
Expand Down Expand Up @@ -136,7 +141,7 @@ const BatchListModal: FC<Props> = ({

const batchListingData: BatchListingData[] = []

listings.forEach((listing) => {
listings.forEach((listing, i) => {
let expirationTime: string | null = null

if (
Expand Down Expand Up @@ -174,6 +179,21 @@ const BatchListModal: FC<Props> = ({
convertedListing.currency = currency.contract
}

const onChainRoyalty =
onChainRoyalties && onChainRoyalties[i] ? onChainRoyalties[i] : null
if (onChainRoyalty && listing.orderKind?.includes('seaport')) {
convertedListing.automatedRoyalties = false
const royaltyData = onChainRoyalty.result as OnChainRoyaltyReturnType
const royalties = royaltyData[0].map((recipient, i) => {
const bps =
(parseFloat(formatUnits(royaltyData[1][i], 18)) / 1) * 10000
return `${recipient}:${bps}`
})
if (royalties.length > 0) {
convertedListing.fees = [...royalties]
}
}

batchListingData.push({
listing: convertedListing,
token: listing.token,
Expand Down Expand Up @@ -241,7 +261,7 @@ const BatchListModal: FC<Props> = ({
)
setTransactionError(transactionError)
})
}, [client, listings, wallet])
}, [client, listings, wallet, onChainRoyalties])

const trigger = (
<Button disabled={disabled} onClick={listTokens}>
Expand Down
65 changes: 63 additions & 2 deletions components/portfolio/BatchListings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
SetStateAction,
useCallback,
useEffect,
useMemo,
useState,
} from 'react'
import { Currency, Listings, ListModal } from '@reservoir0x/reservoir-kit-ui'
Expand All @@ -30,6 +31,10 @@ import BatchListModal from 'components/portfolio/BatchListModal'
import { useMediaQuery } from 'react-responsive'
import { BatchListingsTableHeading } from './BatchListingsTableHeading'
import { BatchListingsTableRow } from './BatchListingsTableRow'
import useOnChainRoyalties, {
OnChainRoyaltyReturnType,
} from 'hooks/useOnChainRoyalties'
import { formatUnits } from 'viem'

export type BatchListing = {
token: UserToken
Expand Down Expand Up @@ -108,6 +113,52 @@ const BatchListings: FC<Props> = ({
const [currency, setCurrency] = useState<Currency>(
currencies && currencies[0] ? currencies[0] : defaultCurrency
)
const royaltyQuery: NonNullable<
Parameters<typeof useOnChainRoyalties>['0']['tokens']
> = useMemo(
() =>
listings
.filter((listing) => listing?.token?.token !== undefined)
.map((listing) => ({
contract: listing.token.token?.contract as string,
tokenId: listing.token.token?.tokenId as string,
})),
[listings]
)
const { data: onChainRoyalties } = useOnChainRoyalties({
tokens: royaltyQuery,
chainId: chain.id,
enabled: royaltyQuery.length > 0,
})

const onChainRoyaltiesMap = useMemo(
() =>
onChainRoyalties?.reduce((royalties, royaltyData, i) => {
if (
royaltyData.status === 'success' &&
(royaltyData.result as any)[0] &&
(royaltyData.result as any)[1]
) {
const royaltyBpsList = (
royaltyData.result as OnChainRoyaltyReturnType
)[1]
const id = `${royaltyQuery[i].contract}:${royaltyQuery[i].tokenId}`
const totalRoyalty = royaltyBpsList
? royaltyBpsList.reduce((total, feeBps) => {
total += parseFloat(
formatUnits(feeBps, currency.decimals || 18)
)
return total
}, 0)
: 0
if (totalRoyalty) {
royalties[id] = (totalRoyalty / 1) * 10000
}
}
return royalties
}, {} as Record<string, number>) || {},
[onChainRoyalties, chainCurrency]
)

const displayQuantity = useCallback(() => {
return listings.some((listing) => listing?.token?.token?.kind === 'erc1155')
Expand Down Expand Up @@ -155,11 +206,15 @@ const BatchListings: FC<Props> = ({
itemId
)

const onChainRoyaltyBps = onChainRoyaltiesMap[itemId]

const profits = itemListings.map((listing) => {
const listingCreatorRoyalties =
(Number(listing.price) *
listing.quantity *
(listing?.token?.token?.collection?.royaltiesBps || 0)) /
(onChainRoyaltyBps ||
listing?.token?.token?.collection?.royaltiesBps ||
0)) /
10000

const profit =
Expand All @@ -176,7 +231,7 @@ const BatchListings: FC<Props> = ({
}, 0)

setTotalProfit(maxProfit)
}, [listings, selectedMarketplaces, globalPrice])
}, [listings, onChainRoyaltiesMap, selectedMarketplaces, globalPrice])

useEffect(() => {
const hasInvalidPrice = listings.some(
Expand Down Expand Up @@ -484,6 +539,11 @@ const BatchListings: FC<Props> = ({
<BatchListingsTableRow
listing={listing}
listings={listings}
onChainRoyaltiesBps={
onChainRoyaltiesMap[
`${listing.token.token?.contract}:${listing.token.token?.tokenId}`
]
}
setListings={setListings}
updateListing={updateListing}
setSelectedItems={setSelectedItems}
Expand Down Expand Up @@ -525,6 +585,7 @@ const BatchListings: FC<Props> = ({
/>
<BatchListModal
listings={listings}
onChainRoyalties={onChainRoyalties}
disabled={listButtonDisabled}
currency={currency}
selectedMarketplaces={selectedMarketplaces}
Expand Down
10 changes: 7 additions & 3 deletions components/portfolio/BatchListingsTableRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import optimizeImage from 'utils/optimizeImage'
type BatchListingsTableRowProps = {
listing: BatchListing
listings: BatchListing[]
onChainRoyaltiesBps: number
displayQuantity: boolean
gridTemplateColumns: string
setListings: Dispatch<SetStateAction<BatchListing[]>>
Expand All @@ -52,6 +53,7 @@ const MINIMUM_AMOUNT = 0.000001
export const BatchListingsTableRow: FC<BatchListingsTableRowProps> = ({
listing,
listings,
onChainRoyaltiesBps,
setListings,
updateListing,
selectedItems,
Expand Down Expand Up @@ -158,7 +160,9 @@ export const BatchListingsTableRow: FC<BatchListingsTableRowProps> = ({
}, [openseaFees, price, quantity, marketplace])

const creatorRoyalties =
(listing?.token?.token?.collection?.royaltiesBps || 0) / 10000
(onChainRoyaltiesBps ||
listing?.token?.token?.collection?.royaltiesBps ||
0) / 10000

const profit =
Number(price) * listing.quantity -
Expand Down Expand Up @@ -431,7 +435,7 @@ export const BatchListingsTableRow: FC<BatchListingsTableRowProps> = ({
}}
/>
<Text style="body1" color="subtle" ellipsify>
({creatorRoyalties * 100})%
({creatorRoyalties * 100}%)
</Text>
</Flex>
</TableCell>
Expand All @@ -443,7 +447,7 @@ export const BatchListingsTableRow: FC<BatchListingsTableRowProps> = ({
textStyle="body1"
/>
<Text style="body1" color="subtle" ellipsify>
({marketplaceFeePercent || 0})%
({marketplaceFeePercent || 0}%)
</Text>
</Flex>
</TableCell>
Expand Down
94 changes: 94 additions & 0 deletions hooks/useOnChainRoyalties.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import { parseUnits } from 'viem'
import { useContractReads } from 'wagmi'
import { mainnet, goerli } from 'wagmi/chains'

type Props = {
tokens?: {
contract: string
tokenId: string
}[]
enabled: boolean
chainId: number
}

export type OnChainRoyaltyReturnType = [`0x${string}`[], bigint[]]

const MANIFOLD_ABI = [
{
inputs: [
{
internalType: 'address',
name: 'tokenAddress',
type: 'address',
},
{
internalType: 'uint256',
name: 'tokenId',
type: 'uint256',
},
{
internalType: 'uint256',
name: 'value',
type: 'uint256',
},
],
name: 'getRoyaltyView',
outputs: [
{
internalType: 'address payable[]',
name: 'recipients',
type: 'address[]',
},
{
internalType: 'uint256[]',
name: 'amounts',
type: 'uint256[]',
},
],
stateMutability: 'view',
type: 'function',
},
] as const

export default function ({ tokens, enabled, chainId = mainnet.id }: Props) {
let manifoldContract = ''
switch (chainId) {
case mainnet.id: {
manifoldContract = '0x0385603ab55642cb4dd5de3ae9e306809991804f'
break
}
case 137: {
manifoldContract = '0x28EdFcF0Be7E86b07493466e7631a213bDe8eEF2'
break
}
case 80001:
manifoldContract = '0x0a01E11887f727D1b1Cd81251eeEE9BEE4262D07'
break
case goerli.id:
case 10:
case 8435:
case 42161:
case 43114:
case 56: {
manifoldContract = '0xEF770dFb6D5620977213f55f99bfd781D04BBE15'
break
}
}

const amount = parseUnits('1', 18)

return useContractReads({
contracts: tokens?.map(({ tokenId, contract }) => ({
chainId: chainId,
address: manifoldContract as any,
abi: MANIFOLD_ABI,
args: [contract as any, tokenId as any, amount as any],
functionName: 'getRoyaltyView',
})),
enabled:
manifoldContract.length > 0 && enabled && tokens && tokens?.length > 0
? true
: false,
cacheTime: 60 * 1000,
})
}
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
"@radix-ui/react-toggle-group": "^1.0.1",
"@radix-ui/react-tooltip": "^1.0.2",
"@rainbow-me/rainbowkit": "^1.0.3",
"@reservoir0x/reservoir-kit-ui": "1.4.0",
"@reservoir0x/reservoir-kit-ui": "1.6.1",
"@sentry/nextjs": "^7.53.1",
"@types/uuid": "^9.0.1",
"dayjs": "^1.11.6",
Expand Down Expand Up @@ -63,6 +63,6 @@
"@types/react": "^18.0",
"@types/react-dom": "^18.0",
"next-themes": "^0.2.0",
"typescript": "^4.9.4"
"typescript": "^5.0.4"
}
}
Loading

2 comments on commit 1977081

@vercel
Copy link

@vercel vercel bot commented on 1977081 Aug 22, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

artblocks-v2 – ./

artblocks-v2-git-main-unevenlabs.vercel.app
artblocks-v2-unevenlabs.vercel.app
artblocks-v2.vercel.app

@vercel
Copy link

@vercel vercel bot commented on 1977081 Aug 22, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.