Skip to content

Commit

Permalink
feat: metadata findmany creators filter
Browse files Browse the repository at this point in the history
  • Loading branch information
vecheslav committed Sep 29, 2021
1 parent 5452b93 commit cf43617
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 29 deletions.
1 change: 1 addition & 0 deletions api/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ export const config = {
// External
memo: 'MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr',
},
maxCreatorLimit: 5,
};
112 changes: 84 additions & 28 deletions api/src/programs/metadata/accounts/Metadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Borsh } from '@metaplex/utils';
import { AccountInfo, Connection, PublicKey } from '@solana/web3.js';
import bs58 from 'bs58';
import { Buffer } from 'buffer';
import { config } from '../../../config';
import { Account } from '../../../Account';
import { TokenAccount } from '../../shared';
import { MetadataKey, MetadataProgram } from '../MetadataProgram';
Expand Down Expand Up @@ -126,35 +127,67 @@ export class Metadata extends Account<MetadataData> {

static async findMany(
connection: Connection,
filters: { mint?: AnyPublicKey; updateAuthority?: AnyPublicKey } = {},
filters: {
mint?: AnyPublicKey;
updateAuthority?: AnyPublicKey;
creators?: AnyPublicKey[];
} = {},
) {
return (
await MetadataProgram.getProgramAccounts(connection, {
filters: [
// Filter for MetadataV1 by key
{
memcmp: {
offset: 0,
bytes: bs58.encode(Buffer.from([MetadataKey.MetadataV1])),
},
},
// Filter for assigned to update authority
filters.updateAuthority && {
memcmp: {
offset: 1,
bytes: new PublicKey(filters.updateAuthority).toBase58(),
},
},
// Filter for assigned to mint
filters.mint && {
memcmp: {
offset: 33,
bytes: new PublicKey(filters.mint).toBase58(),
},
},
].filter(Boolean),
})
).map((account) => Metadata.from(account));
const baseFilters = [
// Filter for MetadataV1 by key
{
memcmp: {
offset: 0,
bytes: bs58.encode(Buffer.from([MetadataKey.MetadataV1])),
},
},
// Filter for assigned to update authority
filters.updateAuthority && {
memcmp: {
offset: 1,
bytes: new PublicKey(filters.updateAuthority).toBase58(),
},
},
// Filter for assigned to mint
filters.mint && {
memcmp: {
offset: 33,
bytes: new PublicKey(filters.mint).toBase58(),
},
},
].filter(Boolean);

if (filters.creators) {
return (
await Promise.all(
Array.from(Array(config.maxCreatorLimit).keys()).reduce(
(prev, i) => [
...prev,
...filters.creators.map((pubkey) =>
MetadataProgram.getProgramAccounts(connection, {
filters: [
...baseFilters,
{
memcmp: {
offset: computeCreatorOffset(i),
bytes: new PublicKey(pubkey).toBase58(),
},
},
],
}),
),
],
[],
),
)
)
.flat()
.map((account) => Metadata.from(account));
} else {
return (await MetadataProgram.getProgramAccounts(connection, { filters: baseFilters })).map(
(account) => Metadata.from(account),
);
}
}

static async findByOwner(connection: Connection, owner: AnyPublicKey) {
Expand Down Expand Up @@ -202,3 +235,26 @@ export class Metadata extends Account<MetadataData> {
}
}
}

export const MAX_NAME_LENGTH = 32;
export const MAX_SYMBOL_LENGTH = 10;
export const MAX_URI_LENGTH = 200;
export const MAX_CREATOR_LEN = 32 + 1 + 1;

export const computeCreatorOffset = (index: number) => {
return (
1 + // key
32 + // update auth
32 + // mint
4 + // name string length
MAX_NAME_LENGTH + // name
4 + // uri string length
MAX_URI_LENGTH + // uri
4 + // symbol string length
MAX_SYMBOL_LENGTH + // symbol
2 + // seller fee basis points
1 + // whether or not there is a creators vec
4 + // creators vec length
index * MAX_CREATOR_LEN
);
};
11 changes: 10 additions & 1 deletion api/test/metadata.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { PublicKey } from '@solana/web3.js';
import { Connection, MasterEdition, Metadata, MetadataKey } from '../src';
import { MASTER_EDITION_PUBKEY, METADATA_PUBKEY } from './utils';
import { MASTER_EDITION_PUBKEY, METADATA_PUBKEY, STORE_OWNER_PUBKEY } from './utils';

describe('Metadata', () => {
let connection: Connection;
Expand All @@ -15,6 +16,14 @@ describe('Metadata', () => {
expect(metadata.pubkey).toEqual(METADATA_PUBKEY);
expect(metadata.data.key).toEqual(MetadataKey.MetadataV1);
});

test('findMany', async () => {
const metadata = await Metadata.findMany(connection, {
creators: [STORE_OWNER_PUBKEY],
});

expect(metadata[0].data.key).toBe(MetadataKey.MetadataV1);
});
});

describe('Master edition', () => {
Expand Down

0 comments on commit cf43617

Please sign in to comment.