Solana DApp开发之 获取各种account数据的方式

2,283 阅读2分钟

简介

本文暂未未经过精细处理 本人手稿 先发布下 日后整理

对于NFT开发来说,一般遵守metaplex规范,我回顾下上架大概设计状态的流程

1: 先创建一个metaDataAccount账户

2: 基于metadata再创建token(nft)

3: metadata publickey就是nft通用的key

4: MasterEdition是追加上去的,里面包含maxSupply

下面数据是我们做pu on slae时候用得到的一些获取数据方式,官方mateplex代码不太行,是全网爬取 数据很慢的,下面是针对性上架需要的数据获取方式。

获取metadata数据

const account = await connection.getAccountInfo(
	new PublicKey('FgErmGp6ZR9G72rUZhRPK7gJTzwPttq85zk9haDsefFT'),
);
console.log(decodeMetadata(account.data));

nft地址mint

获取master edition数据

Solana-web3库有点bug,无法直接获取json类型的数据,顾不得已使用下面方式,之后我会给web3提pr的。

const masterEditionAccount = await connection.getAccountInfo(
    new PublicKey('JBRtQ3BabStLi1dJsGpmfwQTQEFvi4ZmRkJ2pNNzj8xu'),
);
if (masterEditionAccount) {
    console.log('master edtion');
    console.log(
        decodeMasterEdition(masterEditionAccount.data),
        masterEditionAccount,
    );
}

使用metaDataAccount publickey 获取 master edition

export const getAccountInfo = (publicKey: string) => {
    return axios.post(ENDPOINTS[0].endpoint, {
      method: 'getAccountInfo',
      jsonrpc: '2.0',
      params: [publicKey, { encoding: 'jsonParsed' }],
      // TODO
      id: '5b5044f3-b12b-4904-8d79-a2affae6247b',
    });
};
  
export const accountGetMasterEditionInfo = async ({publicKey, connection}: {publicKey: string, connection: Connection}) => {
  const account = await connection.getAccountInfo(
        new PublicKey(publicKey),
        'confirmed',
      );
  if (account && account?.data) {
    const nftInfo = await getAccountInfo(decodeMetadata(account.data).mint);
    const masterKey: string =
      nftInfo.data?.result.value.data.parsed.info.mintAuthority;
    if (masterKey) {
      const masterEditionAccount = await connection.getAccountInfo(
        new PublicKey(masterKey),
      );
      if (masterEditionAccount) {
        const masterEditionAccountData = decodeMasterEdition(
          masterEditionAccount.data,
        );
        return {
          masterEditionAccountData,
          masterEditionAccount
        }
      }
    }
  }
}

exp

const masterEdition = await accountGetMasterEditionInfo({
    publicKey: 'FgErmGp6ZR9G72rUZhRPK7gJTzwPttq85zk9haDsefFT',
    connection,
});

console.log('---masterEdition-----> ', masterEdition);

MasterEdition 方式2

这里主要是优化速度,获取masterEdition地址是可以通过计算得到的,代码如下

export const getMasterEdition = async (mint: PublicKey): Promise<PublicKey> => {
  return (
    await PublicKey.findProgramAddress(
      [
        Buffer.from('metadata'),
        TOKEN_METADATA_PROGRAM_ID.toBuffer(),
        mint.toBuffer(),
        Buffer.from('edition'),
      ],
      TOKEN_METADATA_PROGRAM_ID,
    )
  )[0];
};

export const accountGetMasterEditionInfo = async ({
  publicKey,
  connection,
}: {
  publicKey: string;
  connection: Connection;
}) => {
  const account = await connection.getAccountInfo(
    new PublicKey(publicKey),
    'confirmed',
  );
  if (account && account?.data) {
    const masterKey = (
      await getMasterEdition(new PublicKey(decodeMetadata(account.data).mint))
    ).toBase58();
    if (masterKey) {
      const masterEditionAccount = await connection.getAccountInfo(
        new PublicKey(masterKey),
      );
      if (masterEditionAccount) {
        const masterEditionAccountData = decodeMasterEdition(
          masterEditionAccount.data,
        );
        // cache
        localforage.setItem(
          getDbTableStoreName(DB_TABLES.masterEditions, masterKey),
          JSON.stringify(masterEditionAccountData),
        );
        return {
          masterEditionAccountData,
          masterEditionAccount,
          masterKey,
        };
      }
    }
  }
};

edition

获取地址

export const accountGetEditionInfo = async ({
  parentPubkey,
  connection,
}: {
  parentPubkey: string;
  connection: Connection;
}) => {
  const res = await getProgramAccounts(connection, METADATA_PROGRAM_ID, {
    filters: [
      {
        memcmp: {
          offset: 0,
          bytes: base58.encode(new Uint8Array([MetadataKey.EditionV1])),
        },
      },
      {
        memcmp: {
          offset: 1,
          bytes: parentPubkey,
        },
      },
    ],
  });
  return res;
}

获取具体数据

creator

export const getCreators = async ({
  connection,
}: {
  connection: Connection;
}) => {
  const _creators = await getProgramAccounts(connection, METAPLEX_ID, {
    filters: [
      {
        dataSize: MAX_WHITELISTED_CREATOR_SIZE,
      },
    ],
  });
  let creators: {
    address: string;
    account: ParsedAccount<WhitelistedCreator>;
  }[] = [];
  for (const creator of _creators) {
    await processMetaplexAccounts(
      creator,
      (key, address, account) => {
        creators.push({ address, account });
      },
      false,
    );
  }
  return creators;
};


const creators = (await getCreators({ connection })).map(e => {
    return {
        ...e,
        accountData: decodeWhitelistedCreator(e.account.account.data),
    };
});
console.log('---creators---');
console.log(creators);

这一块数据建议放redux里面,用的地方蛮多的,比如put on sale和admin都需要用。

const storeWhiteCreators = useSelector(
    (state: RootState) => state.user.storeWhiteCreators,
);

console.log('storeWhiteCreators----->', storeWhiteCreators);