1023 lines
22 KiB
TypeScript
1023 lines
22 KiB
TypeScript
import {
|
|
PublicKey,
|
|
SystemProgram,
|
|
SYSVAR_RENT_PUBKEY,
|
|
TransactionInstruction,
|
|
} from '@solana/web3.js';
|
|
import { programIds, PROGRAM_IDS } from '../utils/ids';
|
|
import { deserializeUnchecked, serialize } from 'borsh';
|
|
import BN from 'bn.js';
|
|
export const METADATA_PREFIX = 'metadata';
|
|
export const EDITION = 'edition';
|
|
export const RESERVATION = 'reservation';
|
|
|
|
export const MAX_NAME_LENGTH = 32;
|
|
|
|
export const MAX_SYMBOL_LENGTH = 10;
|
|
|
|
export const MAX_URI_LENGTH = 200;
|
|
|
|
export const MAX_CREATOR_LIMIT = 5;
|
|
|
|
export const MAX_CREATOR_LEN = 32 + 1 + 1;
|
|
|
|
export const MAX_METADATA_LEN =
|
|
1 +
|
|
32 +
|
|
32 +
|
|
MAX_NAME_LENGTH +
|
|
MAX_SYMBOL_LENGTH +
|
|
MAX_URI_LENGTH +
|
|
MAX_CREATOR_LIMIT * MAX_CREATOR_LEN +
|
|
1 +
|
|
1 +
|
|
200;
|
|
|
|
export const MAX_MASTER_EDITION_KEN = 1 + 9 + 8 + 32 + 32;
|
|
|
|
export enum MetadataKey {
|
|
MetadataV1 = 0,
|
|
EditionV1 = 1,
|
|
MasterEditionV1 = 2,
|
|
ReservationListV1 = 3,
|
|
}
|
|
|
|
export enum MetadataCategory {
|
|
Audio = 'audio',
|
|
Video = 'video',
|
|
Image = 'image',
|
|
VR = 'vr',
|
|
}
|
|
|
|
type FileOrString = File | string;
|
|
|
|
export interface IMetadataExtension {
|
|
name: string;
|
|
symbol: string;
|
|
|
|
creators: Creator[] | null;
|
|
description: string;
|
|
// preview image absolute URI
|
|
image: string;
|
|
// stores link to item on meta
|
|
external_url: string;
|
|
|
|
seller_fee_basis_points: number;
|
|
|
|
properties: {
|
|
files?: FileOrString[];
|
|
category: MetadataCategory;
|
|
maxSupply?: number;
|
|
creators?: {
|
|
address: string;
|
|
verified: boolean;
|
|
shares: number;
|
|
}[];
|
|
};
|
|
}
|
|
|
|
export class MasterEdition {
|
|
key: MetadataKey;
|
|
supply: BN;
|
|
maxSupply?: BN;
|
|
/// Can be used to mint tokens that give one-time permission to mint a single limited edition.
|
|
printingMint: PublicKey;
|
|
/// If you don't know how many printing tokens you are going to need, but you do know
|
|
/// you are going to need some amount in the future, you can use a token from this mint.
|
|
/// Coming back to token metadata with one of these tokens allows you to mint (one time)
|
|
/// any number of printing tokens you want. This is used for instance by Auction Manager
|
|
/// with participation NFTs, where we dont know how many people will bid and need participation
|
|
/// printing tokens to redeem, so we give it ONE of these tokens to use after the auction is over,
|
|
/// because when the auction begins we just dont know how many printing tokens we will need,
|
|
/// but at the end we will. At the end it then burns this token with token-metadata to
|
|
/// get the printing tokens it needs to give to bidders. Each bidder then redeems a printing token
|
|
/// to get their limited editions.
|
|
oneTimePrintingAuthorizationMint: PublicKey;
|
|
|
|
constructor(args: {
|
|
key: MetadataKey;
|
|
supply: BN;
|
|
maxSupply?: BN;
|
|
printingMint: PublicKey;
|
|
oneTimePrintingAuthorizationMint: PublicKey;
|
|
}) {
|
|
this.key = MetadataKey.MasterEditionV1;
|
|
this.supply = args.supply;
|
|
this.maxSupply = args.maxSupply;
|
|
this.printingMint = args.printingMint;
|
|
this.oneTimePrintingAuthorizationMint =
|
|
args.oneTimePrintingAuthorizationMint;
|
|
}
|
|
}
|
|
|
|
export class Edition {
|
|
key: MetadataKey;
|
|
/// Points at MasterEdition struct
|
|
parent: PublicKey;
|
|
/// Starting at 0 for master record, this is incremented for each edition minted.
|
|
edition: BN;
|
|
|
|
constructor(args: { key: MetadataKey; parent: PublicKey; edition: BN }) {
|
|
this.key = MetadataKey.EditionV1;
|
|
this.parent = args.parent;
|
|
this.edition = args.edition;
|
|
}
|
|
}
|
|
export class Reservation {
|
|
address: PublicKey;
|
|
spotsRemaining: number;
|
|
totalSpots: number;
|
|
constructor(args: {
|
|
address: PublicKey;
|
|
spotsRemaining: number;
|
|
totalSpots: number;
|
|
}) {
|
|
this.address = args.address;
|
|
this.spotsRemaining = args.spotsRemaining;
|
|
this.totalSpots = args.totalSpots;
|
|
}
|
|
}
|
|
|
|
export class ReservationList {
|
|
key: MetadataKey = MetadataKey.ReservationListV1;
|
|
/// Present for reverse lookups
|
|
masterEdition: PublicKey;
|
|
|
|
/// What supply counter was on master_edition when this reservation was created.
|
|
supplySnapshot: BN | null;
|
|
reservations: Reservation[];
|
|
|
|
constructor(args: {
|
|
key: MetadataKey;
|
|
masterEdition: PublicKey;
|
|
supplySnapshot: BN | null;
|
|
reservations: Reservation[];
|
|
}) {
|
|
this.key = MetadataKey.EditionV1;
|
|
this.masterEdition = args.masterEdition;
|
|
this.supplySnapshot = args.supplySnapshot;
|
|
this.reservations = args.reservations;
|
|
}
|
|
}
|
|
|
|
export class Creator {
|
|
address: PublicKey;
|
|
verified: boolean;
|
|
share: number;
|
|
|
|
constructor(args: { address: PublicKey; verified: boolean; share: number }) {
|
|
this.address = args.address;
|
|
this.verified = args.verified;
|
|
this.share = args.share;
|
|
}
|
|
}
|
|
|
|
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: PublicKey;
|
|
mint: PublicKey;
|
|
data: Data;
|
|
primarySaleHappened: boolean;
|
|
isMutable: boolean;
|
|
|
|
extended?: IMetadataExtension;
|
|
masterEdition?: PublicKey;
|
|
edition?: PublicKey;
|
|
constructor(args: {
|
|
updateAuthority: PublicKey;
|
|
mint: PublicKey;
|
|
data: Data;
|
|
primarySaleHappened: boolean;
|
|
isMutable: boolean;
|
|
}) {
|
|
this.key = MetadataKey.MetadataV1;
|
|
this.updateAuthority = args.updateAuthority;
|
|
this.mint = args.mint;
|
|
this.data = args.data;
|
|
this.primarySaleHappened = args.primarySaleHappened;
|
|
this.isMutable = args.isMutable;
|
|
}
|
|
}
|
|
|
|
class CreateMetadataArgs {
|
|
instruction: number = 0;
|
|
data: Data;
|
|
isMutable: boolean;
|
|
|
|
constructor(args: { data: Data; isMutable: boolean }) {
|
|
this.data = args.data;
|
|
this.isMutable = args.isMutable;
|
|
}
|
|
}
|
|
class UpdateMetadataArgs {
|
|
instruction: number = 1;
|
|
data: Data | null;
|
|
// Not used by this app, just required for instruction
|
|
updateAuthority: PublicKey | null;
|
|
primarySaleHappened: boolean | null;
|
|
constructor(args: {
|
|
data?: Data;
|
|
updateAuthority?: string;
|
|
primarySaleHappened: boolean | null;
|
|
}) {
|
|
this.data = args.data ? args.data : null;
|
|
this.updateAuthority = args.updateAuthority
|
|
? new PublicKey(args.updateAuthority)
|
|
: null;
|
|
this.primarySaleHappened = args.primarySaleHappened;
|
|
}
|
|
}
|
|
|
|
class CreateMasterEditionArgs {
|
|
instruction: number = 2;
|
|
maxSupply: BN | null;
|
|
constructor(args: { maxSupply: BN | null }) {
|
|
this.maxSupply = args.maxSupply;
|
|
}
|
|
}
|
|
|
|
class MintPrintingTokensArgs {
|
|
instruction: number = 9;
|
|
supply: BN;
|
|
|
|
constructor(args: { supply: BN }) {
|
|
this.supply = args.supply;
|
|
}
|
|
}
|
|
|
|
export const METADATA_SCHEMA = new Map<any, any>([
|
|
[
|
|
CreateMetadataArgs,
|
|
{
|
|
kind: 'struct',
|
|
fields: [
|
|
['instruction', 'u8'],
|
|
['data', Data],
|
|
['isMutable', 'u8'], // bool
|
|
],
|
|
},
|
|
],
|
|
[
|
|
UpdateMetadataArgs,
|
|
{
|
|
kind: 'struct',
|
|
fields: [
|
|
['instruction', 'u8'],
|
|
['data', { kind: 'option', type: Data }],
|
|
['updateAuthority', { kind: 'option', type: 'pubkey' }],
|
|
['primarySaleHappened', { kind: 'option', type: 'u8' }],
|
|
],
|
|
},
|
|
],
|
|
|
|
[
|
|
CreateMasterEditionArgs,
|
|
{
|
|
kind: 'struct',
|
|
fields: [
|
|
['instruction', 'u8'],
|
|
['maxSupply', { kind: 'option', type: 'u64' }],
|
|
],
|
|
},
|
|
],
|
|
[
|
|
MintPrintingTokensArgs,
|
|
{
|
|
kind: 'struct',
|
|
fields: [
|
|
['instruction', 'u8'],
|
|
['supply', 'u64'],
|
|
],
|
|
},
|
|
],
|
|
[
|
|
MasterEdition,
|
|
{
|
|
kind: 'struct',
|
|
fields: [
|
|
['key', 'u8'],
|
|
['supply', 'u64'],
|
|
['maxSupply', { kind: 'option', type: 'u64' }],
|
|
['printingMint', 'pubkey'],
|
|
['oneTimePrintingAuthorizationMint', 'pubkey'],
|
|
],
|
|
},
|
|
],
|
|
[
|
|
Edition,
|
|
{
|
|
kind: 'struct',
|
|
fields: [
|
|
['key', 'u8'],
|
|
['parent', 'pubkey'],
|
|
['edition', 'u64'],
|
|
],
|
|
},
|
|
],
|
|
[
|
|
Data,
|
|
{
|
|
kind: 'struct',
|
|
fields: [
|
|
['name', 'string'],
|
|
['symbol', 'string'],
|
|
['uri', 'string'],
|
|
['sellerFeeBasisPoints', 'u16'],
|
|
['creators', { kind: 'option', type: [Creator] }],
|
|
],
|
|
},
|
|
],
|
|
[
|
|
Creator,
|
|
{
|
|
kind: 'struct',
|
|
fields: [
|
|
['address', 'pubkey'],
|
|
['verified', 'u8'],
|
|
['share', 'u8'],
|
|
],
|
|
},
|
|
],
|
|
[
|
|
Metadata,
|
|
{
|
|
kind: 'struct',
|
|
fields: [
|
|
['key', 'u8'],
|
|
['updateAuthority', 'pubkey'],
|
|
['mint', 'pubkey'],
|
|
['data', Data],
|
|
['primarySaleHappened', 'u8'], // bool
|
|
['isMutable', 'u8'], // bool
|
|
],
|
|
},
|
|
],
|
|
[
|
|
Reservation,
|
|
{
|
|
kind: 'struct',
|
|
fields: [
|
|
['address', 'pubkey'],
|
|
['spotsRemaining', 'u8'],
|
|
['totalSpots', 'u8'],
|
|
],
|
|
},
|
|
],
|
|
[
|
|
ReservationList,
|
|
{
|
|
kind: 'struct',
|
|
fields: [
|
|
['key', 'u8'],
|
|
['masterEdition', 'pubkey'],
|
|
['supplySnapshot', { kind: 'option', type: 'u64' }],
|
|
['reservations', [Reservation]],
|
|
],
|
|
},
|
|
],
|
|
]);
|
|
|
|
export const decodeMetadata = async (buffer: Buffer): Promise<Metadata> => {
|
|
const metadata = deserializeUnchecked(
|
|
METADATA_SCHEMA,
|
|
Metadata,
|
|
buffer,
|
|
) as Metadata;
|
|
metadata.edition = await getEdition(metadata.mint);
|
|
metadata.masterEdition = await getEdition(metadata.mint);
|
|
return metadata;
|
|
};
|
|
|
|
export const decodeEdition = (buffer: Buffer) => {
|
|
return deserializeUnchecked(METADATA_SCHEMA, Edition, buffer) as Edition;
|
|
};
|
|
|
|
export const decodeMasterEdition = (buffer: Buffer) => {
|
|
return deserializeUnchecked(
|
|
METADATA_SCHEMA,
|
|
MasterEdition,
|
|
buffer,
|
|
) as MasterEdition;
|
|
};
|
|
|
|
export async function updateMetadata(
|
|
data: Data | undefined,
|
|
newUpdateAuthority: string | undefined,
|
|
primarySaleHappened: boolean | null | undefined,
|
|
mintKey: PublicKey,
|
|
updateAuthority: PublicKey,
|
|
instructions: TransactionInstruction[],
|
|
metadataAccount?: PublicKey,
|
|
) {
|
|
const metadataProgramId = programIds().metadata;
|
|
|
|
metadataAccount =
|
|
metadataAccount ||
|
|
(
|
|
await PublicKey.findProgramAddress(
|
|
[
|
|
Buffer.from('metadata'),
|
|
metadataProgramId.toBuffer(),
|
|
mintKey.toBuffer(),
|
|
],
|
|
metadataProgramId,
|
|
)
|
|
)[0];
|
|
|
|
const value = new UpdateMetadataArgs({
|
|
data,
|
|
updateAuthority: !newUpdateAuthority ? undefined : newUpdateAuthority,
|
|
primarySaleHappened:
|
|
primarySaleHappened === null || primarySaleHappened === undefined
|
|
? null
|
|
: primarySaleHappened,
|
|
});
|
|
const txnData = Buffer.from(serialize(METADATA_SCHEMA, value));
|
|
const keys = [
|
|
{
|
|
pubkey: metadataAccount,
|
|
isSigner: false,
|
|
isWritable: true,
|
|
},
|
|
{
|
|
pubkey: updateAuthority,
|
|
isSigner: true,
|
|
isWritable: false,
|
|
},
|
|
];
|
|
instructions.push(
|
|
new TransactionInstruction({
|
|
keys,
|
|
programId: metadataProgramId,
|
|
data: txnData,
|
|
}),
|
|
);
|
|
|
|
return metadataAccount;
|
|
}
|
|
|
|
export async function createMetadata(
|
|
data: Data,
|
|
updateAuthority: PublicKey,
|
|
mintKey: PublicKey,
|
|
mintAuthorityKey: PublicKey,
|
|
instructions: TransactionInstruction[],
|
|
payer: PublicKey,
|
|
) {
|
|
const metadataProgramId = programIds().metadata;
|
|
|
|
const metadataAccount = (
|
|
await PublicKey.findProgramAddress(
|
|
[
|
|
Buffer.from('metadata'),
|
|
metadataProgramId.toBuffer(),
|
|
mintKey.toBuffer(),
|
|
],
|
|
metadataProgramId,
|
|
)
|
|
)[0];
|
|
console.log('Data', data);
|
|
const value = new CreateMetadataArgs({ data, isMutable: true });
|
|
const txnData = Buffer.from(serialize(METADATA_SCHEMA, value));
|
|
|
|
const keys = [
|
|
{
|
|
pubkey: metadataAccount,
|
|
isSigner: false,
|
|
isWritable: true,
|
|
},
|
|
{
|
|
pubkey: mintKey,
|
|
isSigner: false,
|
|
isWritable: false,
|
|
},
|
|
{
|
|
pubkey: mintAuthorityKey,
|
|
isSigner: true,
|
|
isWritable: false,
|
|
},
|
|
{
|
|
pubkey: payer,
|
|
isSigner: true,
|
|
isWritable: false,
|
|
},
|
|
{
|
|
pubkey: updateAuthority,
|
|
isSigner: false,
|
|
isWritable: false,
|
|
},
|
|
{
|
|
pubkey: SystemProgram.programId,
|
|
isSigner: false,
|
|
isWritable: false,
|
|
},
|
|
{
|
|
pubkey: SYSVAR_RENT_PUBKEY,
|
|
isSigner: false,
|
|
isWritable: false,
|
|
},
|
|
];
|
|
instructions.push(
|
|
new TransactionInstruction({
|
|
keys,
|
|
programId: metadataProgramId,
|
|
data: txnData,
|
|
}),
|
|
);
|
|
|
|
return metadataAccount;
|
|
}
|
|
|
|
export async function createMasterEdition(
|
|
maxSupply: BN | undefined,
|
|
mintKey: PublicKey,
|
|
printingMintKey: PublicKey,
|
|
oneTimePrintingAuthorizationMint: PublicKey,
|
|
updateAuthorityKey: PublicKey,
|
|
mintAuthorityKey: PublicKey,
|
|
instructions: TransactionInstruction[],
|
|
payer: PublicKey,
|
|
printingMintAuthority: PublicKey,
|
|
oneTimePrintingAuthorizationMintAuthority?: PublicKey,
|
|
) {
|
|
const metadataProgramId = programIds().metadata;
|
|
|
|
const metadataAccount = (
|
|
await PublicKey.findProgramAddress(
|
|
[
|
|
Buffer.from(METADATA_PREFIX),
|
|
metadataProgramId.toBuffer(),
|
|
mintKey.toBuffer(),
|
|
],
|
|
metadataProgramId,
|
|
)
|
|
)[0];
|
|
|
|
const editionAccount = (
|
|
await PublicKey.findProgramAddress(
|
|
[
|
|
Buffer.from(METADATA_PREFIX),
|
|
metadataProgramId.toBuffer(),
|
|
mintKey.toBuffer(),
|
|
Buffer.from(EDITION),
|
|
],
|
|
metadataProgramId,
|
|
)
|
|
)[0];
|
|
|
|
const value = new CreateMasterEditionArgs({ maxSupply: maxSupply || null });
|
|
const data = Buffer.from(serialize(METADATA_SCHEMA, value));
|
|
|
|
const keys = [
|
|
{
|
|
pubkey: editionAccount,
|
|
isSigner: false,
|
|
isWritable: true,
|
|
},
|
|
{
|
|
pubkey: mintKey,
|
|
isSigner: false,
|
|
isWritable: true,
|
|
},
|
|
{
|
|
pubkey: printingMintKey,
|
|
isSigner: false,
|
|
isWritable: false,
|
|
},
|
|
{
|
|
pubkey: oneTimePrintingAuthorizationMint,
|
|
isSigner: false,
|
|
isWritable: true,
|
|
},
|
|
{
|
|
pubkey: updateAuthorityKey,
|
|
isSigner: true,
|
|
isWritable: false,
|
|
},
|
|
{
|
|
pubkey: printingMintAuthority,
|
|
isSigner: true,
|
|
isWritable: false,
|
|
},
|
|
{
|
|
pubkey: mintAuthorityKey,
|
|
isSigner: true,
|
|
isWritable: false,
|
|
},
|
|
{
|
|
pubkey: metadataAccount,
|
|
isSigner: false,
|
|
isWritable: false,
|
|
},
|
|
{
|
|
pubkey: payer,
|
|
isSigner: true,
|
|
isWritable: false,
|
|
},
|
|
{
|
|
pubkey: programIds().token,
|
|
isSigner: false,
|
|
isWritable: false,
|
|
},
|
|
{
|
|
pubkey: SystemProgram.programId,
|
|
isSigner: false,
|
|
isWritable: false,
|
|
},
|
|
{
|
|
pubkey: SYSVAR_RENT_PUBKEY,
|
|
isSigner: false,
|
|
isWritable: false,
|
|
},
|
|
];
|
|
|
|
if (oneTimePrintingAuthorizationMintAuthority)
|
|
keys.push({
|
|
pubkey: oneTimePrintingAuthorizationMintAuthority,
|
|
isSigner: true,
|
|
isWritable: false,
|
|
});
|
|
|
|
instructions.push(
|
|
new TransactionInstruction({
|
|
keys,
|
|
programId: metadataProgramId,
|
|
data,
|
|
}),
|
|
);
|
|
}
|
|
|
|
export async function mintNewEditionFromMasterEditionViaToken(
|
|
newMint: PublicKey,
|
|
tokenMint: PublicKey,
|
|
newMintAuthority: PublicKey,
|
|
printingMint: PublicKey,
|
|
authorizationTokenHoldingAccount: PublicKey,
|
|
burnAuthority: PublicKey,
|
|
updateAuthorityOfMaster: PublicKey,
|
|
reservationList: PublicKey | undefined,
|
|
instructions: TransactionInstruction[],
|
|
payer: PublicKey,
|
|
) {
|
|
const metadataProgramId = programIds().metadata;
|
|
|
|
const newMetadataKey = await getMetadata(newMint);
|
|
const masterMetadataKey = await getMetadata(tokenMint);
|
|
const newEdition = await getEdition(newMint);
|
|
const masterEdition = await getEdition(tokenMint);
|
|
|
|
const data = Buffer.from([3]);
|
|
|
|
const keys = [
|
|
{
|
|
pubkey: newMetadataKey,
|
|
isSigner: false,
|
|
isWritable: true,
|
|
},
|
|
{
|
|
pubkey: newEdition,
|
|
isSigner: false,
|
|
isWritable: true,
|
|
},
|
|
{
|
|
pubkey: masterEdition,
|
|
isSigner: false,
|
|
isWritable: true,
|
|
},
|
|
{
|
|
pubkey: newMint,
|
|
isSigner: false,
|
|
isWritable: true,
|
|
},
|
|
{
|
|
pubkey: newMintAuthority,
|
|
isSigner: true,
|
|
isWritable: false,
|
|
},
|
|
{
|
|
pubkey: printingMint,
|
|
isSigner: false,
|
|
isWritable: true,
|
|
},
|
|
{
|
|
pubkey: authorizationTokenHoldingAccount,
|
|
isSigner: false,
|
|
isWritable: true,
|
|
},
|
|
{
|
|
pubkey: burnAuthority,
|
|
isSigner: true,
|
|
isWritable: false,
|
|
},
|
|
{
|
|
pubkey: payer,
|
|
isSigner: true,
|
|
isWritable: false,
|
|
},
|
|
{
|
|
pubkey: updateAuthorityOfMaster,
|
|
isSigner: false,
|
|
isWritable: false,
|
|
},
|
|
{
|
|
pubkey: masterMetadataKey,
|
|
isSigner: false,
|
|
isWritable: false,
|
|
},
|
|
{
|
|
pubkey: programIds().token,
|
|
isSigner: false,
|
|
isWritable: false,
|
|
},
|
|
{
|
|
pubkey: SystemProgram.programId,
|
|
isSigner: false,
|
|
isWritable: false,
|
|
},
|
|
{
|
|
pubkey: SYSVAR_RENT_PUBKEY,
|
|
isSigner: false,
|
|
isWritable: false,
|
|
},
|
|
];
|
|
|
|
if (reservationList) {
|
|
keys.push({
|
|
pubkey: reservationList,
|
|
isSigner: false,
|
|
isWritable: true,
|
|
});
|
|
}
|
|
instructions.push(
|
|
new TransactionInstruction({
|
|
keys,
|
|
programId: metadataProgramId,
|
|
data,
|
|
}),
|
|
);
|
|
}
|
|
|
|
export async function updatePrimarySaleHappenedViaToken(
|
|
metadata: PublicKey,
|
|
owner: PublicKey,
|
|
tokenAccount: PublicKey,
|
|
instructions: TransactionInstruction[],
|
|
) {
|
|
const metadataProgramId = programIds().metadata;
|
|
|
|
const data = Buffer.from([4]);
|
|
|
|
const keys = [
|
|
{
|
|
pubkey: metadata,
|
|
isSigner: false,
|
|
isWritable: true,
|
|
},
|
|
{
|
|
pubkey: owner,
|
|
isSigner: true,
|
|
isWritable: false,
|
|
},
|
|
{
|
|
pubkey: tokenAccount,
|
|
isSigner: false,
|
|
isWritable: false,
|
|
},
|
|
];
|
|
instructions.push(
|
|
new TransactionInstruction({
|
|
keys,
|
|
programId: metadataProgramId,
|
|
data,
|
|
}),
|
|
);
|
|
}
|
|
|
|
export async function createReservationList(
|
|
metadata: PublicKey,
|
|
masterEdition: PublicKey,
|
|
resource: PublicKey,
|
|
updateAuthority: PublicKey,
|
|
payer: PublicKey,
|
|
instructions: TransactionInstruction[],
|
|
) {
|
|
const metadataProgramId = programIds().metadata;
|
|
|
|
const reservationList = await getReservationList(masterEdition, resource);
|
|
const data = Buffer.from([6]);
|
|
|
|
const keys = [
|
|
{
|
|
pubkey: reservationList,
|
|
isSigner: false,
|
|
isWritable: true,
|
|
},
|
|
{
|
|
pubkey: payer,
|
|
isSigner: true,
|
|
isWritable: false,
|
|
},
|
|
{
|
|
pubkey: updateAuthority,
|
|
isSigner: true,
|
|
isWritable: false,
|
|
},
|
|
|
|
{
|
|
pubkey: masterEdition,
|
|
isSigner: false,
|
|
isWritable: false,
|
|
},
|
|
{
|
|
pubkey: resource,
|
|
isSigner: false,
|
|
isWritable: false,
|
|
},
|
|
{
|
|
pubkey: metadata,
|
|
isSigner: false,
|
|
isWritable: false,
|
|
},
|
|
{
|
|
pubkey: SystemProgram.programId,
|
|
isSigner: false,
|
|
isWritable: false,
|
|
},
|
|
{
|
|
pubkey: SYSVAR_RENT_PUBKEY,
|
|
isSigner: false,
|
|
isWritable: false,
|
|
},
|
|
];
|
|
instructions.push(
|
|
new TransactionInstruction({
|
|
keys,
|
|
programId: metadataProgramId,
|
|
data,
|
|
}),
|
|
);
|
|
}
|
|
|
|
export async function signMetadata(
|
|
metadata: PublicKey,
|
|
creator: PublicKey,
|
|
instructions: TransactionInstruction[],
|
|
) {
|
|
const metadataProgramId = programIds().metadata;
|
|
|
|
const data = Buffer.from([7]);
|
|
|
|
const keys = [
|
|
{
|
|
pubkey: metadata,
|
|
isSigner: false,
|
|
isWritable: true,
|
|
},
|
|
{
|
|
pubkey: creator,
|
|
isSigner: true,
|
|
isWritable: false,
|
|
},
|
|
];
|
|
instructions.push(
|
|
new TransactionInstruction({
|
|
keys,
|
|
programId: metadataProgramId,
|
|
data,
|
|
}),
|
|
);
|
|
}
|
|
|
|
export async function mintPrintingTokens(
|
|
destination: PublicKey,
|
|
printingMint: PublicKey,
|
|
updateAuthority: PublicKey,
|
|
metadata: PublicKey,
|
|
masterEdition: PublicKey,
|
|
supply: BN,
|
|
instructions: TransactionInstruction[],
|
|
) {
|
|
const PROGRAM_IDS = programIds();
|
|
const metadataProgramId = PROGRAM_IDS.metadata;
|
|
|
|
const value = new MintPrintingTokensArgs({ supply });
|
|
const data = Buffer.from(serialize(METADATA_SCHEMA, value));
|
|
|
|
const keys = [
|
|
{
|
|
pubkey: destination,
|
|
isSigner: false,
|
|
isWritable: true,
|
|
},
|
|
{
|
|
pubkey: printingMint,
|
|
isSigner: false,
|
|
isWritable: true,
|
|
},
|
|
{
|
|
pubkey: updateAuthority,
|
|
isSigner: true,
|
|
isWritable: false,
|
|
},
|
|
{
|
|
pubkey: metadata,
|
|
isSigner: false,
|
|
isWritable: false,
|
|
},
|
|
{
|
|
pubkey: masterEdition,
|
|
isSigner: false,
|
|
isWritable: false,
|
|
},
|
|
{
|
|
pubkey: PROGRAM_IDS.token,
|
|
isSigner: false,
|
|
isWritable: false,
|
|
},
|
|
{
|
|
pubkey: SYSVAR_RENT_PUBKEY,
|
|
isSigner: false,
|
|
isWritable: false,
|
|
},
|
|
];
|
|
instructions.push(
|
|
new TransactionInstruction({
|
|
keys,
|
|
programId: metadataProgramId,
|
|
data,
|
|
}),
|
|
);
|
|
}
|
|
|
|
export async function getEdition(tokenMint: PublicKey): Promise<PublicKey> {
|
|
const PROGRAM_IDS = programIds();
|
|
|
|
return (
|
|
await PublicKey.findProgramAddress(
|
|
[
|
|
Buffer.from(METADATA_PREFIX),
|
|
PROGRAM_IDS.metadata.toBuffer(),
|
|
tokenMint.toBuffer(),
|
|
Buffer.from(EDITION),
|
|
],
|
|
PROGRAM_IDS.metadata,
|
|
)
|
|
)[0];
|
|
}
|
|
|
|
export async function getMetadata(tokenMint: PublicKey): Promise<PublicKey> {
|
|
const PROGRAM_IDS = programIds();
|
|
|
|
return (
|
|
await PublicKey.findProgramAddress(
|
|
[
|
|
Buffer.from(METADATA_PREFIX),
|
|
PROGRAM_IDS.metadata.toBuffer(),
|
|
tokenMint.toBuffer(),
|
|
],
|
|
PROGRAM_IDS.metadata,
|
|
)
|
|
)[0];
|
|
}
|
|
|
|
export async function getReservationList(
|
|
masterEdition: PublicKey,
|
|
resource: PublicKey,
|
|
): Promise<PublicKey> {
|
|
const PROGRAM_IDS = programIds();
|
|
|
|
return (
|
|
await PublicKey.findProgramAddress(
|
|
[
|
|
Buffer.from(METADATA_PREFIX),
|
|
PROGRAM_IDS.metadata.toBuffer(),
|
|
masterEdition.toBuffer(),
|
|
Buffer.from(RESERVATION),
|
|
resource.toBuffer(),
|
|
],
|
|
PROGRAM_IDS.metadata,
|
|
)
|
|
)[0];
|
|
}
|