diff --git a/packages/common/src/actions/auction.ts b/packages/common/src/actions/auction.ts index 9ef6aa5..75dd1fd 100644 --- a/packages/common/src/actions/auction.ts +++ b/packages/common/src/actions/auction.ts @@ -38,6 +38,11 @@ export class BidState { bids?: Bid[]; max?: BN; + public getWinnerIndex(bidder: PublicKey): number | null { + if (!this.bids) return null; + return this.bids.findIndex(b => b.key.toBase58() == bidder.toBase58()); + } + constructor(args: { type: BidStateType; bids?: Bid[]; max?: BN }) { this.type = args.type; this.bids = args.bids; diff --git a/packages/common/src/actions/metadata.ts b/packages/common/src/actions/metadata.ts index ed9c136..bb62200 100644 --- a/packages/common/src/actions/metadata.ts +++ b/packages/common/src/actions/metadata.ts @@ -630,6 +630,107 @@ export async function createMasterEdition( ); } +export async function mintNewEditionFromMasterEditionViaToken( + newMint: PublicKey, + tokenMint: PublicKey, + newMintAuthority: PublicKey, + masterMint: PublicKey, + authorizationTokenHoldingAccount: PublicKey, + burnAuthority: PublicKey, + updateAuthorityOfMaster: PublicKey, + instructions: TransactionInstruction[], + payer: PublicKey, +) { + const metadataProgramId = programIds().metadata; + + const newMetadataKey = await getMetadata(newMint); + const masterMetadataKey = await getMetadata(tokenMint); + const newEdition = await getEdition(newMint); + const masterEdition = await getEdition(tokenMint); + + const data = Buffer.from('5'); + + const keys = [ + { + pubkey: newMetadataKey, + isSigner: false, + isWritable: true, + }, + { + pubkey: newEdition, + isSigner: false, + isWritable: true, + }, + { + pubkey: masterEdition, + isSigner: false, + isWritable: true, + }, + { + pubkey: newMint, + isSigner: false, + isWritable: true, + }, + { + pubkey: newMintAuthority, + isSigner: true, + isWritable: false, + }, + { + pubkey: masterMint, + isSigner: false, + isWritable: true, + }, + { + pubkey: authorizationTokenHoldingAccount, + isSigner: false, + isWritable: true, + }, + { + pubkey: burnAuthority, + isSigner: true, + isWritable: false, + }, + { + pubkey: payer, + isSigner: true, + isWritable: false, + }, + { + pubkey: updateAuthorityOfMaster, + isSigner: false, + isWritable: false, + }, + { + pubkey: masterMetadataKey, + isSigner: false, + isWritable: false, + }, + { + pubkey: programIds().token, + isSigner: false, + isWritable: false, + }, + { + pubkey: SystemProgram.programId, + isSigner: false, + isWritable: false, + }, + { + pubkey: SYSVAR_RENT_PUBKEY, + isSigner: false, + isWritable: false, + }, + ]; + instructions.push( + new TransactionInstruction({ + keys, + programId: metadataProgramId, + data, + }), + ); +} + export async function getNameSymbol(metadata: Metadata): Promise { const PROGRAM_IDS = programIds(); @@ -662,3 +763,18 @@ export async function getEdition(tokenMint: PublicKey): Promise { ) )[0]; } + +export async function getMetadata(tokenMint: PublicKey): Promise { + const PROGRAM_IDS = programIds(); + + return ( + await PublicKey.findProgramAddress( + [ + Buffer.from(METADATA_PREFIX), + PROGRAM_IDS.metadata.toBuffer(), + tokenMint.toBuffer(), + ], + PROGRAM_IDS.metadata, + ) + )[0]; +} diff --git a/packages/metavinci/src/actions/createAuctionManager.ts b/packages/metavinci/src/actions/createAuctionManager.ts index 94daf33..552cb21 100644 --- a/packages/metavinci/src/actions/createAuctionManager.ts +++ b/packages/metavinci/src/actions/createAuctionManager.ts @@ -11,6 +11,7 @@ import { WinnerLimit, MasterEdition, NameSymbolTuple, + getMetadata, SequenceType, sendTransactions, getSafetyDepositBox, @@ -22,7 +23,6 @@ import BN from 'bn.js'; import { AuctionManagerSettings, getAuctionKeys, - getMetadata, initAuctionManager, startAuction, validateSafetyDepositBox, diff --git a/packages/metavinci/src/actions/sendRedeemBid.ts b/packages/metavinci/src/actions/sendRedeemBid.ts new file mode 100644 index 0000000..3528098 --- /dev/null +++ b/packages/metavinci/src/actions/sendRedeemBid.ts @@ -0,0 +1,448 @@ +import { + Account, + Connection, + PublicKey, + TransactionInstruction, +} from '@solana/web3.js'; +import { + actions, + ParsedAccount, + programIds, + models, + TokenAccount, + getNameSymbol, + createMint, + mintNewEditionFromMasterEditionViaToken, + SafetyDepositBox, +} from '@oyster/common'; + +import { AccountLayout, MintLayout, Token } from '@solana/spl-token'; +import { AuctionView, AuctionViewItem } from '../hooks'; +import { + EditionType, + getOriginalAuthority, + NonWinningConstraint, + redeemBid, + redeemLimitedEditionBid, + redeemMasterEditionBid, + redeemOpenEditionBid, + WinningConstraint, +} from '../models/metaplex'; +const { createTokenAccount } = actions; +const { approve } = models; + +export async function sendRedeemBid( + connection: Connection, + wallet: any, + auctionView: AuctionView, + accountsByMint: Map, +) { + let signers: Array = []; + let instructions: Array = []; + + const accountRentExempt = await connection.getMinimumBalanceForRentExemption( + AccountLayout.span, + ); + + const mintRentExempt = await connection.getMinimumBalanceForRentExemption( + MintLayout.span, + ); + + let winnerIndex = null; + if (auctionView.myBidderMetadata?.info.bidderPubkey) + winnerIndex = auctionView.auction.info.bidState.getWinnerIndex( + auctionView.myBidderMetadata?.info.bidderPubkey, + ); + + if (winnerIndex != null) { + const winningConfig = + auctionView.auctionManager.info.settings.winningConfigs[winnerIndex]; + const item = auctionView.items[winningConfig.safetyDepositBoxIndex]; + const safetyDeposit = item.safetyDeposit; + let newTokenAccount: PublicKey | undefined; + switch (winningConfig.editionType) { + case EditionType.LimitedEdition: + await setupRedeemLimitedInstructions( + connection, + auctionView, + accountsByMint, + accountRentExempt, + mintRentExempt, + wallet, + safetyDeposit, + item, + signers, + instructions, + ); + break; + case EditionType.MasterEdition: + await setupRedeemMasterInstructions( + auctionView, + accountsByMint, + accountRentExempt, + wallet, + safetyDeposit, + item, + signers, + instructions, + ); + break; + case EditionType.NA: + await setupRedeemInstructions( + auctionView, + accountsByMint, + accountRentExempt, + wallet, + safetyDeposit, + signers, + instructions, + ); + break; + } + } + + const eligibleForOpenEdition = + (winnerIndex == null && + auctionView.auctionManager.info.settings + .openEditionNonWinningConstraint != + NonWinningConstraint.NoOpenEdition) || + (winnerIndex != null && + auctionView.auctionManager.info.settings.openEditionWinnerConstraint != + WinningConstraint.NoOpenEdition); + if (auctionView.openEditionItem && eligibleForOpenEdition) { + const item = auctionView.openEditionItem; + const safetyDeposit = item.safetyDeposit; + await setupRedeemOpenInstructions( + auctionView, + accountsByMint, + accountRentExempt, + mintRentExempt, + wallet, + safetyDeposit, + item, + signers, + instructions, + ); + } +} + +async function setupRedeemInstructions( + auctionView: AuctionView, + accountsByMint: Map, + accountRentExempt: number, + wallet: any, + safetyDeposit: ParsedAccount, + signers: Array, + instructions: Array, +) { + let winningPrizeSigner: Account[] = []; + let winningPrizeInstructions: TransactionInstruction[] = []; + + signers.push(winningPrizeSigner); + instructions.push(winningPrizeInstructions); + if (auctionView.myBidderMetadata) { + let newTokenAccount = accountsByMint.get( + safetyDeposit.info.tokenMint.toBase58(), + )?.pubkey; + if (!newTokenAccount) + newTokenAccount = createTokenAccount( + winningPrizeInstructions, + wallet.publicKey, + accountRentExempt, + safetyDeposit.info.tokenMint, + wallet.publicKey, + winningPrizeSigner, + ); + + await redeemBid( + auctionView.auctionManager.info.vault, + safetyDeposit.info.store, + newTokenAccount, + safetyDeposit.pubkey, + auctionView.vault.info.fractionMint, + auctionView.myBidderMetadata.info.bidderPubkey, + wallet.publicKey, + winningPrizeInstructions, + ); + } +} + +async function setupRedeemMasterInstructions( + auctionView: AuctionView, + accountsByMint: Map, + accountRentExempt: number, + wallet: any, + safetyDeposit: ParsedAccount, + item: AuctionViewItem, + signers: Array, + instructions: Array, +) { + let winningPrizeSigner: Account[] = []; + let winningPrizeInstructions: TransactionInstruction[] = []; + + signers.push(winningPrizeSigner); + instructions.push(winningPrizeInstructions); + if (auctionView.myBidderMetadata) { + let newTokenAccount = accountsByMint.get( + safetyDeposit.info.tokenMint.toBase58(), + )?.pubkey; + if (!newTokenAccount) + newTokenAccount = createTokenAccount( + winningPrizeInstructions, + wallet.publicKey, + accountRentExempt, + safetyDeposit.info.tokenMint, + wallet.publicKey, + winningPrizeSigner, + ); + + await redeemMasterEditionBid( + auctionView.auctionManager.info.vault, + safetyDeposit.info.store, + newTokenAccount, + safetyDeposit.pubkey, + auctionView.vault.info.fractionMint, + auctionView.myBidderMetadata.info.bidderPubkey, + wallet.publicKey, + winningPrizeInstructions, + item.metadata.pubkey, + await getNameSymbol(item.metadata.info), + wallet.publicKey, + ); + } +} + +async function setupRedeemLimitedInstructions( + connection: Connection, + auctionView: AuctionView, + accountsByMint: Map, + accountRentExempt: number, + mintRentExempt: number, + wallet: any, + safetyDeposit: ParsedAccount, + item: AuctionViewItem, + signers: Array, + instructions: Array, +) { + let winningPrizeSigner: Account[] = []; + let winningPrizeInstructions: TransactionInstruction[] = []; + + signers.push(winningPrizeSigner); + instructions.push(winningPrizeInstructions); + const updateAuth = + item.metadata.info.nonUniqueSpecificUpdateAuthority || + item.nameSymbol?.info.updateAuthority; + + if (item.masterEdition && updateAuth && auctionView.myBidderMetadata) { + let newTokenAccount: PublicKey | undefined = accountsByMint.get( + item.masterEdition.info.masterMint.toBase58(), + )?.pubkey; + if (!newTokenAccount) + newTokenAccount = createTokenAccount( + winningPrizeInstructions, + wallet.publicKey, + accountRentExempt, + item.masterEdition.info.masterMint, + wallet.publicKey, + winningPrizeSigner, + ); + const originalAuthorityAcct = await connection.getAccountInfo( + await getOriginalAuthority( + auctionView.auction.pubkey, + item.metadata.pubkey, + ), + ); + if (originalAuthorityAcct) { + const originalAuthority = new PublicKey( + originalAuthorityAcct.data.slice(1, 33), + ); + + await redeemLimitedEditionBid( + auctionView.auctionManager.info.vault, + safetyDeposit.info.store, + newTokenAccount, + safetyDeposit.pubkey, + auctionView.vault.info.fractionMint, + auctionView.myBidderMetadata.info.bidderPubkey, + wallet.publicKey, + winningPrizeInstructions, + originalAuthority, + item.metadata.info.mint, + item.masterEdition.info.masterMint, + ); + + let cashInLimitedPrizeAuthorizationTokenSigner: Account[] = []; + let cashInLimitedPrizeAuthorizationTokenInstruction: TransactionInstruction[] = []; + signers.push(cashInLimitedPrizeAuthorizationTokenSigner); + instructions.push(cashInLimitedPrizeAuthorizationTokenInstruction); + + const newLimitedEditionMint = createMint( + cashInLimitedPrizeAuthorizationTokenInstruction, + wallet.publicKey, + mintRentExempt, + 0, + wallet.publicKey, + wallet.publicKey, + cashInLimitedPrizeAuthorizationTokenSigner, + ); + const newLimitedEdition = createTokenAccount( + cashInLimitedPrizeAuthorizationTokenInstruction, + wallet.publicKey, + accountRentExempt, + newLimitedEditionMint, + wallet.publicKey, + cashInLimitedPrizeAuthorizationTokenSigner, + ); + + cashInLimitedPrizeAuthorizationTokenInstruction.push( + Token.createMintToInstruction( + programIds().token, + newLimitedEditionMint, + newLimitedEdition, + wallet.publicKey, + [], + 1, + ), + ); + + const burnAuthority = approve( + cashInLimitedPrizeAuthorizationTokenInstruction, + [], + newTokenAccount, + wallet.publicKey, + 1, + ); + + cashInLimitedPrizeAuthorizationTokenSigner.push(burnAuthority); + + mintNewEditionFromMasterEditionViaToken( + newLimitedEditionMint, + item.metadata.info.mint, + wallet.publicKey, + item.masterEdition.info.masterMint, + newTokenAccount, + burnAuthority.publicKey, + updateAuth, + cashInLimitedPrizeAuthorizationTokenInstruction, + wallet.publicKey, + ); + } + } +} + +async function setupRedeemOpenInstructions( + auctionView: AuctionView, + accountsByMint: Map, + accountRentExempt: number, + mintRentExempt: number, + wallet: any, + safetyDeposit: ParsedAccount, + item: AuctionViewItem, + signers: Array, + instructions: Array, +) { + let winningPrizeSigner: Account[] = []; + let winningPrizeInstructions: TransactionInstruction[] = []; + + signers.push(winningPrizeSigner); + instructions.push(winningPrizeInstructions); + const updateAuth = + item.metadata.info.nonUniqueSpecificUpdateAuthority || + item.nameSymbol?.info.updateAuthority; + + if (item.masterEdition && updateAuth && auctionView.myBidderMetadata) { + let newTokenAccount: PublicKey | undefined = accountsByMint.get( + item.masterEdition.info.masterMint.toBase58(), + )?.pubkey; + if (!newTokenAccount) + newTokenAccount = createTokenAccount( + winningPrizeInstructions, + wallet.publicKey, + accountRentExempt, + item.masterEdition.info.masterMint, + wallet.publicKey, + winningPrizeSigner, + ); + + const transferAuthority = approve( + winningPrizeInstructions, + [], + auctionView.myBidderMetadata.info.bidderPubkey, + wallet.publicKey, + auctionView.auctionManager.info.settings.openEditionFixedPrice || 0, + ); + + winningPrizeSigner.push(transferAuthority); + + await redeemOpenEditionBid( + auctionView.auctionManager.info.vault, + safetyDeposit.info.store, + newTokenAccount, + safetyDeposit.pubkey, + auctionView.vault.info.fractionMint, + auctionView.myBidderMetadata.info.bidderPubkey, + wallet.publicKey, + winningPrizeInstructions, + item.metadata.info.mint, + item.masterEdition.info.masterMint, + transferAuthority.publicKey, + auctionView.auctionManager.info.acceptPayment, + ); + + let cashInOpenPrizeAuthorizationTokenSigner: Account[] = []; + let cashInOpenPrizeAuthorizationTokenInstruction: TransactionInstruction[] = []; + signers.push(cashInOpenPrizeAuthorizationTokenSigner); + instructions.push(cashInOpenPrizeAuthorizationTokenInstruction); + + const newOpenEditionMint = createMint( + cashInOpenPrizeAuthorizationTokenInstruction, + wallet.publicKey, + mintRentExempt, + 0, + wallet.publicKey, + wallet.publicKey, + cashInOpenPrizeAuthorizationTokenSigner, + ); + const newOpenEdition = createTokenAccount( + cashInOpenPrizeAuthorizationTokenInstruction, + wallet.publicKey, + accountRentExempt, + newOpenEditionMint, + wallet.publicKey, + cashInOpenPrizeAuthorizationTokenSigner, + ); + + cashInOpenPrizeAuthorizationTokenInstruction.push( + Token.createMintToInstruction( + programIds().token, + newOpenEditionMint, + newOpenEdition, + wallet.publicKey, + [], + 1, + ), + ); + + const burnAuthority = approve( + cashInOpenPrizeAuthorizationTokenInstruction, + [], + newTokenAccount, + wallet.publicKey, + 1, + ); + + cashInOpenPrizeAuthorizationTokenSigner.push(burnAuthority); + + mintNewEditionFromMasterEditionViaToken( + newOpenEditionMint, + item.metadata.info.mint, + wallet.publicKey, + item.masterEdition.info.masterMint, + newTokenAccount, + burnAuthority.publicKey, + updateAuth, + cashInOpenPrizeAuthorizationTokenInstruction, + wallet.publicKey, + ); + } +} diff --git a/packages/metavinci/src/contexts/meta.tsx b/packages/metavinci/src/contexts/meta.tsx index a44ebdd..aefbbd5 100644 --- a/packages/metavinci/src/contexts/meta.tsx +++ b/packages/metavinci/src/contexts/meta.tsx @@ -26,6 +26,8 @@ import { decodeBidderPot, BIDDER_METADATA_LEN, BIDDER_POT_LEN, + decodeVault, + Vault, } from '@oyster/common'; import { MintInfo } from '@solana/spl-token'; import { Connection, PublicKey, PublicKeyAndAccount } from '@solana/web3.js'; @@ -48,6 +50,7 @@ export interface MetaContextState { masterEditions: Record>; auctionManagers: Record>; auctions: Record>; + vaults: Record>; bidderMetadataByAuctionAndBidder: Record< string, ParsedAccount @@ -67,6 +70,7 @@ const MetaContext = React.createContext({ editions: {}, auctionManagers: {}, auctions: {}, + vaults: {}, bidderMetadataByAuctionAndBidder: {}, safetyDepositBoxesByVaultAndIndex: {}, bidderPotsByAuctionAndBidder: {}, @@ -93,6 +97,9 @@ export function MetaProvider({ children = null as any }) { const [auctions, setAuctions] = useState< Record> >({}); + const [vaults, setVaults] = useState>>( + {}, + ); const [ bidderMetadataByAuctionAndBidder, setBidderMetadataByAuctionAndBidder, @@ -204,7 +211,7 @@ export function MetaProvider({ children = null as any }) { useEffect(() => { let dispose = () => {}; (async () => { - const processSafetyDeposits = async (a: PublicKeyAndAccount) => { + const processVaultData = async (a: PublicKeyAndAccount) => { try { if (a.account.data[0] == VaultKey.SafetyDepositBoxV1) { const safetyDeposit = await decodeSafetyDeposit(a.account.data); @@ -219,6 +226,17 @@ export function MetaProvider({ children = null as any }) { '-' + safetyDeposit.order]: account, })); + } else if (a.account.data[0] == VaultKey.VaultV1) { + const vault = await decodeVault(a.account.data); + const account: ParsedAccount = { + pubkey: a.pubkey, + account: a.account, + info: vault, + }; + setVaults(e => ({ + ...e, + [a.pubkey.toBase58()]: account, + })); } } catch { // ignore errors @@ -228,7 +246,7 @@ export function MetaProvider({ children = null as any }) { const accounts = await connection.getProgramAccounts(programIds().vault); for (let i = 0; i < accounts.length; i++) { - await processSafetyDeposits(accounts[i]); + await processVaultData(accounts[i]); } let subId = connection.onProgramAccountChange( @@ -238,7 +256,7 @@ export function MetaProvider({ children = null as any }) { typeof info.accountId === 'string' ? new PublicKey((info.accountId as unknown) as string) : info.accountId; - await processSafetyDeposits({ + await processVaultData({ pubkey, account: info.accountInfo, }); @@ -433,6 +451,7 @@ export function MetaProvider({ children = null as any }) { safetyDepositBoxesByVaultAndIndex, bidderMetadataByAuctionAndBidder, bidderPotsByAuctionAndBidder, + vaults, }} > {children} diff --git a/packages/metavinci/src/hooks/useAuction.ts b/packages/metavinci/src/hooks/useAuction.ts index 2619b24..0f02982 100644 --- a/packages/metavinci/src/hooks/useAuction.ts +++ b/packages/metavinci/src/hooks/useAuction.ts @@ -25,6 +25,9 @@ export const useAuction = (id: string) => { metadataByMint, bidderMetadataByAuctionAndBidder, bidderPotsByAuctionAndBidder, + masterEditions, + nameSymbolTuples, + vaults, } = useMeta(); useEffect(() => { @@ -35,8 +38,11 @@ export const useAuction = (id: string) => { auctionManagers, safetyDepositBoxesByVaultAndIndex, metadataByMint, + nameSymbolTuples, bidderMetadataByAuctionAndBidder, bidderPotsByAuctionAndBidder, + masterEditions, + vaults, accountByMint, clock, undefined, @@ -52,6 +58,9 @@ export const useAuction = (id: string) => { metadataByMint, bidderMetadataByAuctionAndBidder, bidderPotsByAuctionAndBidder, + vaults, + nameSymbolTuples, + masterEditions, userAccounts, ]); return existingAuctionView; diff --git a/packages/metavinci/src/hooks/useAuctions.ts b/packages/metavinci/src/hooks/useAuctions.ts index f477471..dcb307b 100644 --- a/packages/metavinci/src/hooks/useAuctions.ts +++ b/packages/metavinci/src/hooks/useAuctions.ts @@ -7,9 +7,11 @@ import { AuctionState, BidderMetadata, BidderPot, - useWallet, useUserAccounts, TokenAccount, + Vault, + MasterEdition, + NameSymbolTuple, } from '@oyster/common'; import { useEffect, useState } from 'react'; import { useMeta } from '../contexts'; @@ -24,7 +26,9 @@ export enum AuctionViewState { export interface AuctionViewItem { metadata: ParsedAccount; + nameSymbol?: ParsedAccount; safetyDeposit: ParsedAccount; + masterEdition?: ParsedAccount; } // Flattened surface item for easy display @@ -37,6 +41,7 @@ export interface AuctionView { thumbnail: AuctionViewItem; myBidderMetadata?: ParsedAccount; myBidderPot?: ParsedAccount; + vault: ParsedAccount; totallyComplete: boolean; } @@ -63,6 +68,9 @@ export const useAuctions = (state: AuctionViewState) => { metadataByMint, bidderMetadataByAuctionAndBidder, bidderPotsByAuctionAndBidder, + vaults, + nameSymbolTuples, + masterEditions, } = useMeta(); useEffect(() => { @@ -75,8 +83,11 @@ export const useAuctions = (state: AuctionViewState) => { auctionManagers, safetyDepositBoxesByVaultAndIndex, metadataByMint, + nameSymbolTuples, bidderMetadataByAuctionAndBidder, bidderPotsByAuctionAndBidder, + masterEditions, + vaults, accountByMint, clock, state, @@ -94,6 +105,9 @@ export const useAuctions = (state: AuctionViewState) => { bidderMetadataByAuctionAndBidder, bidderPotsByAuctionAndBidder, userAccounts, + vaults, + nameSymbolTuples, + masterEditions, ]); return Object.values(auctionViews).filter(v => v) as AuctionView[]; @@ -107,11 +121,14 @@ export function processAccountsIntoAuctionView( ParsedAccount >, metadataByMint: Record>, + nameSymbolTuples: Record>, bidderMetadataByAuctionAndBidder: Record< string, ParsedAccount >, bidderPotsByAuctionAndBidder: Record>, + masterEditions: Record>, + vaults: Record>, accountByMint: Map, clock: number, desiredState: AuctionViewState | undefined, @@ -156,6 +173,34 @@ export function processAccountsIntoAuctionView( // and only update the two things that could possibly change existingAuctionView.myBidderPot = bidderPot; existingAuctionView.myBidderMetadata = bidderMetadata; + for (let i = 0; i < existingAuctionView.items.length; i++) { + let curr = existingAuctionView.items[i]; + if (!curr.metadata) { + let foundMetadata = + metadataByMint[curr.safetyDeposit.info.tokenMint.toBase58()]; + curr.metadata = foundMetadata; + if ( + curr.metadata && + !curr.nameSymbol && + curr.metadata.info.nameSymbolTuple + ) { + let foundNS = + nameSymbolTuples[curr.metadata.info.nameSymbolTuple.toBase58()]; + curr.nameSymbol = foundNS; + } + + if ( + curr.metadata && + !curr.masterEdition && + curr.metadata.info.masterEdition + ) { + let foundMaster = + masterEditions[curr.metadata.info.masterEdition.toBase58()]; + curr.masterEdition = foundMaster; + } + } + } + return existingAuctionView; } @@ -183,13 +228,23 @@ export function processAccountsIntoAuctionView( auction, auctionManager, state, - items: auctionManager.info.settings.winningConfigs.map(w => ({ - metadata: + vault: vaults[auctionManager.info.vault.toBase58()], + items: auctionManager.info.settings.winningConfigs.map(w => { + let metadata = metadataByMint[ boxes[w.safetyDepositBoxIndex].info.tokenMint.toBase58() - ], - safetyDeposit: boxes[w.safetyDepositBoxIndex], - })), + ]; + return { + metadata, + nameSymbol: metadata?.info?.nameSymbolTuple + ? nameSymbolTuples[metadata.info.nameSymbolTuple.toBase58()] + : undefined, + safetyDeposit: boxes[w.safetyDepositBoxIndex], + masterEdition: metadata?.info?.masterEdition + ? masterEditions[metadata.info.masterEdition.toBase58()] + : undefined, + }; + }), openEditionItem: auctionManager.info.settings.openEditionConfig != null ? { @@ -213,7 +268,8 @@ export function processAccountsIntoAuctionView( boxesExpected == (view.items || []).length && (auctionManager.info.settings.openEditionConfig == null || (auctionManager.info.settings.openEditionConfig != null && - view.openEditionItem)) + view.openEditionItem)) && + view.vault ); if (!view.thumbnail || !view.thumbnail.metadata) return undefined; return view as AuctionView; diff --git a/packages/metavinci/src/models/metaplex/index.ts b/packages/metavinci/src/models/metaplex/index.ts index e863bb5..e14991f 100644 --- a/packages/metavinci/src/models/metaplex/index.ts +++ b/packages/metavinci/src/models/metaplex/index.ts @@ -18,6 +18,7 @@ export * from './startAuction'; export * from './validateSafetyDepositBox'; export const METAPLEX_PREFIX = 'metaplex'; +export const ORIGINAL_AUTHORITY_LOOKUP_SIZE = 33; export enum MetaplexKey { AuctionManagerV1 = 0, @@ -111,14 +112,14 @@ export class AuctionManagerSettings { } export enum WinningConstraint { - NoOpenEdition, - OpenEditionGiven, + NoOpenEdition = 0, + OpenEditionGiven = 1, } export enum NonWinningConstraint { - NoOpenEdition, - GivenForFixedPrice, - GivenForBidPrice, + NoOpenEdition = 0, + GivenForFixedPrice = 1, + GivenForBidPrice = 2, } export enum EditionType { @@ -400,18 +401,3 @@ export async function getOriginalAuthority( ) )[0]; } - -export async function getMetadata(tokenMint: PublicKey): Promise { - const PROGRAM_IDS = programIds(); - - return ( - await PublicKey.findProgramAddress( - [ - Buffer.from(METADATA_PREFIX), - PROGRAM_IDS.metadata.toBuffer(), - tokenMint.toBuffer(), - ], - PROGRAM_IDS.metadata, - ) - )[0]; -} diff --git a/packages/metavinci/src/models/metaplex/redeemLimitedEditionBid.ts b/packages/metavinci/src/models/metaplex/redeemLimitedEditionBid.ts index 154d71f..e649e60 100644 --- a/packages/metavinci/src/models/metaplex/redeemLimitedEditionBid.ts +++ b/packages/metavinci/src/models/metaplex/redeemLimitedEditionBid.ts @@ -1,4 +1,4 @@ -import { getEdition, programIds } from '@oyster/common'; +import { getEdition, programIds, getMetadata } from '@oyster/common'; import { PublicKey, SystemProgram, @@ -11,7 +11,6 @@ import { serialize } from 'borsh'; import { getAuctionKeys, getBidderKeys, - getMetadata, getOriginalAuthority, RedeemLimitedEditionBidArgs, SCHEMA, diff --git a/packages/metavinci/src/models/metaplex/redeemMasterEditionBid.ts b/packages/metavinci/src/models/metaplex/redeemMasterEditionBid.ts index 89825a2..2342266 100644 --- a/packages/metavinci/src/models/metaplex/redeemMasterEditionBid.ts +++ b/packages/metavinci/src/models/metaplex/redeemMasterEditionBid.ts @@ -1,4 +1,4 @@ -import { programIds, VAULT_PREFIX } from '@oyster/common'; +import { programIds, VAULT_PREFIX, getMetadata } from '@oyster/common'; import { PublicKey, SystemProgram, @@ -11,7 +11,6 @@ import { serialize } from 'borsh'; import { getAuctionKeys, getBidderKeys, - getMetadata, RedeemMasterEditionBidArgs, SCHEMA, } from '.'; diff --git a/packages/metavinci/src/models/metaplex/redeemOpenEditionBid.ts b/packages/metavinci/src/models/metaplex/redeemOpenEditionBid.ts index aa64329..bc2ed6e 100644 --- a/packages/metavinci/src/models/metaplex/redeemOpenEditionBid.ts +++ b/packages/metavinci/src/models/metaplex/redeemOpenEditionBid.ts @@ -1,4 +1,4 @@ -import { getEdition, programIds } from '@oyster/common'; +import { getEdition, programIds, getMetadata } from '@oyster/common'; import { PublicKey, SystemProgram, @@ -11,7 +11,6 @@ import { serialize } from 'borsh'; import { getAuctionKeys, getBidderKeys, - getMetadata, RedeemOpenEditionBidArgs, SCHEMA, } from '.';