import { deserializeUnchecked } from 'borsh'; import { BN, web3 } from '@project-serum/anchor'; // eslint-disable-next-line export const METADATA_REPLACE = new RegExp('\u0000', 'g'); export class Creator { address: web3.PublicKey; verified: boolean; share: number; constructor(args: { address: web3.PublicKey; verified: boolean; share: number }) { this.address = args.address; this.verified = args.verified; this.share = args.share; } } export enum MetadataKey { Uninitialized = 0, MetadataV1 = 4, EditionV1 = 1, MasterEditionV1 = 2, MasterEditionV2 = 6, EditionMarker = 7 } export class MasterEditionV2 { key: MetadataKey; supply: BN; maxSupply?: BN; constructor(args: { key: MetadataKey; supply: BN; maxSupply?: BN }) { this.key = MetadataKey.MasterEditionV2; this.supply = args.supply; this.maxSupply = args.maxSupply; } } export class EditionMarker { key: MetadataKey; ledger: number[]; constructor(args: { key: MetadataKey; ledger: number[] }) { this.key = MetadataKey.EditionMarker; this.ledger = args.ledger; } } export class Edition { key: MetadataKey; parent: web3.PublicKey; edition: BN; constructor(args: { key: MetadataKey; parent: web3.PublicKey; edition: BN }) { this.key = MetadataKey.EditionV1; this.parent = args.parent; this.edition = args.edition; } } export 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; } } export class Metadata { key: MetadataKey; updateAuthority: web3.PublicKey; mint: web3.PublicKey; data: Data; primarySaleHappened: boolean; isMutable: boolean; masterEdition?: web3.PublicKey; edition?: web3.PublicKey; constructor(args: { updateAuthority: web3.PublicKey; mint: web3.PublicKey; data: Data; primarySaleHappened: boolean; isMutable: boolean; masterEdition?: web3.PublicKey; }) { this.key = MetadataKey.MetadataV1; this.updateAuthority = args.updateAuthority; this.mint = args.mint; this.data = args.data; this.primarySaleHappened = args.primarySaleHappened; this.isMutable = args.isMutable; } } export const METADATA_SCHEMA = new Map([ [ MasterEditionV2, { kind: 'struct', fields: [ ['key', 'u8'], ['supply', 'u64'], ['maxSupply', { kind: 'option', type: 'u64' }] ] } ], [ Edition, { kind: 'struct', fields: [ ['key', 'u8'], ['parent', [32]], ['edition', 'u64'] ] } ], [ Data, { kind: 'struct', fields: [ ['name', 'string'], ['symbol', 'string'], ['uri', 'string'], ['sellerFeeBasisPoints', 'u16'], ['creators', { kind: 'option', type: [Creator] }] ] } ], [ Creator, { kind: 'struct', fields: [ ['address', [32]], ['verified', 'u8'], ['share', 'u8'] ] } ], [ Metadata, { kind: 'struct', fields: [ ['key', 'u8'], ['updateAuthority', [32]], ['mint', [32]], ['data', Data], ['primarySaleHappened', 'u8'], ['isMutable', 'u8'] ] } ], [ EditionMarker, { kind: 'struct', fields: [ ['key', 'u8'], ['ledger', [31]] ] } ] ]); export type AssetKey = { mediaExt: string; index: string }; export const parseMasterEditionV2 = (buffer: Buffer) => { return deserializeUnchecked(METADATA_SCHEMA, MasterEditionV2, buffer); }; export const parseMetadata = (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 const parseEditionMarker = (buffer: Buffer): EditionMarker => { const editionMarker = deserializeUnchecked(METADATA_SCHEMA, EditionMarker, buffer) as EditionMarker; return editionMarker; }; export const parseEdition = (buffer: Buffer) => { return deserializeUnchecked(METADATA_SCHEMA, Edition, buffer) as Edition; };