mirror of https://github.com/certusone/oyster.git
Merge remote-tracking branch 'origin/feature/m-jordan' into feature/m
This commit is contained in:
commit
2b875e4d25
|
@ -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;
|
||||
|
|
|
@ -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<PublicKey> {
|
||||
const PROGRAM_IDS = programIds();
|
||||
|
||||
|
@ -662,3 +763,18 @@ export async function getEdition(tokenMint: PublicKey): Promise<PublicKey> {
|
|||
)
|
||||
)[0];
|
||||
}
|
||||
|
||||
export async function getMetadata(tokenMint: PublicKey): Promise<PublicKey> {
|
||||
const PROGRAM_IDS = programIds();
|
||||
|
||||
return (
|
||||
await PublicKey.findProgramAddress(
|
||||
[
|
||||
Buffer.from(METADATA_PREFIX),
|
||||
PROGRAM_IDS.metadata.toBuffer(),
|
||||
tokenMint.toBuffer(),
|
||||
],
|
||||
PROGRAM_IDS.metadata,
|
||||
)
|
||||
)[0];
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -151,7 +151,7 @@ export const mintNFT = async (
|
|||
|
||||
// Force wait for max confirmations
|
||||
// await connection.confirmTransaction(txid, 'max');
|
||||
await connection.getParsedConfirmedTransaction(txid, 'confirmed');
|
||||
await connection.getParsedConfirmedTransaction(txid);
|
||||
|
||||
// this means we're done getting AR txn setup. Ship it off to ARWeave!
|
||||
const data = new FormData();
|
||||
|
@ -183,8 +183,7 @@ export const mintNFT = async (
|
|||
const metadataFile = result.messages?.find(
|
||||
m => m.filename == RESERVED_TXN_MANIFEST,
|
||||
);
|
||||
if (metadataFile?.transactionId && wallet.publicKey)
|
||||
{
|
||||
if (metadataFile?.transactionId && wallet.publicKey) {
|
||||
const updateInstructions: TransactionInstruction[] = [];
|
||||
const updateSigners: Account[] = [];
|
||||
|
||||
|
|
|
@ -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<string, TokenAccount>,
|
||||
) {
|
||||
let signers: Array<Account[]> = [];
|
||||
let instructions: Array<TransactionInstruction[]> = [];
|
||||
|
||||
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<string, TokenAccount>,
|
||||
accountRentExempt: number,
|
||||
wallet: any,
|
||||
safetyDeposit: ParsedAccount<SafetyDepositBox>,
|
||||
signers: Array<Account[]>,
|
||||
instructions: Array<TransactionInstruction[]>,
|
||||
) {
|
||||
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<string, TokenAccount>,
|
||||
accountRentExempt: number,
|
||||
wallet: any,
|
||||
safetyDeposit: ParsedAccount<SafetyDepositBox>,
|
||||
item: AuctionViewItem,
|
||||
signers: Array<Account[]>,
|
||||
instructions: Array<TransactionInstruction[]>,
|
||||
) {
|
||||
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<string, TokenAccount>,
|
||||
accountRentExempt: number,
|
||||
mintRentExempt: number,
|
||||
wallet: any,
|
||||
safetyDeposit: ParsedAccount<SafetyDepositBox>,
|
||||
item: AuctionViewItem,
|
||||
signers: Array<Account[]>,
|
||||
instructions: Array<TransactionInstruction[]>,
|
||||
) {
|
||||
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<string, TokenAccount>,
|
||||
accountRentExempt: number,
|
||||
mintRentExempt: number,
|
||||
wallet: any,
|
||||
safetyDeposit: ParsedAccount<SafetyDepositBox>,
|
||||
item: AuctionViewItem,
|
||||
signers: Array<Account[]>,
|
||||
instructions: Array<TransactionInstruction[]>,
|
||||
) {
|
||||
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,
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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<string, ParsedAccount<MasterEdition>>;
|
||||
auctionManagers: Record<string, ParsedAccount<AuctionManager>>;
|
||||
auctions: Record<string, ParsedAccount<AuctionData>>;
|
||||
vaults: Record<string, ParsedAccount<Vault>>;
|
||||
bidderMetadataByAuctionAndBidder: Record<
|
||||
string,
|
||||
ParsedAccount<BidderMetadata>
|
||||
|
@ -67,6 +70,7 @@ const MetaContext = React.createContext<MetaContextState>({
|
|||
editions: {},
|
||||
auctionManagers: {},
|
||||
auctions: {},
|
||||
vaults: {},
|
||||
bidderMetadataByAuctionAndBidder: {},
|
||||
safetyDepositBoxesByVaultAndIndex: {},
|
||||
bidderPotsByAuctionAndBidder: {},
|
||||
|
@ -93,6 +97,9 @@ export function MetaProvider({ children = null as any }) {
|
|||
const [auctions, setAuctions] = useState<
|
||||
Record<string, ParsedAccount<AuctionData>>
|
||||
>({});
|
||||
const [vaults, setVaults] = useState<Record<string, ParsedAccount<Vault>>>(
|
||||
{},
|
||||
);
|
||||
const [
|
||||
bidderMetadataByAuctionAndBidder,
|
||||
setBidderMetadataByAuctionAndBidder,
|
||||
|
@ -204,7 +211,7 @@ export function MetaProvider({ children = null as any }) {
|
|||
useEffect(() => {
|
||||
let dispose = () => {};
|
||||
(async () => {
|
||||
const processSafetyDeposits = async (a: PublicKeyAndAccount<Buffer>) => {
|
||||
const processVaultData = async (a: PublicKeyAndAccount<Buffer>) => {
|
||||
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<Vault> = {
|
||||
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}
|
||||
|
|
|
@ -25,19 +25,24 @@ export const useAuction = (id: string) => {
|
|||
metadataByMint,
|
||||
bidderMetadataByAuctionAndBidder,
|
||||
bidderPotsByAuctionAndBidder,
|
||||
masterEditions,
|
||||
nameSymbolTuples,
|
||||
vaults,
|
||||
} = useMeta();
|
||||
|
||||
useEffect(() => {
|
||||
const auction = auctions[id];
|
||||
if (auction) {
|
||||
console.log(bidderMetadataByAuctionAndBidder);
|
||||
const auctionView = processAccountsIntoAuctionView(
|
||||
auction,
|
||||
auctionManagers,
|
||||
safetyDepositBoxesByVaultAndIndex,
|
||||
metadataByMint,
|
||||
nameSymbolTuples,
|
||||
bidderMetadataByAuctionAndBidder,
|
||||
bidderPotsByAuctionAndBidder,
|
||||
masterEditions,
|
||||
vaults,
|
||||
accountByMint,
|
||||
clock,
|
||||
undefined,
|
||||
|
@ -53,6 +58,9 @@ export const useAuction = (id: string) => {
|
|||
metadataByMint,
|
||||
bidderMetadataByAuctionAndBidder,
|
||||
bidderPotsByAuctionAndBidder,
|
||||
vaults,
|
||||
nameSymbolTuples,
|
||||
masterEditions,
|
||||
userAccounts,
|
||||
]);
|
||||
return existingAuctionView;
|
||||
|
|
|
@ -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<Metadata>;
|
||||
nameSymbol?: ParsedAccount<NameSymbolTuple>;
|
||||
safetyDeposit: ParsedAccount<SafetyDepositBox>;
|
||||
masterEdition?: ParsedAccount<MasterEdition>;
|
||||
}
|
||||
|
||||
// Flattened surface item for easy display
|
||||
|
@ -37,6 +41,7 @@ export interface AuctionView {
|
|||
thumbnail: AuctionViewItem;
|
||||
myBidderMetadata?: ParsedAccount<BidderMetadata>;
|
||||
myBidderPot?: ParsedAccount<BidderPot>;
|
||||
vault: ParsedAccount<Vault>;
|
||||
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<SafetyDepositBox>
|
||||
>,
|
||||
metadataByMint: Record<string, ParsedAccount<Metadata>>,
|
||||
nameSymbolTuples: Record<string, ParsedAccount<NameSymbolTuple>>,
|
||||
bidderMetadataByAuctionAndBidder: Record<
|
||||
string,
|
||||
ParsedAccount<BidderMetadata>
|
||||
>,
|
||||
bidderPotsByAuctionAndBidder: Record<string, ParsedAccount<BidderPot>>,
|
||||
masterEditions: Record<string, ParsedAccount<MasterEdition>>,
|
||||
vaults: Record<string, ParsedAccount<Vault>>,
|
||||
accountByMint: Map<string, TokenAccount>,
|
||||
clock: number,
|
||||
desiredState: AuctionViewState | undefined,
|
||||
|
@ -150,22 +167,40 @@ export function processAccountsIntoAuctionView(
|
|||
bidderPotsByAuctionAndBidder[
|
||||
auction.pubkey.toBase58() + '-' + myPayingAccount?.pubkey.toBase58()
|
||||
];
|
||||
if (
|
||||
auction.pubkey.toBase58() ==
|
||||
'CLxhAeuhz8KX3y8yEWHADtmTzE26ofAnd6j8zwMXjW9P'
|
||||
) {
|
||||
console.log(
|
||||
'I found',
|
||||
|
||||
bidderMetadata,
|
||||
myPayingAccount?.pubkey.toBase58(),
|
||||
);
|
||||
}
|
||||
if (existingAuctionView && existingAuctionView.totallyComplete) {
|
||||
// If totally complete, we know we arent updating anythign else, let's speed things up
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
@ -193,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
|
||||
? {
|
||||
|
@ -223,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;
|
||||
|
|
|
@ -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<PublicKey> {
|
||||
const PROGRAM_IDS = programIds();
|
||||
|
||||
return (
|
||||
await PublicKey.findProgramAddress(
|
||||
[
|
||||
Buffer.from(METADATA_PREFIX),
|
||||
PROGRAM_IDS.metadata.toBuffer(),
|
||||
tokenMint.toBuffer(),
|
||||
],
|
||||
PROGRAM_IDS.metadata,
|
||||
)
|
||||
)[0];
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 '.';
|
||||
|
|
|
@ -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 '.';
|
||||
|
|
Loading…
Reference in New Issue