Holy cow, now we have editions too

This commit is contained in:
Jordan Prince 2021-08-11 17:31:10 -05:00
parent e7abac452f
commit ad23dbfb4f
7 changed files with 142 additions and 34 deletions

View File

@ -213,6 +213,7 @@ export class Metadata {
data: Data;
primarySaleHappened: boolean;
isMutable: boolean;
editionNonce: number | null;
// set lazy
masterEdition?: PublicKey;
@ -224,6 +225,7 @@ export class Metadata {
data: Data;
primarySaleHappened: boolean;
isMutable: boolean;
editionNonce: number | null;
}) {
this.key = MetadataKey.MetadataV1;
this.updateAuthority = args.updateAuthority;
@ -231,6 +233,7 @@ export class Metadata {
this.data = args.data;
this.primarySaleHappened = args.primarySaleHappened;
this.isMutable = args.isMutable;
this.editionNonce = args.editionNonce;
}
public async init() {

View File

@ -4,7 +4,7 @@ import {
METAPLEX_ID,
VAULT_ID,
} from '@oyster/common/dist/lib/utils/ids';
import { Connection } from '@solana/web3.js';
import { Connection, PublicKey } from '@solana/web3.js';
import { AccountAndPubkey, MetaState, ProcessAccountsFunc } from './types';
import { isMetadataPartOfStore } from './isMetadataPartOfStore';
import { processAuctions } from './processAuctions';
@ -12,12 +12,16 @@ import { processMetaplexAccounts } from './processMetaplexAccounts';
import { processMetaData } from './processMetaData';
import { processVaultData } from './processVaultData';
import {
findProgramAddress,
getEdition,
getMultipleAccounts,
MAX_CREATOR_LEN,
MAX_CREATOR_LIMIT,
MAX_NAME_LENGTH,
MAX_SYMBOL_LENGTH,
MAX_URI_LENGTH,
Metadata,
METADATA_PREFIX,
ParsedAccount,
} from '../../../../common/dist/lib';
import {
@ -83,35 +87,46 @@ export const loadAccounts = async (connection: Connection, all: boolean) => {
tempCache.whitelistedCreatorsByCreator,
);
for (let i = 0; i < MAX_CREATOR_LIMIT; i++) {
for (let j = 0; j < whitelistedCreators.length; j++) {
additionalPromises.push(
connection
.getProgramAccounts(METADATA_PROGRAM_ID, {
filters: [
{
memcmp: {
offset:
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
i * MAX_CREATOR_LEN,
bytes: whitelistedCreators[j].info.address.toBase58(),
if (whitelistedCreators.length > 3) {
console.log(' too many creators, pulling all nfts in one go');
additionalPromises.push(
connection
.getProgramAccounts(METADATA_PROGRAM_ID)
.then(forEach(processMetaData)),
);
} else {
console.log('pulling optimized nfts');
for (let i = 0; i < MAX_CREATOR_LIMIT; i++) {
for (let j = 0; j < whitelistedCreators.length; j++) {
additionalPromises.push(
connection
.getProgramAccounts(METADATA_PROGRAM_ID, {
filters: [
{
memcmp: {
offset:
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
i * MAX_CREATOR_LEN,
bytes: whitelistedCreators[j].info.address.toBase58(),
},
},
},
],
})
.then(forEach(processMetaData)),
);
],
})
.then(forEach(processMetaData)),
);
}
}
}
}),
@ -122,6 +137,63 @@ export const loadAccounts = async (connection: Connection, all: boolean) => {
await postProcessMetadata(tempCache, all);
console.log('Metadata size', tempCache.metadata.length);
if (additionalPromises.length > 0) {
console.log('Pulling editions for optimized metadata');
let setOf100MetadataEditionKeys: string[] = [];
const editionPromises = [];
for (let i = 0; i < tempCache.metadata.length; i++) {
let edition: PublicKey;
if (tempCache.metadata[i].info.editionNonce != null) {
edition = await PublicKey.createProgramAddress(
[
Buffer.from(METADATA_PREFIX),
METADATA_PROGRAM_ID.toBuffer(),
tempCache.metadata[i].info.mint.toBuffer(),
new Uint8Array([tempCache.metadata[i].info.editionNonce || 0]),
],
METADATA_PROGRAM_ID,
);
} else {
edition = await getEdition(tempCache.metadata[i].info.mint);
}
setOf100MetadataEditionKeys.push(edition.toBase58());
if (setOf100MetadataEditionKeys.length >= 100) {
console.log('push');
editionPromises.push(
getMultipleAccounts(
connection,
setOf100MetadataEditionKeys,
'recent',
),
);
setOf100MetadataEditionKeys = [];
}
}
const responses = await Promise.all(editionPromises);
for (let i = 0; i < responses.length; i++) {
const returnedAccounts = responses[i];
for (let j = 0; j < returnedAccounts.array.length; j++) {
processMetaData(
{
pubkey: new PublicKey(returnedAccounts.keys[j]),
account: returnedAccounts.array[j],
},
updateTemp,
all,
);
}
}
console.log(
'Edition size',
Object.keys(tempCache.editions).length,
Object.keys(tempCache.masterEditions).length,
);
}
return tempCache;
};

View File

@ -84,8 +84,12 @@ export const processMetaData: ProcessAccountsFunc = (
}
};
const isMetadataAccount = (account: AccountInfo<Buffer>) =>
account.owner.equals(METADATA_PROGRAM_ID);
const isMetadataAccount = (account: AccountInfo<Buffer>) => {
return account.owner.equals
? account.owner.equals(METADATA_PROGRAM_ID)
: //@ts-ignore
account.owner === METADATA_PROGRAM_ID.toBase58();
};
const isMetadataV1Account = (account: AccountInfo<Buffer>) =>
account.data[0] === MetadataKey.MetadataV1;

View File

@ -592,6 +592,16 @@ pub fn process_puff_metadata_account(
assert_owned_by(metadata_account_info, program_id)?;
puff_out_data_fields(&mut metadata);
let edition_seeds = &[
PREFIX.as_bytes(),
program_id.as_ref(),
metadata.mint.as_ref(),
EDITION.as_bytes()
];
let (_, edition_bump_seed) =
Pubkey::find_program_address(edition_seeds, program_id);
metadata.edition_nonce = Some(edition_bump_seed);
metadata.serialize(&mut *metadata_account_info.data.borrow_mut())?;
Ok(())

View File

@ -23,14 +23,20 @@ pub const MAX_URI_LENGTH: usize = 200;
pub const MAX_METADATA_LEN: usize = 1
+ 32
+ 32
+ 4
+ MAX_NAME_LENGTH
+ 4
+ MAX_SYMBOL_LENGTH
+ 4
+ MAX_URI_LENGTH
+ MAX_CREATOR_LIMIT * MAX_CREATOR_LEN
+ 2
+ 1
+ 4
+ MAX_CREATOR_LIMIT * MAX_CREATOR_LEN
+ 1
+ 198;
+ 1
+ 9
+ 172;
pub const MAX_EDITION_LEN: usize = 1 + 32 + 8 + 200;
@ -93,6 +99,8 @@ pub struct Metadata {
pub primary_sale_happened: bool,
// Whether or not the data struct is mutable, default is not
pub is_mutable: bool,
/// nonce for easy calculation of editions, if present
pub edition_nonce: Option<u8>
}
impl Metadata {

View File

@ -851,6 +851,17 @@ pub fn process_create_metadata_accounts_logic(
metadata.update_authority = *update_authority_info.key;
puff_out_data_fields(&mut metadata);
let edition_seeds = &[
PREFIX.as_bytes(),
program_id.as_ref(),
metadata.mint.as_ref(),
EDITION.as_bytes()
];
let (_, edition_bump_seed) =
Pubkey::find_program_address(edition_seeds, program_id);
metadata.edition_nonce = Some(edition_bump_seed);
metadata.serialize(&mut *metadata_account_info.data.borrow_mut())?;
Ok(())

View File

@ -40,7 +40,7 @@ fn puff_unpuffed_metadata(_app_matches: &ArgMatches, payer: Keypair, client: Rpc
for acct in metadata_accounts {
if acct.1.data[0] == Key::MetadataV1 as u8 {
let account: Metadata = try_from_slice_unchecked(&acct.1.data).unwrap();
if account.data.name.len() < MAX_NAME_LENGTH || account.data.uri.len() < MAX_URI_LENGTH || account.data.symbol.len() < MAX_SYMBOL_LENGTH {
if account.data.name.len() < MAX_NAME_LENGTH || account.data.uri.len() < MAX_URI_LENGTH || account.data.symbol.len() < MAX_SYMBOL_LENGTH || account.edition_nonce.is_none() {
needing_puffing.push(acct.0);
}
}