From 39005940e8af11aca9813cff19c1fb15125fb505 Mon Sep 17 00:00:00 2001 From: Vecheslav Druzhbin Date: Fri, 24 Sep 2021 14:22:20 +0300 Subject: [PATCH] feat: find many for auction/manager/metadata --- api/src/programs/auction/accouns/Auction.ts | 30 ++++++++++++-- .../programs/metadata/accounts/Metadata.ts | 40 +++++++++---------- .../metaplex/accounts/AuctionManager.ts | 33 +++++++++++++++ api/test/auction.test.ts | 12 +++++- api/test/metaplex.test.ts | 8 ++++ examples/node/index.ts | 4 +- 6 files changed, 98 insertions(+), 29 deletions(-) diff --git a/api/src/programs/auction/accouns/Auction.ts b/api/src/programs/auction/accouns/Auction.ts index d61dce2..a18e7c5 100644 --- a/api/src/programs/auction/accouns/Auction.ts +++ b/api/src/programs/auction/accouns/Auction.ts @@ -1,13 +1,13 @@ -import { AccountInfo, Connection, PublicKey } from '@solana/web3.js'; -import BN from 'bn.js'; import { ERROR_INVALID_OWNER } from '@metaplex/errors'; import { AnyPublicKey, StringPublicKey } from '@metaplex/types'; +import { Borsh } from '@metaplex/utils'; +import { AccountInfo, Connection, PublicKey } from '@solana/web3.js'; +import BN from 'bn.js'; +import { Buffer } from 'buffer'; import { Account } from '../../../Account'; import { AuctionProgram } from '../AuctionProgram'; import { BidderMetadata } from './BidderMetadata'; import { BidderPot } from './BidderPot'; -import { Buffer } from 'buffer'; -import { Borsh } from '@metaplex/utils'; export enum AuctionState { Created = 0, @@ -183,6 +183,28 @@ export class Auction extends Account { ]); } + static async findMany(connection: Connection, filters: { authority?: AnyPublicKey }) { + return ( + await AuctionProgram.getProgramAccounts(connection, { + filters: [ + // Filter for assigned to authority + filters.authority && { + memcmp: { + offset: 0, + bytes: new PublicKey(filters.authority).toBase58(), + }, + }, + ].filter(Boolean), + }) + ) + .map((account) => { + try { + return Auction.from(account); + } catch (err) {} + }) + .filter(Boolean); + } + async getBidderPots(connection: Connection) { return ( await AuctionProgram.getProgramAccounts(connection, { diff --git a/api/src/programs/metadata/accounts/Metadata.ts b/api/src/programs/metadata/accounts/Metadata.ts index 5c99f11..437dbcf 100644 --- a/api/src/programs/metadata/accounts/Metadata.ts +++ b/api/src/programs/metadata/accounts/Metadata.ts @@ -124,7 +124,10 @@ export class Metadata extends Account { ]); } - static async getAll(connection: Connection) { + static async findMany( + connection: Connection, + filters: { mint?: AnyPublicKey; updateAuthority?: AnyPublicKey } = {}, + ) { return ( await MetadataProgram.getProgramAccounts(connection, { filters: [ @@ -135,38 +138,30 @@ export class Metadata extends Account { bytes: bs58.encode(Buffer.from([MetadataKey.MetadataV1])), }, }, - ], - }) - ).map((account) => Metadata.from(account)); - } - - static async getByMint(connection: Connection, mint: AnyPublicKey) { - return ( - await MetadataProgram.getProgramAccounts(connection, { - filters: [ - // Filter for MetadataV1 by key - { + // Filter for assigned to update authority + filters.updateAuthority && { memcmp: { - offset: 0, - bytes: bs58.encode(Buffer.from([MetadataKey.MetadataV1])), + offset: 1, + bytes: new PublicKey(filters.updateAuthority).toBase58(), }, }, // Filter for assigned to mint - { + filters.mint && { memcmp: { offset: 33, - bytes: new PublicKey(mint).toBase58(), + bytes: new PublicKey(filters.mint).toBase58(), }, }, - ], + ].filter(Boolean), }) ).map((account) => Metadata.from(account)); } - static async getMetdataByOwner(connection: Connection, owner: AnyPublicKey) { + static async findByOwner(connection: Connection, owner: AnyPublicKey) { const accounts = await TokenAccount.getTokenAccountsByOwner(connection, owner); const accountMap = new Map(accounts.map(({ data }) => [data.mint.toString(), data])); - const allMetadata = await Metadata.getAll(connection); + // Slow method + const allMetadata = await Metadata.findMany(connection); return allMetadata.filter( (metadata) => @@ -175,15 +170,16 @@ export class Metadata extends Account { ); } - // TODO: lol - static async getMetdataByOwnerV2(connection: Connection, owner: AnyPublicKey) { + static async findByOwnerV2(connection: Connection, owner: AnyPublicKey) { const accounts = await TokenAccount.getTokenAccountsByOwner(connection, owner); const accountsWithAmount = accounts .map(({ data }) => data) .filter(({ amount }) => amount?.toNumber() > 0); return ( - await Promise.all(accountsWithAmount.map(({ mint }) => Metadata.getByMint(connection, mint))) + await Promise.all( + accountsWithAmount.map(({ mint }) => Metadata.findMany(connection, { mint })), + ) ).flat(); } diff --git a/api/src/programs/metaplex/accounts/AuctionManager.ts b/api/src/programs/metaplex/accounts/AuctionManager.ts index f4542d8..5f5a17c 100644 --- a/api/src/programs/metaplex/accounts/AuctionManager.ts +++ b/api/src/programs/metaplex/accounts/AuctionManager.ts @@ -113,6 +113,39 @@ export class AuctionManager extends Account { ]); } + static async findMany( + connection: Connection, + filters: { store?: AnyPublicKey; authority?: AnyPublicKey } = {}, + ) { + return ( + await MetaplexProgram.getProgramAccounts(connection, { + filters: [ + // Filter for AuctionManagerV2 by key + { + memcmp: { + offset: 0, + bytes: bs58.encode(Buffer.from([MetaplexKey.AuctionManagerV2])), + }, + }, + // Filter for assigned to store + filters.store && { + memcmp: { + offset: 1, + bytes: new PublicKey(filters.store).toBase58(), + }, + }, + // Filter for assigned to authority + filters.authority && { + memcmp: { + offset: 33, + bytes: new PublicKey(filters.authority).toBase58(), + }, + }, + ].filter(Boolean), + }) + ).map((account) => AuctionManager.from(account)); + } + async getAuction(connection: Connection) { return Auction.load(connection, this.data.auction); } diff --git a/api/test/auction.test.ts b/api/test/auction.test.ts index 1e02c26..6fd2fca 100644 --- a/api/test/auction.test.ts +++ b/api/test/auction.test.ts @@ -1,5 +1,10 @@ import { Auction, AuctionExtended, AuctionState, Connection } from '../src'; -import { AUCTION_EXTENDED_PUBKEY, AUCTION_PUBKEY, VAULT_PUBKEY } from './utils'; +import { + AUCTION_EXTENDED_PUBKEY, + AUCTION_MANAGER_PUBKEY, + AUCTION_PUBKEY, + VAULT_PUBKEY, +} from './utils'; describe('Auction', () => { let connection: Connection; @@ -16,6 +21,11 @@ describe('Auction', () => { expect(auction.data.state).toEqual(AuctionState.Started); }); + test('findMany', async () => { + const auctions = await Auction.findMany(connection, { authority: AUCTION_MANAGER_PUBKEY }); + expect(auctions[0].data.authority).toEqual(AUCTION_MANAGER_PUBKEY.toString()); + }); + test('getBidderPots', async () => { const auction = await Auction.load(connection, AUCTION_PUBKEY); const bidderPots = await auction.getBidderPots(connection); diff --git a/api/test/metaplex.test.ts b/api/test/metaplex.test.ts index 60016d1..af581a8 100644 --- a/api/test/metaplex.test.ts +++ b/api/test/metaplex.test.ts @@ -56,6 +56,14 @@ describe('Metaplex', () => { expect(auctionManager.data.key).toEqual(MetaplexKey.AuctionManagerV2); }); + test('findMany', async () => { + const auctionManagers = await AuctionManager.findMany(connection, { + store: STORE_PUBKEY, + authority: STORE_OWNER_PUBKEY, + }); + expect(auctionManagers[0].data.store).toEqual(STORE_PUBKEY.toString()); + }); + test('getAuction', async () => { const auctionManager = await AuctionManager.load(connection, AUCTION_MANAGER_PUBKEY); const auction = await auctionManager.getAuction(connection); diff --git a/examples/node/index.ts b/examples/node/index.ts index dde0a60..92fea26 100644 --- a/examples/node/index.ts +++ b/examples/node/index.ts @@ -15,12 +15,12 @@ const connection = new Connection('devnet'); const run = async () => { // TODO: just waiting for layer service with combine // console.time('ownedMetadata'); - // const ownedMetadata = await Metadata.getMetdataByOwner(connection, payer.publicKey); + // const ownedMetadata = await Metadata.findByOwner(connection, payer.publicKey); // console.log(ownedMetadata); // console.timeEnd('ownedMetadata'); console.time('ownedMetadata v2'); - const ownedMetadata = await Metadata.getMetdataByOwnerV2(connection, payer.publicKey); + const ownedMetadata = await Metadata.findByOwnerV2(connection, payer.publicKey); console.log(ownedMetadata); console.timeEnd('ownedMetadata v2');