Oh yeaj, it works and it's fast as sh*t...just get the metadata oyu ned
This commit is contained in:
parent
bc97c0c678
commit
9170223fb0
|
@ -14,6 +14,9 @@ import { processVaultData } from './processVaultData';
|
||||||
import {
|
import {
|
||||||
MAX_CREATOR_LEN,
|
MAX_CREATOR_LEN,
|
||||||
MAX_CREATOR_LIMIT,
|
MAX_CREATOR_LIMIT,
|
||||||
|
MAX_NAME_LENGTH,
|
||||||
|
MAX_SYMBOL_LENGTH,
|
||||||
|
MAX_URI_LENGTH,
|
||||||
Metadata,
|
Metadata,
|
||||||
ParsedAccount,
|
ParsedAccount,
|
||||||
} from '../../../../common/dist/lib';
|
} from '../../../../common/dist/lib';
|
||||||
|
@ -56,22 +59,6 @@ export const loadAccounts = async (connection: Connection, all: boolean) => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
await connection
|
|
||||||
.getProgramAccounts(METAPLEX_ID, {
|
|
||||||
filters: [
|
|
||||||
{
|
|
||||||
dataSize: MAX_WHITELISTED_CREATOR_SIZE,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
memcmp: {
|
|
||||||
offset: 0,
|
|
||||||
bytes: MetaplexKey.WhitelistedCreatorV1.toString(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
})
|
|
||||||
.then(forEach(processMetaplexAccounts));
|
|
||||||
|
|
||||||
const promises = [
|
const promises = [
|
||||||
connection.getProgramAccounts(VAULT_ID).then(forEach(processVaultData)),
|
connection.getProgramAccounts(VAULT_ID).then(forEach(processVaultData)),
|
||||||
connection.getProgramAccounts(AUCTION_ID).then(forEach(processAuctions)),
|
connection.getProgramAccounts(AUCTION_ID).then(forEach(processAuctions)),
|
||||||
|
@ -79,27 +66,58 @@ export const loadAccounts = async (connection: Connection, all: boolean) => {
|
||||||
connection
|
connection
|
||||||
.getProgramAccounts(METAPLEX_ID)
|
.getProgramAccounts(METAPLEX_ID)
|
||||||
.then(forEach(processMetaplexAccounts)),
|
.then(forEach(processMetaplexAccounts)),
|
||||||
];
|
connection
|
||||||
for (let i = 0; i < MAX_CREATOR_LIMIT; i++) {
|
.getProgramAccounts(METAPLEX_ID, {
|
||||||
promises.push(
|
filters: [
|
||||||
connection
|
{
|
||||||
.getProgramAccounts(METADATA_PROGRAM_ID, {
|
dataSize: MAX_WHITELISTED_CREATOR_SIZE,
|
||||||
filters: [
|
},
|
||||||
{
|
],
|
||||||
memcmp: {
|
})
|
||||||
offset: 0,
|
.then(async creators => {
|
||||||
bytes: MetaplexKey.WhitelistedCreatorV1.toString(),
|
await forEach(processMetaplexAccounts)(creators);
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
})
|
|
||||||
.then(forEach(processMetaData)),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
const whitelistedCreators = Object.values(
|
||||||
|
tempCache.whitelistedCreatorsByCreator,
|
||||||
|
);
|
||||||
|
|
||||||
|
for (let i = 0; i < MAX_CREATOR_LIMIT; i++) {
|
||||||
|
for (let j = 0; j < whitelistedCreators.length; j++) {
|
||||||
|
promises.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)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
];
|
||||||
await Promise.all(promises);
|
await Promise.all(promises);
|
||||||
|
|
||||||
await postProcessMetadata(tempCache, all);
|
await postProcessMetadata(tempCache, all);
|
||||||
|
console.log('Metadata size', tempCache.metadata.length);
|
||||||
|
|
||||||
return tempCache;
|
return tempCache;
|
||||||
};
|
};
|
||||||
|
|
|
@ -131,7 +131,6 @@ export const processMetaplexAccounts: ProcessAccountsFunc = async (
|
||||||
|
|
||||||
if (isWhitelistedCreatorV1Account(account)) {
|
if (isWhitelistedCreatorV1Account(account)) {
|
||||||
const whitelistedCreator = decodeWhitelistedCreator(account.data);
|
const whitelistedCreator = decodeWhitelistedCreator(account.data);
|
||||||
|
|
||||||
// TODO: figure out a way to avoid generating creator addresses during parsing
|
// TODO: figure out a way to avoid generating creator addresses during parsing
|
||||||
// should we store store id inside creator?
|
// should we store store id inside creator?
|
||||||
const creatorKeyIfCreatorWasPartOfThisStore = await getWhitelistedCreator(
|
const creatorKeyIfCreatorWasPartOfThisStore = await getWhitelistedCreator(
|
||||||
|
|
|
@ -238,6 +238,11 @@ pub enum MetadataInstruction {
|
||||||
/// 15. `[]` System program
|
/// 15. `[]` System program
|
||||||
/// 16. `[]` Rent info
|
/// 16. `[]` Rent info
|
||||||
MintNewEditionFromMasterEditionViaVaultProxy(MintNewEditionFromMasterEditionViaTokenArgs),
|
MintNewEditionFromMasterEditionViaVaultProxy(MintNewEditionFromMasterEditionViaTokenArgs),
|
||||||
|
|
||||||
|
/// Puff a Metadata - make all of it's variable length fields (name/uri/symbol) a fixed length using a null character
|
||||||
|
/// so that it can be found using offset searches by the RPC to make client lookups cheaper.
|
||||||
|
/// 0. `[writable]` Metadata account
|
||||||
|
PuffMetadata,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates an CreateMetadataAccounts instruction
|
/// Creates an CreateMetadataAccounts instruction
|
||||||
|
@ -308,6 +313,22 @@ pub fn update_metadata_accounts(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// puff metadata account instruction
|
||||||
|
pub fn puff_metadata_account(
|
||||||
|
program_id: Pubkey,
|
||||||
|
metadata_account: Pubkey,
|
||||||
|
) -> Instruction {
|
||||||
|
Instruction {
|
||||||
|
program_id,
|
||||||
|
accounts: vec![
|
||||||
|
AccountMeta::new(metadata_account, false),
|
||||||
|
],
|
||||||
|
data: MetadataInstruction::PuffMetadata
|
||||||
|
.try_to_vec()
|
||||||
|
.unwrap(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// creates a update_primary_sale_happened_via_token instruction
|
/// creates a update_primary_sale_happened_via_token instruction
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn update_primary_sale_happened_via_token(
|
pub fn update_primary_sale_happened_via_token(
|
||||||
|
|
|
@ -130,6 +130,13 @@ pub fn process_instruction<'a>(
|
||||||
args.edition,
|
args.edition,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
MetadataInstruction::PuffMetadata => {
|
||||||
|
msg!("Instruction: Puff Metadata");
|
||||||
|
process_puff_metadata_account(
|
||||||
|
program_id,
|
||||||
|
accounts
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -570,3 +577,22 @@ pub fn process_mint_new_edition_from_master_edition_via_vault_proxy<'a>(
|
||||||
|
|
||||||
process_mint_new_edition_from_master_edition_via_token_logic(program_id, args, edition, true)
|
process_mint_new_edition_from_master_edition_via_token_logic(program_id, args, edition, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Puff out the variable length fields to a fixed length on a metadata
|
||||||
|
/// account in a permissionless way.
|
||||||
|
pub fn process_puff_metadata_account(
|
||||||
|
program_id: &Pubkey,
|
||||||
|
accounts: &[AccountInfo],
|
||||||
|
) -> ProgramResult {
|
||||||
|
let account_info_iter = &mut accounts.iter();
|
||||||
|
|
||||||
|
let metadata_account_info = next_account_info(account_info_iter)?;
|
||||||
|
let mut metadata = Metadata::from_account_info(metadata_account_info)?;
|
||||||
|
|
||||||
|
assert_owned_by(metadata_account_info, program_id)?;
|
||||||
|
|
||||||
|
puff_out_data_fields(&mut metadata);
|
||||||
|
|
||||||
|
metadata.serialize(&mut *metadata_account_info.data.borrow_mut())?;
|
||||||
|
Ok(())
|
||||||
|
}
|
|
@ -23,17 +23,63 @@ use {
|
||||||
spl_token_metadata::{
|
spl_token_metadata::{
|
||||||
instruction::{
|
instruction::{
|
||||||
create_master_edition, create_metadata_accounts,
|
create_master_edition, create_metadata_accounts,
|
||||||
mint_new_edition_from_master_edition_via_token, update_metadata_accounts,
|
mint_new_edition_from_master_edition_via_token, update_metadata_accounts,puff_metadata_account
|
||||||
},
|
},
|
||||||
state::{
|
state::{
|
||||||
get_reservation_list, Data, Edition, Key, MasterEditionV1, MasterEditionV2, Metadata,
|
get_reservation_list, Data, Edition, Key, MasterEditionV1, MasterEditionV2, Metadata,
|
||||||
EDITION, PREFIX,
|
EDITION, PREFIX,MAX_NAME_LENGTH, MAX_URI_LENGTH, MAX_SYMBOL_LENGTH
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
std::str::FromStr,
|
std::str::FromStr,
|
||||||
};
|
};
|
||||||
|
|
||||||
const TOKEN_PROGRAM_PUBKEY: &str = "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA";
|
const TOKEN_PROGRAM_PUBKEY: &str = "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA";
|
||||||
|
fn puff_unpuffed_metadata(_app_matches: &ArgMatches, payer: Keypair, client: RpcClient) {
|
||||||
|
let metadata_accounts = client.get_program_accounts(&spl_token_metadata::id()).unwrap();
|
||||||
|
let mut needing_puffing = vec![];
|
||||||
|
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 {
|
||||||
|
needing_puffing.push(acct.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!("Found {} accounts needing puffing", needing_puffing.len());
|
||||||
|
|
||||||
|
let mut instructions = vec![];
|
||||||
|
let mut i = 0;
|
||||||
|
while i < needing_puffing.len() {
|
||||||
|
let pubkey = needing_puffing[i];
|
||||||
|
instructions.push(puff_metadata_account(spl_token_metadata::id(), pubkey));
|
||||||
|
if instructions.len() == 20 {
|
||||||
|
let mut transaction = Transaction::new_with_payer(&instructions, Some(&payer.pubkey()));
|
||||||
|
let recent_blockhash = client.get_recent_blockhash().unwrap().0;
|
||||||
|
|
||||||
|
transaction.sign(&[&payer], recent_blockhash);
|
||||||
|
match client.send_and_confirm_transaction(&transaction) {
|
||||||
|
Ok(_) => {
|
||||||
|
println!("Another 20 down. At {} / {}", i, needing_puffing.len());
|
||||||
|
instructions = vec![];
|
||||||
|
i += 1;
|
||||||
|
},
|
||||||
|
Err(_) => {
|
||||||
|
println!("Txn failed. Retry.");
|
||||||
|
std::thread::sleep(std::time::Duration::from_millis(1000));
|
||||||
|
},
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if instructions.len() > 0 {
|
||||||
|
let mut transaction = Transaction::new_with_payer(&instructions, Some(&payer.pubkey()));
|
||||||
|
let recent_blockhash = client.get_recent_blockhash().unwrap().0;
|
||||||
|
transaction.sign(&[&payer], recent_blockhash);
|
||||||
|
client.send_and_confirm_transaction(&transaction).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn mint_coins(app_matches: &ArgMatches, payer: Keypair, client: RpcClient) {
|
fn mint_coins(app_matches: &ArgMatches, payer: Keypair, client: RpcClient) {
|
||||||
let token_key = Pubkey::from_str(TOKEN_PROGRAM_PUBKEY).unwrap();
|
let token_key = Pubkey::from_str(TOKEN_PROGRAM_PUBKEY).unwrap();
|
||||||
|
@ -780,7 +826,10 @@ fn main() {
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.help("Account's authority, defaults to you"),
|
.help("Account's authority, defaults to you"),
|
||||||
)
|
)
|
||||||
).get_matches();
|
|
||||||
|
).subcommand(
|
||||||
|
SubCommand::with_name("puff_unpuffed_metadata")
|
||||||
|
.about("Take metadata that still have variable length name, symbol, and uri fields and stretch them out with null symbols so they can be searched more easily by RPC.")).get_matches();
|
||||||
|
|
||||||
let client = RpcClient::new(
|
let client = RpcClient::new(
|
||||||
app_matches
|
app_matches
|
||||||
|
@ -831,6 +880,9 @@ fn main() {
|
||||||
("mint_coins", Some(arg_matches)) => {
|
("mint_coins", Some(arg_matches)) => {
|
||||||
mint_coins(arg_matches, payer, client);
|
mint_coins(arg_matches, payer, client);
|
||||||
}
|
}
|
||||||
|
("puff_unpuffed_metadata", Some(arg_matches)) => {
|
||||||
|
puff_unpuffed_metadata(arg_matches, payer, client);
|
||||||
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue