diff --git a/packages/common/src/actions/auction.ts b/packages/common/src/actions/auction.ts index ed86e8f..69821ec 100644 --- a/packages/common/src/actions/auction.ts +++ b/packages/common/src/actions/auction.ts @@ -45,6 +45,10 @@ export class BidState { } } +export const decodeAuction = (buffer: Buffer) => { + return deserializeBorsh(AUCTION_SCHEMA, AuctionData, buffer) as AuctionData; +}; + export const BASE_AUCTION_DATA_SIZE = 32 + 32 + 32 + 8 + 8 + 1 + 9 + 9 + 9 + 9; export class AuctionData { @@ -67,6 +71,9 @@ export class AuctionData { /// Gap time is the amount of time in slots after the previous bid at which the auction ends. endAuctionGap?: BN; + /// Used for precalculation on the front end, not a backend key + auctionManagerKey?: PublicKey; + constructor(args: { authority: PublicKey; resource: PublicKey; @@ -247,7 +254,7 @@ export const AUCTION_SCHEMA = new Map([ ['resource', 'pubkey'], ['tokenMint', 'pubkey'], ['state', 'u8'], - ['bidState', 'BidState'], + ['bidState', BidState], ['lastBid', { kind: 'option', type: 'u64' }], ['endedAt', { kind: 'option', type: 'u64' }], ['endAuctionAt', { kind: 'option', type: 'u64' }], diff --git a/packages/common/src/actions/vault.ts b/packages/common/src/actions/vault.ts index f837bd7..60e8e0d 100644 --- a/packages/common/src/actions/vault.ts +++ b/packages/common/src/actions/vault.ts @@ -258,6 +258,14 @@ export const decodeVault = (buffer: Buffer) => { return deserializeBorsh(VAULT_SCHEMA, Vault, buffer) as Vault; }; +export const decodeSafetyDeposit = (buffer: Buffer) => { + return deserializeBorsh( + VAULT_SCHEMA, + SafetyDepositBox, + buffer, + ) as SafetyDepositBox; +}; + export async function initVault( allowFurtherShareCreation: boolean, fractionalMint: PublicKey, diff --git a/packages/metavinci/src/components/AuctionCard/index.tsx b/packages/metavinci/src/components/AuctionCard/index.tsx index cae05b3..50d881e 100644 --- a/packages/metavinci/src/components/AuctionCard/index.tsx +++ b/packages/metavinci/src/components/AuctionCard/index.tsx @@ -1,39 +1,46 @@ import React, { useEffect, useState } from 'react'; -import { - Row, - Col, - Divider, - Button, - InputNumber -} from 'antd' +import { Row, Col, Divider, Button, InputNumber } from 'antd'; -import { Auction, Presale } from '../../types' +import { Auction, Presale } from '../../types'; -import './index.less' -import { getCountdown } from '../../utils/utils' -import { shortenAddress } from '@oyster/common'; +import './index.less'; +import { getCountdown } from '../../utils/utils'; +import { shortenAddress, useConnection } from '@oyster/common'; +import { AuctionView } from '../../hooks'; -export const AuctionCard = ({ auction }: { auction: Auction }) => { - const [hours, setHours] = useState(23) - const [minutes, setMinutes] = useState(59) - const [seconds, setSeconds] = useState(59) +export const AuctionCard = ({ auctionView }: { auctionView: AuctionView }) => { + const [hours, setHours] = useState(23); + const [minutes, setMinutes] = useState(59); + const [seconds, setSeconds] = useState(59); + const [clock, setClock] = useState(0); + const connection = useConnection(); + + useEffect(() => { + connection.getSlot().then(setClock); + }, [connection]); useEffect(() => { const interval = setInterval(() => { - const { hours, minutes, seconds } = getCountdown(auction.endingTS) + const slotDiff = + (auctionView.auction.info.endedAt?.toNumber() || 0) - clock; - setHours(hours) - setMinutes(minutes) - setSeconds(seconds) - }, 1000) - return () => clearInterval(interval) - }, []) + /* const { hours, minutes, seconds } = getCountdown( + auctionView.auction.info.endedAt?.toNumber(), + ); + + setHours(hours); + setMinutes(minutes); + setSeconds(seconds);*/ + setHours(1); + }, 1000); + return () => clearInterval(interval); + }, [clock]); return (
STARTING BID
◎40.00
-
+
AUCTION ENDS IN
@@ -49,13 +56,17 @@ export const AuctionCard = ({ auction }: { auction: Auction }) => {
seconds
-
-
- Any bids placed in the last 15 minutes will extend the auction for another 15 minutes. +
+
+ Any bids placed in the last 15 minutes will extend the auction for + another 15 minutes.

-
+
{ // } /> -
+
Your Balance: ◎ {0.0} (${0.0})
- -
- ) -} + ); +}; export const AuctionBidders = (auctionID: string) => { const bids: any[] = []; - return - {bids.map((bid, index) => { - return {index+1}. {shortenAddress(bid.address)} {bid.amount} - })} - + return ( + + {bids.map((bid, index) => { + return ( + + {index + 1}. {shortenAddress(bid.address)} {bid.amount} + + ); + })} + + ); }; diff --git a/packages/metavinci/src/contexts/meta.tsx b/packages/metavinci/src/contexts/meta.tsx index cb64bb3..6799e0d 100644 --- a/packages/metavinci/src/contexts/meta.tsx +++ b/packages/metavinci/src/contexts/meta.tsx @@ -4,6 +4,7 @@ import { useConnection, decodeMetadata, decodeNameSymbolTuple, + decodeAuction, decodeEdition, decodeMasterEdition, Metadata, @@ -15,30 +16,55 @@ import { Edition, MasterEdition, NameSymbolTuple, + AuctionData, + SafetyDepositBox, + VaultKey, + decodeSafetyDeposit, } from '@oyster/common'; import { MintInfo } from '@solana/spl-token'; import { Connection, PublicKey, PublicKeyAndAccount } from '@solana/web3.js'; import BN from 'bn.js'; import React, { useContext, useEffect, useState } from 'react'; +import { + AuctionManager, + AuctionManagerStatus, + decodeAuctionManager, + getAuctionManagerKey, + MetaplexKey, +} from '../models/metaplex'; const { MetadataKey } = actions; export interface MetaContextState { metadata: ParsedAccount[]; + metadataByMint: Record>; nameSymbolTuples: Record>; editions: Record>; masterEditions: Record>; + auctionManagers: Record>; + auctions: Record>; + safetyDepositBoxesByVaultAndIndex: Record< + string, + ParsedAccount + >; } const MetaContext = React.createContext({ metadata: [], + metadataByMint: {}, nameSymbolTuples: {}, masterEditions: {}, editions: {}, + auctionManagers: {}, + auctions: {}, + safetyDepositBoxesByVaultAndIndex: {}, }); export function MetaProvider({ children = null as any }) { const connection = useConnection(); const [metadata, setMetadata] = useState[]>([]); + const [metadataByMint, setMetadataByMint] = useState< + Record> + >({}); const [nameSymbolTuples, setNameSymbolTuples] = useState< Record> >({}); @@ -48,12 +74,181 @@ export function MetaProvider({ children = null as any }) { const [editions, setEditions] = useState< Record> >({}); + const [auctionManagers, setAuctionManagers] = useState< + Record> + >({}); + const [auctions, setAuctions] = useState< + Record> + >({}); + const [ + safetyDepositBoxesByVaultAndIndex, + setSafetyDepositBoxesByVaultAndIndex, + ] = useState>>({}); useEffect(() => { let dispose = () => {}; (async () => { - const mintToMetadata = new Map>(); + const processAuctions = async (a: PublicKeyAndAccount) => { + try { + const auction = await decodeAuction(a.account.data); + auction.auctionManagerKey = await getAuctionManagerKey( + auction.resource, + a.pubkey, + ); + const account: ParsedAccount = { + pubkey: a.pubkey, + account: a.account, + info: auction, + }; + setAuctions(e => ({ + ...e, + [a.pubkey.toBase58()]: account, + })); + } catch { + // ignore errors + // add type as first byte for easier deserialization + } + }; + const accounts = await connection.getProgramAccounts( + programIds().auction, + ); + for (let i = 0; i < accounts.length; i++) { + await processAuctions(accounts[i]); + } + + let subId = connection.onProgramAccountChange( + programIds().auction, + async info => { + const pubkey = + typeof info.accountId === 'string' + ? new PublicKey((info.accountId as unknown) as string) + : info.accountId; + await processAuctions({ + pubkey, + account: info.accountInfo, + }); + }, + ); + dispose = () => { + connection.removeProgramAccountChangeListener(subId); + }; + })(); + + return () => { + dispose(); + }; + }, [connection, setAuctions]); + + useEffect(() => { + let dispose = () => {}; + (async () => { + const processSafetyDeposits = async (a: PublicKeyAndAccount) => { + try { + if (a.account.data[0] == VaultKey.SafetyDepositBoxV1) { + const safetyDeposit = await decodeSafetyDeposit(a.account.data); + const account: ParsedAccount = { + pubkey: a.pubkey, + account: a.account, + info: safetyDeposit, + }; + setSafetyDepositBoxesByVaultAndIndex(e => ({ + ...e, + [safetyDeposit.vault.toBase58() + + '-' + + safetyDeposit.order]: account, + })); + } + } catch { + // ignore errors + // add type as first byte for easier deserialization + } + }; + + const accounts = await connection.getProgramAccounts(programIds().vault); + for (let i = 0; i < accounts.length; i++) { + await processSafetyDeposits(accounts[i]); + } + + let subId = connection.onProgramAccountChange( + programIds().vault, + async info => { + const pubkey = + typeof info.accountId === 'string' + ? new PublicKey((info.accountId as unknown) as string) + : info.accountId; + await processSafetyDeposits({ + pubkey, + account: info.accountInfo, + }); + }, + ); + dispose = () => { + connection.removeProgramAccountChangeListener(subId); + }; + })(); + + return () => { + dispose(); + }; + }, [connection, setSafetyDepositBoxesByVaultAndIndex]); + + useEffect(() => { + let dispose = () => {}; + (async () => { + const processAuctionManagers = async (a: PublicKeyAndAccount) => { + try { + if (a.account.data[0] == MetaplexKey.AuctionManagerV1) { + const auctionManager = await decodeAuctionManager(a.account.data); + const account: ParsedAccount = { + pubkey: a.pubkey, + account: a.account, + info: auctionManager, + }; + setAuctionManagers(e => ({ + ...e, + [a.pubkey.toBase58()]: account, + })); + } + } catch { + // ignore errors + // add type as first byte for easier deserialization + } + }; + + const accounts = await connection.getProgramAccounts( + programIds().metaplex, + ); + for (let i = 0; i < accounts.length; i++) { + await processAuctionManagers(accounts[i]); + } + + let subId = connection.onProgramAccountChange( + programIds().metaplex, + async info => { + const pubkey = + typeof info.accountId === 'string' + ? new PublicKey((info.accountId as unknown) as string) + : info.accountId; + await processAuctionManagers({ + pubkey, + account: info.accountInfo, + }); + }, + ); + dispose = () => { + connection.removeProgramAccountChangeListener(subId); + }; + })(); + + return () => { + dispose(); + }; + }, [connection, setAuctionManagers]); + + useEffect(() => { + let dispose = () => {}; + (async () => { const processMetaData = async (meta: PublicKeyAndAccount) => { try { if (meta.account.data[0] == MetadataKey.MetadataV1) { @@ -67,7 +262,10 @@ export function MetaProvider({ children = null as any }) { account: meta.account, info: metadata, }; - mintToMetadata.set(metadata.mint.toBase58(), account); + setMetadataByMint(e => ({ + ...e, + [metadata.mint.toBase58()]: account, + })); } } else if (meta.account.data[0] == MetadataKey.EditionV1) { const edition = decodeEdition(meta.account.data); @@ -113,20 +311,21 @@ export function MetaProvider({ children = null as any }) { await processMetaData(accounts[i]); } - await queryExtendedMetadata(connection, setMetadata, mintToMetadata); + await queryExtendedMetadata(connection, setMetadata, metadataByMint); let subId = connection.onProgramAccountChange( programIds().metadata, async info => { - const pubkey = typeof info.accountId === 'string' ? - new PublicKey((info.accountId as unknown) as string) : - info.accountId; + const pubkey = + typeof info.accountId === 'string' + ? new PublicKey((info.accountId as unknown) as string) + : info.accountId; await processMetaData({ pubkey, account: info.accountInfo, }); - queryExtendedMetadata(connection, setMetadata, mintToMetadata); + queryExtendedMetadata(connection, setMetadata, metadataByMint); }, ); dispose = () => { @@ -147,7 +346,16 @@ export function MetaProvider({ children = null as any }) { return ( {children} @@ -157,14 +365,14 @@ export function MetaProvider({ children = null as any }) { const queryExtendedMetadata = async ( connection: Connection, setMetadata: (metadata: ParsedAccount[]) => void, - mintToMeta: Map>, + mintToMeta: Record>, ) => { - const mintToMetadata = new Map>(mintToMeta); + const mintToMetadata = { ...mintToMeta }; const extendedMetadataFetch = new Map>(); const mints = await getMultipleAccounts( connection, - [...mintToMetadata.keys()].filter(k => !cache.get(k)), + [...Object.keys(mintToMetadata)].filter(k => !cache.get(k)), 'single', ); mints.keys.forEach((key, index) => { @@ -176,9 +384,9 @@ const queryExtendedMetadata = async ( ) as ParsedAccount; if (mint.info.supply.gt(new BN(1)) || mint.info.decimals !== 0) { // naive not NFT check - mintToMetadata.delete(key); + delete mintToMetadata[key]; } else { - const metadata = mintToMetadata.get(key); + const metadata = mintToMetadata[key]; if (metadata && metadata.info.uri) { extendedMetadataFetch.set( key, @@ -190,19 +398,19 @@ const queryExtendedMetadata = async ( !metadata.info.extended || metadata.info.extended?.files?.length === 0 ) { - mintToMetadata.delete(key); + delete mintToMetadata[key]; } else { if (metadata.info.extended?.image) { metadata.info.extended.image = `${metadata.info.uri}/${metadata.info.extended.image}`; } } } catch { - mintToMetadata.delete(key); + delete mintToMetadata[key]; return undefined; } }) .catch(() => { - mintToMetadata.delete(key); + delete mintToMetadata[key]; return undefined; }), ); @@ -212,7 +420,7 @@ const queryExtendedMetadata = async ( await Promise.all([...extendedMetadataFetch.values()]); - setMetadata([...mintToMetadata.values()]); + setMetadata([...Object.values(mintToMetadata)]); }; export const useMeta = () => { diff --git a/packages/metavinci/src/hooks/useArt.tsx b/packages/metavinci/src/hooks/useArt.ts similarity index 94% rename from packages/metavinci/src/hooks/useArt.tsx rename to packages/metavinci/src/hooks/useArt.ts index cdcf522..4d52f8c 100644 --- a/packages/metavinci/src/hooks/useArt.tsx +++ b/packages/metavinci/src/hooks/useArt.ts @@ -1,6 +1,6 @@ import React, { useMemo } from 'react'; import { PublicKey } from '@solana/web3.js'; -import { useMeta } from './../contexts'; +import { useMeta } from '../contexts'; import { Art } from '../types'; export const useArt = (id: PublicKey | string) => { diff --git a/packages/metavinci/src/hooks/useAuction.ts b/packages/metavinci/src/hooks/useAuction.ts new file mode 100644 index 0000000..510d088 --- /dev/null +++ b/packages/metavinci/src/hooks/useAuction.ts @@ -0,0 +1,45 @@ +import { + ParsedAccount, + Metadata, + SafetyDepositBox, + AuctionData, + useConnection, + AuctionState, +} from '@oyster/common'; +import { useEffect, useState } from 'react'; +import { AuctionView, processAccountsIntoAuctionView } from '.'; +import { useMeta } from '../contexts'; +import { AuctionManager } from '../models/metaplex'; +import { sampleAuction } from '../views/home/sampleData'; + +export const useAuction = (id: string) => { + const connection = useConnection(); + const [clock, setClock] = useState(0); + const [auctionView, setAuctionView] = useState(null); + useEffect(() => { + connection.getSlot().then(setClock); + }, [connection]); + + const { + auctions, + auctionManagers, + safetyDepositBoxesByVaultAndIndex, + metadataByMint, + } = useMeta(); + + useEffect(() => { + const auction = auctions[id]; + if (auction) { + const auctionView = processAccountsIntoAuctionView( + auction, + auctionManagers, + safetyDepositBoxesByVaultAndIndex, + metadataByMint, + clock, + undefined, + ); + if (auctionView) setAuctionView(auctionView); + } + }, [clock]); + return auctionView; +}; diff --git a/packages/metavinci/src/hooks/useAuction.tsx b/packages/metavinci/src/hooks/useAuction.tsx deleted file mode 100644 index f000524..0000000 --- a/packages/metavinci/src/hooks/useAuction.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import React, { useMemo } from 'react'; -import { sampleAuction } from '../views/home/sampleData'; -import { useMeta } from './../contexts'; - -export const useAuction = (id: string) => { - const { metadata } = useMeta(); - - return sampleAuction; -} diff --git a/packages/metavinci/src/hooks/useAuctions.ts b/packages/metavinci/src/hooks/useAuctions.ts new file mode 100644 index 0000000..ea45915 --- /dev/null +++ b/packages/metavinci/src/hooks/useAuctions.ts @@ -0,0 +1,155 @@ +import { + ParsedAccount, + Metadata, + SafetyDepositBox, + AuctionData, + useConnection, + AuctionState, +} from '@oyster/common'; +import { useEffect, useState } from 'react'; +import { useMeta } from '../contexts'; +import { AuctionManager } from '../models/metaplex'; + +export enum AuctionViewState { + Live = '0', + Upcoming = '1', + Ended = '2', + BuyNow = '3', +} + +export interface AuctionViewItem { + metadata: ParsedAccount; + safetyDeposit: ParsedAccount; +} + +// Flattened surface item for easy display +export interface AuctionView { + items: AuctionViewItem[]; + auction: ParsedAccount; + auctionManager: ParsedAccount; + openEditionItem?: AuctionViewItem; + state: AuctionViewState; + thumbnail: AuctionViewItem; +} + +export const useAuctions = (state: AuctionViewState) => { + const connection = useConnection(); + const [clock, setClock] = useState(0); + const [auctionViews, setAuctionViews] = useState([]); + useEffect(() => { + connection.getSlot().then(setClock); + }, [connection]); + + const { + auctions, + auctionManagers, + safetyDepositBoxesByVaultAndIndex, + metadataByMint, + } = useMeta(); + + useEffect(() => { + const newAuctionViews: AuctionView[] = []; + Object.keys(auctions).forEach(a => { + const auction = auctions[a]; + const auctionView = processAccountsIntoAuctionView( + auction, + auctionManagers, + safetyDepositBoxesByVaultAndIndex, + metadataByMint, + clock, + state, + ); + if (auctionView) newAuctionViews.push(auctionView); + }); + setAuctionViews(newAuctionViews); + }, [clock, state, auctions]); + + return auctionViews; +}; + +export function processAccountsIntoAuctionView( + auction: ParsedAccount, + auctionManagers: Record>, + safetyDepositBoxesByVaultAndIndex: Record< + string, + ParsedAccount + >, + metadataByMint: Record>, + clock: number, + desiredState: AuctionViewState | undefined, +) { + let state: AuctionViewState; + if ( + auction.info.state == AuctionState.Ended || + (auction.info.endedAt && auction.info.endedAt.toNumber() <= clock) + ) { + state = AuctionViewState.Ended; + } else if ( + auction.info.state == AuctionState.Started || + (auction.info.endedAt && auction.info.endedAt.toNumber() > clock) + ) { + state = AuctionViewState.Live; + } else if (auction.info.state == AuctionState.Created) { + state = AuctionViewState.Upcoming; + } else { + state = AuctionViewState.BuyNow; + } + + if (desiredState && desiredState != state) return null; + + const auctionManager = + auctionManagers[auction.info.auctionManagerKey?.toBase58() || '']; + if (auctionManager) { + let boxes: ParsedAccount[] = []; + let box = + safetyDepositBoxesByVaultAndIndex[ + auctionManager.info.vault.toBase58() + '-0' + ]; + if (box) { + boxes.push(box); + let i = 1; + while (box) { + box = + safetyDepositBoxesByVaultAndIndex[ + auctionManager.info.vault.toBase58() + '-' + i.toString() + ]; + if (box) boxes.push(box); + i++; + } + } + + if (boxes.length > 0) { + let view: any = { + auction, + auctionManager, + state, + items: auctionManager.info.settings.winningConfigs.map(w => ({ + metadata: + metadataByMint[ + boxes[w.safetyDepositBoxIndex].info.tokenMint.toBase58() + ], + safetyDeposit: boxes[w.safetyDepositBoxIndex], + })), + openEditionItem: + auctionManager.info.settings.openEditionConfig != null + ? { + metadata: + metadataByMint[ + boxes[ + auctionManager.info.settings.openEditionConfig + ].info.tokenMint.toBase58() + ], + safetyDeposit: + boxes[auctionManager.info.settings.openEditionConfig], + } + : undefined, + }; + + view.thumbnail = view.items[0] || view.openEditionItem; + if (!view.thumbnail || !view.thumbnail.metadata) return null; + return view; + } + } + + return null; +} diff --git a/packages/metavinci/src/hooks/useAuctions.tsx b/packages/metavinci/src/hooks/useAuctions.tsx deleted file mode 100644 index 393bc9c..0000000 --- a/packages/metavinci/src/hooks/useAuctions.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import React, { useMemo } from 'react'; -import { useMeta } from './../contexts'; - -export enum AuctionState { - Live = '0', - Upcoming = '1', - Ended = '2', - BuyNow = '3', -} - -export const useAuctions = (state: AuctionState) => { - const { metadata } = useMeta(); - - return metadata; -} diff --git a/packages/metavinci/src/hooks/useUserArts.tsx b/packages/metavinci/src/hooks/useUserArts.ts similarity index 100% rename from packages/metavinci/src/hooks/useUserArts.tsx rename to packages/metavinci/src/hooks/useUserArts.ts diff --git a/packages/metavinci/src/models/metaplex/index.ts b/packages/metavinci/src/models/metaplex/index.ts index 76ec495..e863bb5 100644 --- a/packages/metavinci/src/models/metaplex/index.ts +++ b/packages/metavinci/src/models/metaplex/index.ts @@ -140,6 +140,9 @@ export class WinningConfig { Object.assign(this, args); } } +export const decodeAuctionManager = (buffer: Buffer) => { + return deserializeBorsh(SCHEMA, AuctionManager, buffer) as AuctionManager; +}; export class WinningConfigState { amountMinted: number = 0; @@ -313,6 +316,20 @@ export const SCHEMA = new Map([ ], ]); +export async function getAuctionManagerKey( + vault: PublicKey, + auctionKey: PublicKey, +): Promise { + const PROGRAM_IDS = programIds(); + + return ( + await PublicKey.findProgramAddress( + [Buffer.from(METAPLEX_PREFIX), auctionKey.toBuffer()], + PROGRAM_IDS.metaplex, + ) + )[0]; +} + export async function getAuctionKeys( vault: PublicKey, ): Promise<{ auctionKey: PublicKey; auctionManagerKey: PublicKey }> { @@ -329,12 +346,7 @@ export async function getAuctionKeys( ) )[0]; - const auctionManagerKey: PublicKey = ( - await PublicKey.findProgramAddress( - [Buffer.from(METAPLEX_PREFIX), auctionKey.toBuffer()], - PROGRAM_IDS.metaplex, - ) - )[0]; + const auctionManagerKey = await getAuctionManagerKey(vault, auctionKey); return { auctionKey, auctionManagerKey }; } diff --git a/packages/metavinci/src/views/auction/index.tsx b/packages/metavinci/src/views/auction/index.tsx index f3262ab..c5e69b9 100644 --- a/packages/metavinci/src/views/auction/index.tsx +++ b/packages/metavinci/src/views/auction/index.tsx @@ -1,32 +1,40 @@ import React from 'react'; import { useParams } from 'react-router-dom'; -import { Row, Col, Divider, Layout, Image } from 'antd'; +import { Row, Col, Divider, Layout, Image, Spin } from 'antd'; import { AuctionCard } from '../../components/AuctionCard'; import { useArt, useAuction } from '../../hooks'; import { ArtContent } from '../../components/ArtContent'; import { sampleArtist } from '../home/sampleData'; -const { Content } = Layout +const { Content } = Layout; export const AuctionView = () => { const { id } = useParams<{ id: string }>(); const auction = useAuction(id); const art = useArt(id); - const artist = sampleArtist + const artist = sampleArtist; return ( - + - - + +
{art.title}

CREATED BY
-
@{art.artist}
+
+ @{art.artist} +

CREATOR ROYALTIES
{art.royalties}%
@@ -38,7 +46,7 @@ export const AuctionView = () => {
{artist.about}
- + {auction ? : }
diff --git a/packages/metavinci/src/views/auctionCreate/index.tsx b/packages/metavinci/src/views/auctionCreate/index.tsx index 2ff37c3..aa5f4d3 100644 --- a/packages/metavinci/src/views/auctionCreate/index.tsx +++ b/packages/metavinci/src/views/auctionCreate/index.tsx @@ -129,7 +129,7 @@ export const AuctionCreateView = () => { const [attributes, setAttributes] = useState({ reservationPrice: 0, items: [], - category: AuctionCategory.Open, + category: AuctionCategory.Single, saleType: 'auction', winnersCount: 1, }); @@ -161,6 +161,7 @@ export const AuctionCreateView = () => { usize: ZERO, }); } else if (attributes.category == AuctionCategory.Single) { + console.log('Using single'); settings = new AuctionManagerSettings({ openEditionWinnerConstraint: WinningConstraint.NoOpenEdition, openEditionNonWinningConstraint: NonWinningConstraint.NoOpenEdition, diff --git a/packages/metavinci/src/views/home/index.tsx b/packages/metavinci/src/views/home/index.tsx index 4d9f1dc..1748d36 100644 --- a/packages/metavinci/src/views/home/index.tsx +++ b/packages/metavinci/src/views/home/index.tsx @@ -1,52 +1,58 @@ -import React, { useState } from 'react' -import { Layout, Row, Col, Tabs } from 'antd' -import Masonry from 'react-masonry-css' +import React, { useState } from 'react'; +import { Layout, Row, Col, Tabs } from 'antd'; +import Masonry from 'react-masonry-css'; -import { PreSaleBanner } from '../../components/PreSaleBanner' -import { AuctionState, useAuctions } from '../../hooks' +import { PreSaleBanner } from '../../components/PreSaleBanner'; +import { AuctionViewState, useAuctions } from '../../hooks'; -import './index.less' -import { ArtCard } from '../../components/ArtCard' -import { Link } from 'react-router-dom' +import './index.less'; +import { ArtCard } from '../../components/ArtCard'; +import { Link } from 'react-router-dom'; const { TabPane } = Tabs; -const { Content } = Layout +const { Content } = Layout; export const HomeView = () => { - const [activeKey, setActiveKey] = useState(AuctionState.Live); - const auctions = useAuctions(AuctionState.Live) - + const [activeKey, setActiveKey] = useState(AuctionViewState.Live); + const auctions = useAuctions(activeKey); + console.log('Auctions', auctions); const breakpointColumnsObj = { default: 4, 1100: 3, 700: 2, - 500: 1 - } + 500: 1, + }; - const auctionGrid = - {auctions.map(m => { - const id = m.pubkey.toBase58(); - return - - - })} - ; + {auctions.map(m => { + const id = m.auction.pubkey.toBase58(); + return ( + + + + ); + })} + + ); return ( @@ -54,28 +60,31 @@ export const HomeView = () => { - setActiveKey(key as AuctionState)}> + setActiveKey(key as AuctionViewState)} + > Live} - key={AuctionState.Live} + key={AuctionViewState.Live} > {auctionGrid} Upcoming} - key={AuctionState.Upcoming} + key={AuctionViewState.Upcoming} > {auctionGrid} Ended} - key={AuctionState.Ended} + key={AuctionViewState.Ended} > {auctionGrid} Buy Now} - key={AuctionState.BuyNow} + key={AuctionViewState.BuyNow} > {auctionGrid}