@symmetry-hq/baskets-v2-sdk
Version:
Symmetry Baskets V2 SDK
197 lines (179 loc) • 5.37 kB
text/typescript
/**
* This blob of a file is pulled together from different files from the metaplex
* repository.
* Metaplex does not have a NPM package at the current time to make this easier, so instead of
* trying to reference their stuff, I copied all of the minimum necessary code into this file
*/
import { BinaryReader, BinaryWriter, deserializeUnchecked } from "borsh";
import { Connection, PublicKey } from "@solana/web3.js";
import { bs58 } from "@coral-xyz/anchor/dist/cjs/utils/bytes";
export const METADATA_PROGRAM_ID = "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s" as StringPublicKey;
export const METADATA_PREFIX = "metadata";
// Borsh extension for pubkey stuff
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(BinaryReader.prototype as any).readPubkey = function () {
const reader = this as unknown as BinaryReader;
const array = reader.readFixedArray(32);
return new PublicKey(array);
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(BinaryWriter.prototype as any).writePubkey = function (value: PublicKey) {
const writer = this as unknown as BinaryWriter;
writer.writeFixedArray(value.toBuffer());
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(BinaryReader.prototype as any).readPubkeyAsString = function () {
const reader = this as unknown as BinaryReader;
const array = reader.readFixedArray(32);
return bs58.encode(array) as StringPublicKey;
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(BinaryWriter.prototype as any).writePubkeyAsString = function (
value: StringPublicKey
) {
const writer = this as unknown as BinaryWriter;
writer.writeFixedArray(bs58.decode(value));
};
export type StringPublicKey = string;
export enum MetadataKey {
Uninitialized = 0,
MetadataV1 = 4,
EditionV1 = 1,
MasterEditionV1 = 2,
MasterEditionV2 = 6,
EditionMarker = 7,
}
class Creator {
address: StringPublicKey;
verified: boolean;
share: number;
constructor(args: {
address: StringPublicKey;
verified: boolean;
share: number;
}) {
this.address = args.address;
this.verified = args.verified;
this.share = args.share;
}
}
class Data {
name: string;
symbol: string;
uri: string;
sellerFeeBasisPoints: number;
creators: Creator[] | null;
constructor(args: {
name: string;
symbol: string;
uri: string;
sellerFeeBasisPoints: number;
creators: Creator[] | null;
}) {
this.name = args.name;
this.symbol = args.symbol;
this.uri = args.uri;
this.sellerFeeBasisPoints = args.sellerFeeBasisPoints;
this.creators = args.creators;
}
}
class Metadata {
key: MetadataKey;
updateAuthority: StringPublicKey;
mint: StringPublicKey;
data: Data;
primarySaleHappened: boolean;
isMutable: boolean;
editionNonce: number | null;
// set lazy
masterEdition?: StringPublicKey;
edition?: StringPublicKey;
constructor(args: {
updateAuthority: StringPublicKey;
mint: StringPublicKey;
data: Data;
primarySaleHappened: boolean;
isMutable: boolean;
editionNonce: number | null;
}) {
this.key = MetadataKey.MetadataV1;
this.updateAuthority = args.updateAuthority;
this.mint = args.mint;
this.data = args.data;
this.primarySaleHappened = args.primarySaleHappened;
this.isMutable = args.isMutable;
this.editionNonce = args.editionNonce;
}
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const METADATA_SCHEMA = new Map<any, any>([
[
Data,
{
kind: "struct",
fields: [
["name", "string"],
["symbol", "string"],
["uri", "string"],
["sellerFeeBasisPoints", "u16"],
["creators", { kind: "option", type: [Creator] }],
],
},
],
[
Creator,
{
kind: "struct",
fields: [
["address", "pubkeyAsString"],
["verified", "u8"],
["share", "u8"],
],
},
],
[
Metadata,
{
kind: "struct",
fields: [
["key", "u8"],
["updateAuthority", "pubkeyAsString"],
["mint", "pubkeyAsString"],
["data", Data],
["primarySaleHappened", "u8"], // bool
["isMutable", "u8"], // bool
],
},
],
]);
// eslint-disable-next-line no-control-regex
const METADATA_REPLACE = new RegExp("\u0000", "g");
export const decodeMetadata = (buffer: Buffer): Metadata => {
const metadata = deserializeUnchecked(
METADATA_SCHEMA,
Metadata,
buffer
) as Metadata;
metadata.data.name = metadata.data.name.replace(METADATA_REPLACE, "");
metadata.data.uri = metadata.data.uri.replace(METADATA_REPLACE, "");
metadata.data.symbol = metadata.data.symbol.replace(METADATA_REPLACE, "");
return metadata;
};
export async function parseMetadata(
connection: Connection,
metadataAccount: PublicKey // eslint-disable-next-line @typescript-eslint/no-explicit-any
): Promise<any> {
const metadataBuffer = await connection.getAccountInfo(metadataAccount, "confirmed");
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
const metadata = decodeMetadata(metadataBuffer?.data);
let json = {};
try {
const parsed = await fetch(metadata.data.uri)
json = await parsed.json();
} catch (e) { console.log(e); }
return {
...metadata.data,
parsed: json,
};
}