From b2cf942d680bc9e26a469097d07d9c35ca5b8438 Mon Sep 17 00:00:00 2001 From: Kartik Soneji Date: Sun, 15 Jan 2023 14:29:10 +0530 Subject: [PATCH 1/4] Auto load `auctioneerAuthority` if not specified --- .../operations/findAuctionHouseByAddress.ts | 7 ++++--- .../auctionHouseModule/createAuctionHouse.test.ts | 13 +++++++++++++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/packages/js/src/plugins/auctionHouseModule/operations/findAuctionHouseByAddress.ts b/packages/js/src/plugins/auctionHouseModule/operations/findAuctionHouseByAddress.ts index ac51cec7a..6933a571d 100644 --- a/packages/js/src/plugins/auctionHouseModule/operations/findAuctionHouseByAddress.ts +++ b/packages/js/src/plugins/auctionHouseModule/operations/findAuctionHouseByAddress.ts @@ -1,6 +1,5 @@ import type { PublicKey } from '@solana/web3.js'; import { toAuctioneerAccount, toAuctionHouseAccount } from '../accounts'; -import { AuctioneerAuthorityRequiredError } from '../errors'; import { AuctionHouse, toAuctionHouse } from '../models/AuctionHouse'; import { Operation, @@ -51,7 +50,7 @@ export type FindAuctionHouseByAddressInput = { /** * The Auctioneer authority key. - * It is required when Auction House has Auctioneer enabled. + * It is automatically loaded when not specified and Auction House has Auctioneer enabled. * * @defaultValue No default value. */ @@ -101,7 +100,9 @@ export const findAuctionHouseByAddressOperationHandler: OperationHandler { From c61d21f20b6b94c344f116f14411b0f5b974577a Mon Sep 17 00:00:00 2001 From: Kartik Soneji Date: Sun, 15 Jan 2023 14:30:38 +0530 Subject: [PATCH 2/4] Add `findAuctionHousesByAddressList()` operation --- .../auctionHouseModule/AuctionHouseClient.ts | 12 ++ .../findAuctionHousesByAddressList.ts | 153 ++++++++++++++++++ .../auctionHouseModule/operations/index.ts | 1 + .../src/plugins/auctionHouseModule/plugin.ts | 6 + 4 files changed, 172 insertions(+) create mode 100644 packages/js/src/plugins/auctionHouseModule/operations/findAuctionHousesByAddressList.ts diff --git a/packages/js/src/plugins/auctionHouseModule/AuctionHouseClient.ts b/packages/js/src/plugins/auctionHouseModule/AuctionHouseClient.ts index 34f36696b..05c32266c 100644 --- a/packages/js/src/plugins/auctionHouseModule/AuctionHouseClient.ts +++ b/packages/js/src/plugins/auctionHouseModule/AuctionHouseClient.ts @@ -22,6 +22,8 @@ import { findAuctionHouseByAddressOperation, FindAuctionHouseByCreatorAndMintInput, findAuctionHouseByCreatorAndMintOperation, + FindAuctionHousesByAddressListInput, + findAuctionHousesByAddressListOperation, FindBidByReceiptInput, findBidByReceiptOperation, FindBidByTradeStateInput, @@ -188,6 +190,16 @@ export class AuctionHouseClient { .execute(findAuctionHouseByCreatorAndMintOperation(input), options); } + /** {@inheritDoc findAuctionHousesByAddressListOperation} */ + findByAddressList( + input: FindAuctionHousesByAddressListInput, + options?: OperationOptions + ) { + return this.metaplex + .operations() + .execute(findAuctionHousesByAddressListOperation(input), options); + } + /** {@inheritDoc findBidByReceiptOperation} */ findBidByReceipt(input: FindBidByReceiptInput, options?: OperationOptions) { return this.metaplex diff --git a/packages/js/src/plugins/auctionHouseModule/operations/findAuctionHousesByAddressList.ts b/packages/js/src/plugins/auctionHouseModule/operations/findAuctionHousesByAddressList.ts new file mode 100644 index 000000000..e5f293c04 --- /dev/null +++ b/packages/js/src/plugins/auctionHouseModule/operations/findAuctionHousesByAddressList.ts @@ -0,0 +1,153 @@ +import { PublicKey } from '@solana/web3.js'; +import { toAuctioneerAccount, toAuctionHouseAccount } from '../accounts'; +import { AuctionHouse, toAuctionHouse } from '../models'; +import { toMint, toMintAccount } from '../../tokenModule'; +import { chunk } from '../../../utils/common'; +import { + Operation, + OperationHandler, + OperationScope, + UnparsedMaybeAccount, + useOperation, +} from '@/types'; +import { Metaplex } from '@/Metaplex'; + +// ----------------- +// Operation +// ----------------- + +const Key = 'FindAuctionHousesByAddressListOperation' as const; + +/** + * Finds multiple Auction Houses by their address. + * + * ```ts + * const nft = await metaplex + * .auctionHouse() + * .findByAddressList({ addresses }; + * ``` + * + * @group Operations + * @category Constructors + */ +export const findAuctionHousesByAddressListOperation = + useOperation(Key); + +/** + * @group Operations + * @category Types + */ +export type FindAuctionHousesByAddressListOperation = Operation< + typeof Key, + FindAuctionHousesByAddressListInput, + FindAuctionHousesByAddressListOutput +>; + +/** + * @group Operations + * @category Inputs + */ +export type FindAuctionHousesByAddressListInput = { + /** The addresses of the Auction Houses. */ + addresses: PublicKey[]; +}; + +/** + * @group Operations + * @category Outputs + */ +export type FindAuctionHousesByAddressListOutput = AuctionHouse[]; + +const fetchUniqueAccountMap: ( + metaplex: Metaplex, + accounts: PublicKey[], + mapper: (account: UnparsedMaybeAccount) => T, + accountMap?: Map +) => Promise> = async ( + metaplex, + accounts, + mapper, // = (account) => account, + accountMap = new Map() +) => { + const uniqueAccounts: Set = new Set( + accounts.filter((key): key is PublicKey => key !== null) + ); + + const accountInfos = await Promise.all( + chunk(Array.from(uniqueAccounts), 100).map((chunk) => + metaplex.rpc().getMultipleAccounts(chunk) + ) + ).then((infos) => infos.flat()); + + for (const account of accountInfos) { + accountMap.set(account.publicKey, mapper(account)); + } + + return accountMap; +}; + +/** + * @group Operations + * @category Handlers + */ +export const findAuctionHousesByAddressListOperationHandler: OperationHandler = + { + handle: async ( + operation: FindAuctionHousesByAddressListOperation, + metaplex: Metaplex, + scope: OperationScope + ): Promise => { + const { commitment } = scope; + const { addresses } = operation.input; + + const auctionHouseUnparsedAccounts = await Promise.all( + chunk(addresses, 100).map((c) => + metaplex.rpc().getMultipleAccounts(c, commitment) + ) + ); + scope.throwIfCanceled(); + + const auctionHouseAccounts = auctionHouseUnparsedAccounts + .flat() + .map((account) => toAuctionHouseAccount(account)); + + const mintAddresses = auctionHouseAccounts.map( + (auctionHouseAccount) => auctionHouseAccount.data.treasuryMint + ); + const auctioneerAddresses = auctionHouseAccounts + .map(({ data: { hasAuctioneer, auctioneerAddress } }) => + hasAuctioneer ? auctioneerAddress : null + ) + .filter((key): key is PublicKey => key !== null); + + const mintAndAuctioneerAccounts = await fetchUniqueAccountMap( + metaplex, + mintAddresses.concat(auctioneerAddresses), + (a) => a + ); + scope.throwIfCanceled(); + + return auctionHouseAccounts.map((auctionHouseAccount) => { + const mintModel = toMint( + toMintAccount( + mintAndAuctioneerAccounts.get( + auctionHouseAccount.data.treasuryMint + )! + ) + ); + + if (!auctionHouseAccount.data.hasAuctioneer) + return toAuctionHouse(auctionHouseAccount, mintModel); + + return toAuctionHouse( + auctionHouseAccount, + mintModel, + toAuctioneerAccount( + mintAndAuctioneerAccounts.get( + auctionHouseAccount.data.auctioneerAddress + )! + ) + ); + }); + }, + }; diff --git a/packages/js/src/plugins/auctionHouseModule/operations/index.ts b/packages/js/src/plugins/auctionHouseModule/operations/index.ts index f5f607451..153a51b55 100644 --- a/packages/js/src/plugins/auctionHouseModule/operations/index.ts +++ b/packages/js/src/plugins/auctionHouseModule/operations/index.ts @@ -9,6 +9,7 @@ export * from './directSell'; export * from './executeSale'; export * from './findAuctionHouseByAddress'; export * from './findAuctionHouseByCreatorAndMint'; +export * from './findAuctionHousesByAddressList'; export * from './findBidByReceipt'; export * from './findBidByTradeState'; export * from './findBids'; diff --git a/packages/js/src/plugins/auctionHouseModule/plugin.ts b/packages/js/src/plugins/auctionHouseModule/plugin.ts index 9bc26fb0b..3f1109edf 100644 --- a/packages/js/src/plugins/auctionHouseModule/plugin.ts +++ b/packages/js/src/plugins/auctionHouseModule/plugin.ts @@ -24,6 +24,8 @@ import { findAuctionHouseByAddressOperationHandler, findAuctionHouseByCreatorAndMintOperation, findAuctionHouseByCreatorAndMintOperationHandler, + findAuctionHousesByAddressListOperation, + findAuctionHousesByAddressListOperationHandler, findBidByReceiptOperation, findBidByReceiptOperationHandler, findBidByTradeStateOperation, @@ -104,6 +106,10 @@ export const auctionHouseModule = (): MetaplexPlugin => ({ findAuctionHouseByCreatorAndMintOperation, findAuctionHouseByCreatorAndMintOperationHandler ); + op.register( + findAuctionHousesByAddressListOperation, + findAuctionHousesByAddressListOperationHandler + ); op.register(findBidByReceiptOperation, findBidByReceiptOperationHandler); op.register( findBidByTradeStateOperation, From 7c72200296b95f21de6e394b47b9b1c31493e9fc Mon Sep 17 00:00:00 2001 From: Kartik Soneji Date: Sun, 15 Jan 2023 14:38:01 +0530 Subject: [PATCH 3/4] Make `auctionHouse` optional in `findListings()` --- .../operations/findListings.ts | 46 ++++++++++++++++--- 1 file changed, 40 insertions(+), 6 deletions(-) diff --git a/packages/js/src/plugins/auctionHouseModule/operations/findListings.ts b/packages/js/src/plugins/auctionHouseModule/operations/findListings.ts index f215c2a56..d6855ab16 100644 --- a/packages/js/src/plugins/auctionHouseModule/operations/findListings.ts +++ b/packages/js/src/plugins/auctionHouseModule/operations/findListings.ts @@ -53,7 +53,7 @@ export type FindListingsOperation = Operation< */ export type FindListingsInput = { /** A model of the Auction House related to these listings. */ - auctionHouse: AuctionHouse; + auctionHouse?: AuctionHouse; /** The address of a seller to search by. */ seller?: PublicKey; @@ -92,9 +92,11 @@ export const findListingsOperationHandler: OperationHandler - toLazyListing(toListingReceiptAccount(account), auctionHouse) + const listingReceiptAccounts = await listingQuery.getAndMap((account) => + toListingReceiptAccount(account) + ); + + // return early if auctionHouse is specified + if (auctionHouse) { + return listingReceiptAccounts.map((listing) => + toLazyListing(listing, auctionHouse) + ); + } + + const uniqueAuctionHouseAddresses = Array.from( + new Set( + listingReceiptAccounts.map( + (auctionHouseAccount) => auctionHouseAccount.data.auctionHouse + ) + ) + ); + + const auctionHouses = await metaplex + .auctionHouse() + .findByAddressList({ addresses: uniqueAuctionHouseAddresses }); + + scope.throwIfCanceled(); + + const auctionHouseMap: Map = new Map( + auctionHouses.map((auctionHouse) => [ + auctionHouse.address, + auctionHouse, + ]) + ); + + return listingReceiptAccounts.map((listing) => + toLazyListing(listing, auctionHouseMap.get(listing.data.auctionHouse)!) ); }, }; From 40bb37e558f5bdbcd215090e8f25c00bca722289 Mon Sep 17 00:00:00 2001 From: Kartik Soneji Date: Wed, 18 Jan 2023 19:41:11 +0530 Subject: [PATCH 4/4] Add `withdrawFromFeeAccount()` to AuctionHouseBuildersClient --- .../auctionHouseModule/AuctionHouseBuildersClient.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/packages/js/src/plugins/auctionHouseModule/AuctionHouseBuildersClient.ts b/packages/js/src/plugins/auctionHouseModule/AuctionHouseBuildersClient.ts index 357d384d7..cff641e2c 100644 --- a/packages/js/src/plugins/auctionHouseModule/AuctionHouseBuildersClient.ts +++ b/packages/js/src/plugins/auctionHouseModule/AuctionHouseBuildersClient.ts @@ -11,6 +11,8 @@ import { DirectSellBuilderParams, withdrawFromBuyerAccountBuilder, WithdrawFromBuyerAccountBuilderParams, + withdrawFromFeeAccountBuilder, + WithdrawFromFeeAccountBuilderParams, } from './operations'; import { createAuctionHouseBuilder, @@ -120,4 +122,12 @@ export class AuctionHouseBuildersClient { ) { return withdrawFromBuyerAccountBuilder(this.metaplex, input, options); } + + /** {@inheritDoc withdrawFromFeeAccountBuilder} */ + withdrawFromFeeAccount( + input: WithdrawFromFeeAccountBuilderParams, + options?: TransactionBuilderOptions + ) { + return withdrawFromFeeAccountBuilder(this.metaplex, input, options); + } }