Skip to content

Commit

Permalink
fix: allow Master Edition max supply to be 0 (#147)
Browse files Browse the repository at this point in the history
* fix: allow Master Edition max supply to be 0

* test: use familiar name

* chore: fix lint issues
  • Loading branch information
aheckmann authored Jan 17, 2022
1 parent a618072 commit 7839353
Show file tree
Hide file tree
Showing 10 changed files with 75 additions and 61 deletions.
6 changes: 3 additions & 3 deletions src/actions/mintNFT.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@ import { sendTransaction } from './transactions';
import { lookup } from '../utils/metadata';
import { prepareTokenAccountAndMintTxs } from './shared';

interface MintNFTParams {
export interface MintNFTParams {
connection: Connection;
wallet: Wallet;
uri: string;
maxSupply?: number;
}

interface MintNFTResponse {
export interface MintNFTResponse {
txId: string;
mint: PublicKey;
metadata: PublicKey;
Expand Down Expand Up @@ -90,7 +90,7 @@ export const mintNFT = async ({
updateAuthority: wallet.publicKey,
mint: mint.publicKey,
mintAuthority: wallet.publicKey,
maxSupply: maxSupply ? new BN(maxSupply) : null,
maxSupply: maxSupply || maxSupply === 0 ? new BN(maxSupply) : null,
},
);

Expand Down
6 changes: 3 additions & 3 deletions test/actions/createMetadataAndME.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import BN from 'bn.js';
import { Token, TOKEN_PROGRAM_ID } from '@solana/spl-token';
import { Connection, NodeWallet } from '../../src';
import { FEE_PAYER, NETWORK, pause } from '../utils';
import { FEE_PAYER, NETWORK, sleep } from '../utils';
import {
Creator,
MasterEdition,
Expand Down Expand Up @@ -51,7 +51,7 @@ describe('creatomg metadata and master edition PDAs', () => {
metadataData,
});

await pause(20000);
await sleep(20000);

const metadata = await Metadata.getPDA(mint.publicKey);
const metadataInfo = await Account.getInfo(connection, metadata);
Expand All @@ -66,7 +66,7 @@ describe('creatomg metadata and master edition PDAs', () => {
});

// had to increase to 25s, or it was failing
await pause(25000);
await sleep(25000);

const edition = await MasterEdition.getPDA(mint.publicKey);
const editionInfo = await Account.getInfo(connection, edition);
Expand Down
4 changes: 2 additions & 2 deletions test/actions/mintEditionFromMaster.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Connection, NodeWallet } from '../../src';
import { mintNFT } from '../../src/actions';
import { FEE_PAYER, NETWORK, pause } from '../utils';
import { FEE_PAYER, NETWORK, sleep } from '../utils';
import { MasterEdition, Metadata } from '@metaplex-foundation/mpl-token-metadata';
import { mintEditionFromMaster } from '../../src/actions/mintEditionFromMaster';
import { mockAxios200, uri } from './shared';
Expand All @@ -26,7 +26,7 @@ describe('minting a limited edition from master', () => {

// unfortunately it takes some time for the master mint to propagate
// empirically, I found anything below 20s to be unreliable
await pause(20000);
await sleep(20000);

const editionMintResponse = await mintEditionFromMaster({
connection,
Expand Down
86 changes: 52 additions & 34 deletions test/actions/mintNFT.test.ts
Original file line number Diff line number Diff line change
@@ -1,57 +1,75 @@
import { Keypair } from '@solana/web3.js';
import { Connection, NodeWallet } from '../../src';
import { mintNFT } from '../../src/actions';
import { FEE_PAYER, NETWORK } from '../utils';
import { mintNFT, MintNFTParams } from '../../src/actions';
import { sleep } from '../utils';
import { MasterEdition, Metadata } from '@metaplex-foundation/mpl-token-metadata';
import { mockAxios200, mockAxios404, uri } from './shared';
import { uri, generateConnectionAndWallet, mockAxios200, mockAxios404 } from './shared';
import { airdrop } from '@metaplex-foundation/amman';

jest.mock('axios');

describe('minting an NFT', () => {
const connection = new Connection(NETWORK);
const wallet = new NodeWallet(FEE_PAYER);
let mint: Keypair;
let connection: Connection;
let wallet: NodeWallet;
let payer: Keypair;

beforeAll(() => {
jest
.spyOn(connection, 'sendRawTransaction')
.mockResolvedValue(
'64Tpr1DNj9UWg1P89Zss5Y4Mh2gGyRUMYZPNenZKY2hiNjsotrCDMBriDrsvhg5BJt3mY4hH6jcparNHCZGhAwf6',
);
});
beforeAll(async () => {
const result = await generateConnectionAndWallet();
connection = result.connection;
wallet = result.wallet;
payer = result.payer;

beforeEach(() => {
mint = Keypair.generate();
jest.spyOn(Keypair, 'generate').mockReturnValue(mint);
await airdrop(connection, payer.publicKey, 2);
});

describe('when can find metadata json', () => {
beforeEach(() => {
mockAxios200(wallet);
describe('when metadata json is found', () => {
beforeAll(async () => {
mockAxios200(wallet); // metadata json found
});

test('generates a unique mint and creates metadata plus master edition from metadata URL and max supply', async () => {
const mintResponse = await mintNFT({
connection,
wallet,
uri,
maxSupply: 0,
});
const values = [0, 3, undefined];
for (const maxSupply of values) {
describe(`when max supply is "${maxSupply}"`, () => {
test('generates a unique mint, metadata & master editions from metadata URL', async () => {
const arg: MintNFTParams = {
connection,
wallet,
uri,
};

if (maxSupply !== undefined) {
arg.maxSupply = maxSupply;
}

const mintResponse = await mintNFT(arg);
const { mint } = mintResponse;

const metadata = await Metadata.getPDA(mint.publicKey);
const edition = await MasterEdition.getPDA(mint.publicKey);
const metadata = await Metadata.getPDA(mint);
const edition = await MasterEdition.getPDA(mint);

expect(mintResponse).toMatchObject({
metadata,
edition,
mint: mint.publicKey,
expect(mintResponse).toMatchObject({
metadata,
edition,
});

await sleep(2000); // HACK

const metadataEdition = (await Metadata.getEdition(connection, mint)) as MasterEdition;
expect(metadataEdition.data?.maxSupply?.toNumber()).toBe(maxSupply);
});
});
});
}
});

describe('when metadata json not found', () => {
beforeEach(() => {
mockAxios404();

jest
.spyOn(connection, 'sendRawTransaction')
.mockResolvedValue(
'64Tpr1DNj9UWg1P89Zss5Y4Mh2gGyRUMYZPNenZKY2hiNjsotrCDMBriDrsvhg5BJt3mY4hH6jcparNHCZGhAwf6',
);
});

test('exits the action and throws an error', async () => {
Expand All @@ -63,7 +81,7 @@ describe('minting an NFT', () => {
maxSupply: 0,
});
} catch (e) {
expect(e).not.toBeNull();
expect(e.message).toMatch(/unable to get metadata/);
}
});
});
Expand Down
6 changes: 3 additions & 3 deletions test/actions/signMetadata.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Keypair } from '@solana/web3.js';
import { Connection, NodeWallet } from '../../src';
import { mintNFT } from '../../src/actions';
import { FEE_PAYER, NETWORK, pause } from '../utils';
import { FEE_PAYER, NETWORK, sleep } from '../utils';
import { Metadata } from '@metaplex-foundation/mpl-token-metadata';
import { signMetadata } from '../../src/actions/signMetadata';
import { mockAxios200, uri } from './shared';
Expand Down Expand Up @@ -30,7 +30,7 @@ describe('signing metadata on a master edition', () => {

// unfortunately it takes some time for the master mint to propagate
// empirically, I found anything below 20s to be unreliable
await pause(20000);
await sleep(20000);

// before signing
const metadata = await Metadata.getPDA(masterMintResponse.mint);
Expand All @@ -45,7 +45,7 @@ describe('signing metadata on a master edition', () => {
signer: secondSigner,
});

await pause(20000);
await sleep(20000);

//after signing
info = await Account.getInfo(connection, metadata);
Expand Down
6 changes: 3 additions & 3 deletions test/actions/updateMetadata.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Keypair } from '@solana/web3.js';
import { Connection, NodeWallet } from '../../src';
import { mintNFT } from '../../src/actions';
import { FEE_PAYER, NETWORK, pause } from '../utils';
import { FEE_PAYER, NETWORK, sleep } from '../utils';
import { Creator, Metadata, MetadataDataData } from '@metaplex-foundation/mpl-token-metadata';
import { updateMetadata } from '../../src/actions/updateMetadata';
import { mockAxios200, uri } from './shared';
Expand Down Expand Up @@ -44,7 +44,7 @@ describe('updating metadata on a master edition', () => {

// unfortunately it takes some time for the master mint to propagate
// empirically, I found anything below 20s to be unreliable
await pause(20000);
await sleep(20000);

// before update
const metadata = await Metadata.getPDA(masterMintResponse.mint);
Expand All @@ -63,7 +63,7 @@ describe('updating metadata on a master edition', () => {
primarySaleHappened: true,
});

await pause(20000);
await sleep(20000);

//after update
info = await Account.getInfo(connection, metadata);
Expand Down
6 changes: 3 additions & 3 deletions test/actions/utility/closeVault.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { NATIVE_MINT } from '@solana/spl-token';
import { Vault, VaultState } from '@metaplex-foundation/mpl-token-vault';

import { pause } from '../../utils';
import { sleep } from '../../utils';
import { generateConnectionAndWallet } from '../shared';
import { closeVault, createVault, createExternalPriceAccount } from '../../../src/actions/utility';

Expand All @@ -19,7 +19,7 @@ describe('closing a Vault', () => {
...externalPriceAccountData,
});

await pause(1000);
await sleep(1000);

vault = await Vault.load(connection, vaultResponse.vault);
expect(vault).toHaveProperty('data');
Expand All @@ -32,7 +32,7 @@ describe('closing a Vault', () => {
priceMint: NATIVE_MINT,
});

await pause(1000);
await sleep(1000);

vault = await Vault.load(connection, vaultResponse.vault);
expect(vault).toHaveProperty('data');
Expand Down
4 changes: 2 additions & 2 deletions test/actions/utility/createVault.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Vault, VaultState } from '@metaplex-foundation/mpl-token-vault';

import { pause } from '../../utils';
import { sleep } from '../../utils';
import { createVault, createExternalPriceAccount } from '../../../src/actions/utility';
import { generateConnectionAndWallet } from '../shared';

Expand All @@ -17,7 +17,7 @@ describe('creating a Vault', () => {
...externalPriceAccountData,
});

await pause(1000);
await sleep(1000);
const vault = await Vault.load(connection, vaultResponse.vault);
expect(vault).toHaveProperty('data');
expect(vault.data.state).toEqual(VaultState.Inactive);
Expand Down
4 changes: 2 additions & 2 deletions test/actions/utility/initAuction.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
WinnerLimitType,
} from '@metaplex-foundation/mpl-auction';

import { pause } from '../../utils';
import { sleep } from '../../utils';
import { generateConnectionAndWallet } from '../shared';
import { createExternalPriceAccount, createVault, initAuction } from '../../../src/actions/utility';

Expand Down Expand Up @@ -45,7 +45,7 @@ describe('initAuction action', () => {
auctionSettings,
});

await pause(1000);
await sleep(1000);

const auctionInstance = await Auction.load(connection, auction);

Expand Down
8 changes: 2 additions & 6 deletions test/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,12 +111,8 @@ export const projectRoot = path.resolve(__dirname, '..', '..');
export const tmpTestDir = path.resolve(tmpdir(), 'test');

export const serializeConfig = { verifySignatures: false, requireAllSignatures: false };
export async function pause(ms: number) {
await new Promise((response) =>
setTimeout(() => {
response(0);
}, ms),
);
export async function sleep(ms: number) {
return new Promise((resolve) => setTimeout(resolve, ms));
}

export function getUserKeypairFromFile(keypairPath) {
Expand Down

0 comments on commit 7839353

Please sign in to comment.