This SDK helps developers get started with the on-chain tools provided by Metaplex.

Overview

Metaplex JavaScript SDK

⛔️ DO NOT USE IN PRODUCTION, THIS SDK IS IN VERY EARLY ALPHA STAGES!

This SDK helps developers get started with the on-chain tools provided by Metaplex. It focuses its API on common use-cases to provide a smooth developer experience whilst allowing third parties to extend its features via plugins.

Please note that this SDK has been re-implemented from scratch and is currently in alpha. This means some of the core API and interfaces might change from one version to another and therefore we do not recommend that you use it in production just yet.

However, feel free to play with it and provide some early feedback if you wish to contribute to the direction of this project.

Installation

npm install @metaplex-foundation/js-next

Setup

The entry point to the JavaScript SDK is a Metaplex instance that will give you access to its API.

It accepts a Connection instance that will be used to communicate with the cluster.

import { Metaplex } from "@metaplex-foundation/js-next";
import { Connection, clusterApiUrl } from "@solana/web3.js";

const connection = new Connection(clusterApiUrl("mainnet-beta"));
const metaplex = new Metaplex(connection);

On top of that, you can customise who the SDK should interact on behalf of and which storage provider to use when uploading assets. We refer to these as "Identity Drivers" and "Storage Drivers" respectively. You may change these drivers by calling the use method on the Metaplex instance like so. We'll see all available drivers in more detail below.

import { Metaplex, keypairIdentity, bundlrStorage } from "@metaplex-foundation/js-next";
import { Connection, clusterApiUrl, Keypair } from "@solana/web3.js";

const connection = new Connection(clusterApiUrl("mainnet-beta"));
const wallet = Keypair.generate();

const metaplex = Metaplex.make(connection)
    .use(keypairIdentity(wallet))
    .use(bundlrStorage());

Notice how you can create a Metaplex instance using Metaplex.make(...) instead of new Metaplex(...) in order to make the fluent API more readable.

Usage

Once properly configured, that Metaplex instance can be used to access modules providing different sets of features. Currently, there is only one NFT module that can be accessed via the nfts() method. From that module, you will be able to find, create and update NFTs with more features to come.

Here is a little visual representation of the SDK in its current state.

High-level architecture of the SDK.

Now, let’s look into the NFT module in a bit more detail before moving on to the identity and storage drivers.

NFTs

The NFT module can be accessed via Metaplex.nfts() and provide the following methods.

And the following model, either returned or used by the above methods.

findNftByMint

The findNftByMint method accepts a mint public key and returns an Nft object.

const mint = new PublicKey("ATe3DymKZadrUoqAMn7HSpraxE4gB88uo1L9zLGmzJeL");

const nft = await metaplex.nfts().findNftByMint(mint);

The returned Nft object will have its JSON metadata already loaded so you can, for instance, access its image URL like so (provided it is present in the downloaded metadata).

const imageUrl = nft.metadata.image;

Similarly, the OriginalEdition account (a.k.a the Master Edition) of the NFT will also be already loaded and, if it exists on that NFT, you can use it like so.

const supply = nft.originalEdition.supply;
const maxSupply = nft.originalEdition.maxSupply;

You can read more about the NFT model below.

findNftsByMintList

The findNftsByMintList method accepts an array of mint addresses and returns an array of Nfts. However, null values will be returned for each provided mint address that is not associated with an NFT.

Note that this is much more efficient than calling findNftByMint for each mint in the list as the SDK can optimise the query and fetch multiple NFTs in much fewer requests.

const [nftA, nftB] = await metaplex.nfts().findNftsByMintList([mintA, mintB]);

NFTs retrieved via findNftsByMintList will not have their JSON metadata loaded because this would require one request per NFT and could be inefficient if you provide a long list of mint addresses. Additionally, you might want to fetch these on-demand, as the NFTs are being displayed on your web app for instance. The same goes for the Edition account which might be irrelevant until the user clicks on the NFT.

Thus, if you want to load the JSON metadata and/or the Edition account of an NFT, you may do this like so.

await nft.metadataTask.run();
await nft.EditionTask.run();

This will give you access to the metadata, originalEdition and printEdition properties of the NFT. The last two depend on whether the NFT is an original edition or a print edition.

const imageUrl = nft.metadata.image;

if (nft.isOriginal()) {
    const currentSupply = nft.originalEdition.supply;
    const maxSupply = nft.originalEdition.maxSupply;
}

if (nft.isPrint()) {
  const parentEdition = nft.printEdition.parent;
  const editionNumber = nft.printEdition.edition;
}

We'll talk more about these tasks when documenting the NFT model.

findNftsByOwner

The findNftsByOwner method accepts a public key and returns all Nfts owned by that public key.

const myNfts = await metaplex.nfts().findNftsByOwner(metaplex.identity().publicKey);

Similarly to findNftsByMintList, the returned Nfts will not have their JSON metadata nor their edition account loaded.

findNftsByCreator

The findNftsByCreator method accepts a public key and returns all Nfts that have that public key registered as their first creator. Additionally, you may provide an optional position parameter to match the public key at a specific position in the creator list.

const nfts = await metaplex.nfts().findNftsByCreator(creatorPublicKey);
const nfts = await metaplex.nfts().findNftsByCreator(creatorPublicKey, 1); // Equivalent to the previous line.
const nfts = await metaplex.nfts().findNftsByCreator(creatorPublicKey, 2); // Now matching the second creator field.

Similarly to findNftsByMintList, the returned Nfts will not have their JSON metadata nor their edition account loaded.

findNftsByCandyMachine

The findNftsByCandyMachine method accepts the public key of a Candy Machine and returns all Nfts that have been minted from that Candy Machine so far.

By default, it will assume you're providing the public key of a Candy Machine v2. If you want to use a different version, you can provide the version as the second parameter.

const nfts = await metaplex.nfts().findNftsByCandyMachine(candyMachinePublicKey);
const nfts = await metaplex.nfts().findNftsByCandyMachine(candyMachinePublicKey, 2); // Equivalent to the previous line.
const nfts = await metaplex.nfts().findNftsByCandyMachine(candyMachinePublicKey, 1); // Now finding NFTs for Candy Machine v1.

Note that the current implementation of this method delegates to findNftsByCreator whilst fetching the appropriate PDA for Candy Machines v2.

Similarly to findNftsByMintList, the returned Nfts will not have their JSON metadata nor their edition account loaded.

uploadMetadata

When creating or updating an NFT, you will need a URI pointing to some JSON Metadata describing the NFT. Depending on your requirement, you may do this on-chain or off-chain.

If your metadata is not already uploaded, you may do this using the SDK via the uploadMetadata method. It accepts a metadata object and returns the URI of the uploaded metadata. Where exactly the metadata will be uploaded depends on the selected StorageDriver.

const { uri } = await metaplex.nfts().uploadMetadata({
    name: "My NFT",
    description: "My description",
    image: "https://arweave.net/123",
});

console.log(uri) // https://arweave.net/789

Some properties inside that metadata object will also require you to upload some assets to provide their URI — such as the image property on the example above.

To make this process easier, the uploadMetadata method will recognise any instances of MetaplexFile within the provided object and upload them in bulk to the current storage driver. It will then create a new version of the provided metadata where all instances of MetaplexFile are replaced with their URI. Finally, it will upload that replaced metadata to the storage driver and return it.

// Assuming the user uploaded two images via an input of type "file".
const browserFiles = event.target.files;

const { uri, metadata } = await metaplex.nfts().uploadMetadata({
    name: "My NFT",
    image: await MetaplexFile.fromFile(browserFiles[0]),
    properties: {
        files: [
            {
                type: "video/mp4",
                uri: await MetaplexFile.fromFile(browserFiles[1]),
            },
        ]
    }
});

console.log(metadata.image) // https://arweave.net/123
console.log(metadata.properties.files[0].uri) // https://arweave.net/456
console.log(uri) // https://arweave.net/789

Note that MetaplexFiles can be created in various different ways based on where the file is coming from. You can read more about MetaplexFile objects and how to use them here.

createNft

The createNft method accepts a variety of parameters that define the on-chain data of the NFT. The only required parameter is the uri pointing to its JSON metadata — remember that you can use uploadMetadata to get that URI. All other parameters are optional as the SDK will do its best to provide sensible default values.

Here's how you can create a new NFT with minimum configuration.

const { nft } = await metaplex.nfts().createNft({
    uri: "https://arweave.net/123",
});

This will take care of creating the mint account, the associated token account, the metadata PDA and the original edition PDA (a.k.a. the master edition) for you.

Additionally, since no other optional parameters were provided, it will do its best to provide sensible default values for the rest of the parameters. Namely:

  • It will fetch the JSON metadata from the provided URI and try to use some of its fields to fill the gaps in the on-chain data. E.g. the metadata name will be used for the on-chain name as a fallback.
  • Since no owner, mint authority or update authority were provided, the “identity” of the SDK will be used by default for these parameters. Meaning the SDK's identity will be the owner of that new NFT.
  • It will also default to setting the identity as the first and only creator with a 100% share.
  • It will try to fetch the secondary sales royalties from the downloaded JSON metadata or will default to 5%.
  • It will default to making the NFT immutable — meaning you won't be able to update it later on.

If some of these default parameters are not suitable for your use case, you may provide them explicitly when creating the NFT. Here is the exhaustive list of parameters accepted by the createNft method.

updateNft

The updateNft method accepts an Nft object and a set of parameters to update on the NFT. It then returns a new Nft object representing the updated NFT.

For instance, here is how you would change the on-chain name of an NFT.

const { nft: updatedNft } = await metaplex.nfts().updateNft(nft, {
    name: "My Updated Name",
});

Anything that you don’t provide in the parameters will stay unchanged.

If you’d like to change the JSON metadata of the NFT, you’d first need to upload a new metadata object using the uploadMetadata method and then use the provided URI to update the NFT.

const { uri: newUri } = await metaplex.nfts().uploadMetadata({
    ...nft.metadata,
    name: "My Updated Metadata Name",
    description: "My Updated Metadata Description",
});

const { nft: updatedNft } = await metaplex.nfts().updateNft(nft, {
    uri: newUri,
});

printNewEdition

The printNewEdition method requires the mint address of the original NFT and returns a brand-new NFT printed from the original edition.

For instance, this is how you would print a new edition of the originalNft NFT.

const { nft: printedNft } = await metaplex.nfts().printNewEdition(originalNft.mint);

By default, it will print using the token account of the original NFT as proof of ownership, and it will do so using the current identity of the SDK. You may customise all of these parameters by providing them explicitly.

const { nft: printedNft } = await metaplex.nfts().printNewEdition(originalMint, {
  newMint,                   // Defaults to a brand-new Keypair.
  newMintAuthority,          // Defaults to the current identity.
  newUpdateAuthority,        // Defaults to the current identity.
  newOwner,                  // Defaults to the current identity.
  newFreezeAuthority,        // Defaults to undefined.
  payer,                     // Defaults to the current identity.
  originalTokenAccountOwner, // Defaults to the current identity.
  originalTokenAccount,      // Defaults to the ATA of the current identity.
});

The Nft model

All of the methods above either return or interact with an Nft object. The Nft object is a read-only data representation of your NFT that contains all the information you need at the top level — i.e. no more metadata.data.data.

You can see its full data representation by checking the code but here is an overview of the properties that are available on the Nft object.

// Always loaded.
updateAuthority: PublicKey;
mint: PublicKey;
name: string;
symbol: string;
uri: string;
sellerFeeBasisPoints: number;
creators: Creator[] | null;
primarySaleHappened: boolean;
isMutable: boolean;
editionNonce: number | null;
tokenStandard: TokenStandard | null;
collection: Collection | null;
uses: Uses | null;

// Sometimes loaded.
metadata: JsonMetadata | null;
editionAccount: OriginalOrPrintEditionAccount | null;
originalEdition: null | {
    supply: number | BN;
    maxSupply: number | BN;
};
printEdition: null | {
  parent: PublicKey;
  edition: number | BN;
};

As you can see, some of the properties — such as metadata — are loaded on demand. This is because they are not always needed and/or can be expensive to load. Therefore, the SDK uses the following rule of thumb:

  • If you're only fetching one NFT — e.g. by using findNftByMint — then these properties will already be loaded.
  • If you're fetching multiple NFTs — e.g. by using findNftsByMintLint — then these properties will not be loaded and you will need to load them as and when you need them.

In order to load these properties, you may run the metadataTask and editionTask properties of the Nft object.

await nft.metadataTask.run();
await nft.editionTask.run();

After these two promises resolve, you should have access to the metadata, editionAccount, originalEdition and printEdition properties. Note that if a task fails to load the data, an error will be thrown.

Also, note that both metadataTask and editionTask are of type Task which contains a bunch of helper methods. Here's an overview of the methods available in the Task class:

export type Task<T> = {
    getStatus: () => TaskStatus;
    getResult: () => T | undefined;
    getError: () => unknown;
    isPending: () => boolean;
    isRunning: () => boolean;
    isCompleted: () => boolean;
    isSuccessful: () => boolean;
    isFailed: () => boolean;
    isCanceled: () => boolean;
    run: (options?: TaskOptions) => Promise<T>;
    loadWith: (preloadedResult: T) => Task<T>;
    reset: () => Task<T>;
    onStatusChange: (callback: (status: TaskStatus) => unknown) => Task<T>;
    onStatusChangeTo: (status: TaskStatus, callback: () => unknown) => Task<T>;
    onSuccess: (callback: () => unknown) => Task<T>;
    onFailure: (callback: () => unknown) => Task<T>;
    onCancel: (callback: () => unknown) => Task<T>;
};

export type TaskOptions = {
  signal?: AbortSignal;
  force?: boolean;
};

As you can see, you get a bunch of methods to check the status of a task, to listen to its changes, to run it and to reset its data. You also get a loadWith method which allows you to bypass the task and load the provided data directly — this can be useful when loading NFTs in batch.

Finally, you may provide an AbortSignal using the signal property of the TaskOptions when running a task, allowing you to cancel the task if you need to. This needs to be supported by the concrete implementation of the task as they will have to consistently check that the task was not cancelled and return early if it was. The force property of TaskOptions can be used to force the task to run even if the task was already completed.

Identity

The current identity of a Metaplex instance can be accessed via metaplex.identity() and provide information on the wallet we are acting on behalf of when interacting with the SDK.

This method returns an identity object with the following interface.

class IdentityDriver {
    publicKey: PublicKey;
    signMessage(message: Uint8Array): Promise<Uint8Array>;
    verifyMessage(message: Uint8Array, signature: Uint8Array): Promise<boolean>;
    signTransaction(transaction: Transaction): Promise<Transaction>;
    signAllTransactions(transactions: Transaction[]): Promise<Transaction[]>;
    is(that: IdentityDriver): boolean;
}

The implementation of these methods depends on the concrete identity driver being used. For instance, in the CLI, these methods will directly use a key pair whereas, in the browser, they will delegate to a wallet adapter.

Let’s have a quick look at the concrete identity drivers available to us.

guestIdentity

The guestIdentity driver is the default driver and requires no parameter. It is essentially a null driver that can be useful when we don’t need to send any signed transactions.

import { guestIdentity } from "@metaplex-foundation/js-next";

metaplex.use(guestIdentity());

If we try to sign a message or a transaction using this driver, an error will be thrown.

keypairIdentity

The keypairIdentity driver accepts a Keypair object as a parameter. This is useful when using the SDK locally such as within CLI applications.

import { keypairIdentity } from "@metaplex-foundation/js-next";
import { Keypair } from "@solana/web3.js";

// Load a local keypair.
const keypairFile = fs.readFileSync('/Users/username/.config/solana/id.json');
const keypair = Keypair.fromSecretKey(Buffer.from(JSON.parse(keypairFile.toString())));

// Use it in the SDK.
metaplex.use(keypairIdentity(keypair));

walletAdapterIdentity

The walletAdapterIdentity driver accepts a wallet adapter as defined by the “wallet-adapter” repo from Solana Labs. This is useful when using the SDK in a web application that requires the user to manually approve transactions.

import { walletAdapterIdentity } from "@metaplex-foundation/js-next";
import { useWallet } from '@solana/wallet-adapter-react';

const { wallet } = useWallet();

if (wallet) {
    metaplex.use(walletAdapterIdentity(wallet));
}

Note that we have to wrap metaplex.use(...) in an if-statement because wallet could be null — meaning there’s no connected wallet at this time. If you’d like to accept a nullable wallet and use the guestIdentity when it is null, you may use the walletOrGuestIdentity helper method instead.

import { walletOrGuestIdentity } from "@metaplex-foundation/js-next";
import { useWallet } from '@solana/wallet-adapter-react';

const { wallet } = useWallet();

metaplex.use(walletOrGuestIdentity(wallet));

Storage

You may access the current storage driver using metaplex.storage() which will give you access to the following interface.

class StorageDriver {
    getPrice(...files: MetaplexFile[]): Promise<SolAmount>;
    upload(file: MetaplexFile): Promise<string>;
    uploadAll(files: MetaplexFile[]): Promise<string[]>;
    uploadJson<T extends object>(json: T): Promise<string>;
    download(uri: string): Promise<MetaplexFile>;
    downloadJson<T extends object>(uri: string): Promise<T>;
}

The implementation of these storage methods depends on the concrete storage driver being used. Let’s take a look at the storage drivers available to us. But first, let's talk about the MetaplexFile class which is being used in the API of every storage driver.

MetaplexFile

The MetaplexFile class is a simple wrapper around Buffer that adds additional context relevant to files and assets such as their filename, content type, extension, etc. It contains the following data.

class MetaplexFile {
  public readonly buffer: Buffer;
  public readonly fileName: string;
  public readonly displayName: string;
  public readonly uniqueName: string;
  public readonly contentType: string | null;
  public readonly extension: string | null;
  public readonly tags: { name: string; value: string }[];
}

There are many ways of creating a MetaplexFile. The simplest way is to pass a string to the constructor with a filename. The filename is necessary to infer the extension and the mime type of the provided file.

const file = new MetaplexFile('The content of my file', 'my-file.txt');

You may also explicitly provide these options by passing a third parameter to the constructor.

const file = new MetaplexFile('The content of my file', 'my-file.txt', {
    displayName = 'A Nice Title For My File'; // Defaults to the filename.
    uniqueName = 'my-company/files/some-identifier'; // Defaults to a random string.
    contentType = 'text/plain'; // Infer it from filename by default.
    extension = 'txt'; // Infer it from filename by default.
    tags = [{ name: 'my-tag', value: 'some-value' }]; // Defaults to [].
});

Note that if you want to create a MetaplexFile directly from a JSON object, there's a static fromJson method that you can use like so.

const file = MetaplexFile.fromJson({ foo: 42 });

In practice, you will most likely be creating MetaplexFiles from files either present on your computer or uploaded by some user on the browser. You can do the former by using fs.readFileSync.

const buffer = fs.readFileSync('/path/to/my-file.txt');
const file = new MetaplexFile(buffer, 'my-file.txt');

And the latter by using the fromFile static method which accepts a File object as defined in the browser.

const browserFile: File = event.target.files[0];
const file: MetaplexFile = await MetaplexFile.fromFile(browserFile);

Okay, now let’s talk about the concrete storage drivers available to us and how to set them up.

bundlrStorage

The bundlrStorage driver is the default driver and uploads assets on Arweave using the Bundlr network.

By default, it will use the same RPC endpoint used by the Metaplex instance as a providerUrl and the mainnet address "https://node1.bundlr.network" as the Bundlr address.

You may customise these by passing a parameter object to the bundlrStorage method. For instance, here’s how you can use Bundlr on devnet.

import { bundlrStorage } from "@metaplex-foundation/js-next";

metaplex.use(bundlrStorage({
    address: 'https://devnet.bundlr.network',
    providerUrl: 'https://api.devnet.solana.com',
    timeout: 60000,
}));

awsStorage

The awsStorage driver uploads assets off-chain to an S3 bucket of your choice.

To set this up, you need to pass in the AWS client as well as the bucket name you wish to use. For instance:

import { awsStorage } from "@metaplex-foundation/js-next";
import { S3Client } from "@aws-sdk/client-s3";

const awsClient = new S3Client({ region: 'us-east-1' });

metaplex.use(awsStorage(awsClient, 'my-nft-bucket'));

When uploading a MetaplexFile using metaplex.storage().upload(file), the unique name of the file will be used as the AWS key. By default, this will be a random string generated by the SDK but you may explicitly provide your own like so.

const file = new MetaplexFile('file-content', 'filename.jpg', {
    uniqueName: 'my-unique-aws-key',
})

const uri = await metaplex.storage().upload(file);

mockStorage

The mockStorage driver is a fake driver mostly used for testing purposes. It will not actually upload the assets anywhere but instead will generate random URLs and keep track of their content in a local dictionary. That way, once uploaded, an asset can be retrieved using the download method.

import { mockStorage } from "@metaplex-foundation/js-next";

metaplex.use(mockStorage());

Next steps

As mentioned above, this SDK is still in very early stages. We plan to add a lot more features to it. Here’s a quick overview of what we plan to work on next.

  • New features in the NFT module.
  • New modules such as an NFT Collections module, a Candy Machine module, an Action House module, etc.
  • More storage drivers.
  • More identity drivers.
  • New types of drivers such as error handling, logging, etc.
  • Extracting some of the SDK logic to external libraries for developers to reuse them in their own projects.
  • Adding more services and abstractions in order to encapsulate some of the quirky behaviour of the cluster and improve the user experience.
  • More documentation, tutorials, starter kits, etc.

Stay tuned. 🔥

Comments
  • Error on nfts().findAllByCreator(verifiedcreator)

    Error on nfts().findAllByCreator(verifiedcreator)

    When trying to get a collection using nfts().findAllByCreator(verifiedcreator) I get the following error;

    Version 0.15.0

    /app/node_modules/@solana/web3.js/lib/index.cjs.js:4909
    callback(new Error(`${res.status} ${res.statusText}: ${text}`));
    Error: 410 Gone:  {"jsonrpc":"2.0","error":{"code": 410, "message":"The RPC call or parameters have been disabled."}, "id": "73a0aec1-3805-4bf8-b121-40119a2eb8ac" }
    at ClientBrowser.callServer (/app/node_modules/@solana/web3.js/lib/index.cjs.js:4909:18)
    

    Using

    const { Metaplex, keypairIdentity, bundlrStorage } = require("@metaplex-foundation/js")
    const { Connection, clusterApiUrl, Keypair } = require("@solana/web3.js")
    
    async function getMetaplexData(creator) {
    
    const connection = new Connection(clusterApiUrl("mainnet-beta"));
        const wallet = Keypair.generate();
    
    const metaplex = Metaplex.make(connection)
          .use(keypairIdentity(wallet))
          .use(bundlrStorage())
    
    const nfts = await metaplex.nfts().findAllByCreator(creator).run();
        return nfts
    } 
    
    var collectionNFTs = await getMetaplexData('2UWNPgEto1x2TnBisJ814xdXKUQE5KFzypBNKPPjXz9b')
    console.log(collectionNFTs)
    
    opened by LaniakeaSC4 15
  • Verify Collection Feature

    Verify Collection Feature

    First, thank you for all metaplex-foundation's convenience library.

    Recently, I want to feature that verify collection. and #141 too. So I refer to Metaplex docs and cli-nft.ts that added verifying collection feature. There may be something I'm missing. and I write test code not yet, but simply working well. Please give us a lot of opinion.

    Thanks!

    opened by jon890 15
  • uploadMetadata(...) fails: MetaplexError: Bundlr > Failed to Initialize Bundlr

    uploadMetadata(...) fails: MetaplexError: Bundlr > Failed to Initialize Bundlr

    See code below; fails at uploadMetadata(...)

    const {
      Metaplex,
      keypairIdentity,
      bundlrStorage,
    } = require("@metaplex-foundation/js-next");
    
    async function mint(keypair: Keypair) {
      if (!keypair) {
        return;
      }
      const metaplex = Metaplex.make(connection)
        .use(keypairIdentity(keypair))
        .use(bundlrStorage());
    
      const { uri } = await metaplex.nfts().uploadMetadata({
        name: "My NFT",
        description: "My description",
        image:
          "https://www.arweave.net/VsKHsd9aJa2IZ82aYpcBuoT2PmXLifuM4HeeSYtRJj8?ext=jpeg",
      });
    
      console.log(uri);
    

    Crash logs:

    Unhandled Runtime Error
    MetaplexError: Bundlr > Failed to Initialize Bundlr
    >> Source: Plugin > Bundlr
    >> Problem: Bundlr could not be initialized.
    >> Solution: This could happen for a variety of reasons. Check the underlying error below for more information.
    
    Caused By: TypeError: Cannot read properties of undefined (reading 'toBuffer')
    
    Screen Shot 2022-05-01 at 3 32 29 PM
    opened by zkhalapyan 14
  • Makes BundlrStorageDriver work in browser contexts without polyfills

    Makes BundlrStorageDriver work in browser contexts without polyfills

    We've been getting reports from our users that installing @thirdweb-dev/sdk requires them to polyfill CRA and vite applications.

    I've hunted down the issue to be within @metaplex-foundation/js -> @bundlr-network/client.

    After some testing I found the simplest fix to be importing the @bundlr-network/client dependency with a dynamic import() instead of top level, which means the resulting bundle will load the correct version at runtime for web vs node contexts.

    Please let me know if there's anything I'm missing here, it seems to have no negative side-effects in my testing.

    opened by jnsdls 13
  • Adding metadata to a new fungible token.

    Adding metadata to a new fungible token.

    Overview

    I've been working on finding a method for adding metadata to a new fungible token for a few days now. However, it appears there is a need for this as one does not currently exist. I've documented some troubles in this Issue.

    Core Problem

    With the change from Solana-Labs Token List to the MetaPlexToken MetaData Program, there is now no method for adding MetaData to a new asset on Solana. There is documentation for the MetaPlex JS-SDK, however it focuses only on the nfts() method.

    The MetaPlex metadata instructions explain the metadata file, but they provide no explanation of how to actually add the metadata to a token. Thus, there is a need for a method to add metadata to new SPL tokens. This is important because without a method for adding metadata to assets, new SPL tokens cannot be launched on the Solana blockchain.

    Solution Needed An ideal solution would be a directory, guide, or resource providing a step-by-step guide on how to add metadata to an SPL fungible token. Thanks in advance - I sincerely appreciate any suggestions or advice!

    opened by Bhaney44 13
  • Update creators error: Incorrect account owner

    Update creators error: Incorrect account owner

    I'mn trying to update a list of nfts to have a new secondary creator (the one with the 100% share). I don't think it's possible to update the first creator because I think the first creator is signed by the candy machine that created the nft? Anyway here's my code:

    import { keypairIdentity, Metadata, Metaplex } from '@metaplex-foundation/js'
    import { Connection, Keypair, PublicKey } from '@solana/web3.js'
    import { program } from 'commander'
    import { readFileSync, writeFileSync } from 'fs'
    
    program
      .command('update_creators')
      .description('Updates the creator of all nfts')
      .requiredOption(
        '-i, --input-file <string>',
        'Json file, list of NFT mint details'
      )
      .requiredOption(
        '-o,  --output-file <string>',
        'Output file for NFT addresses that failed to update'
      )
      .requiredOption(
        '-k, --keypair-file <path>',
        `JSON file containing private key of token owner`,
        '.cache/creator-keypair.json'
      )
      .option('-r, --rpc <string>', 'JSON rpc api url', defaultRpc)
      .action(async ({ inputFile, outputFile, keypairFile, rpc }) => {
        const connection = new Connection(rpc)
        const metaplex = Metaplex.make(connection)
        const keypairFileContents = readFileSync(keypairFile, 'utf-8')
        const keypair = Keypair.fromSecretKey(
          Buffer.from(JSON.parse(keypairFileContents))
        )
        metaplex.use(keypairIdentity(keypair))
    
        const nftMintAddresses = JSON.parse(
          readFileSync(inputFile, 'utf-8')
        ) as string[]
    
        let nfts = (await metaplex
          .nfts()
          .findAllByMintList({
            mints: nftMintAddresses.map(mint => new PublicKey(mint)),
          })
          .run()) as Metadata[]
    
        const newCreator = new PublicKey(
          'CUAwUE5N3TdHHHyPTHb3E5mpnpQFiRF6BcY8kEvJakfS'
        )
        const failedNfts: any[] = []
    
        for (const nft of nfts) {
          try {
            console.dir(nft, { depth: null })
            const newNft = await metaplex
              .nfts()
              .update({
                nftOrSft: nft,
                creators: [
                  nft.creators[0],
                  {
                    address: newCreator,
                    share: 100,
                    authority: keypair,
                  },
                ],
              })
              .run()
            console.dir(newNft, { depth: null })
          } catch (e) {
            console.error(e)
            failedNfts.push(nft)
            process.exit()
          }
        }
        writeFileSync(outputFile, JSON.stringify(failedNfts))
      })
    

    Note, the metaplex.use() keypair I'm using is the same wallet used to create the candy machine and has authority to update the nfts. I keep getting the following error:

    ParsedProgramError [MetaplexError]: TokenMetadataProgram > Incorrect account owner
    >> Source: Program > TokenMetadataProgram [metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s]
    >> Problem: The program [TokenMetadataProgram] at address [metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s] raised an error of code [57] that translates to "Incorrect account owner".
    >> Solution: Check the error message provided by the program.
    
    Caused By: IncorrectOwner: Incorrect account owner
    
        at RpcClient.parseProgramError (C:\xampp\htdocs\sol-tools\node_modules\@metaplex-foundation\js\src\plugins\rpcModule\RpcClient.ts:302:9)
        at RpcClient.sendTransaction (C:\xampp\htdocs\sol-tools\node_modules\@metaplex-foundation\js\src\plugins\rpcModule\RpcClient.ts:87:18)
        at processTicksAndRejections (node:internal/process/task_queues:96:5)
        at async RpcClient.sendAndConfirmTransaction (C:\xampp\htdocs\sol-tools\node_modules\@metaplex-foundation\js\src\plugins\rpcModule\RpcClient.ts:117:23)
        at async TransactionBuilder.sendAndConfirm (C:\xampp\htdocs\sol-tools\node_modules\@metaplex-foundation\js\src\utils\TransactionBuilder.ts:189:22)
        at async C:\xampp\htdocs\sol-tools\node_modules\@metaplex-foundation\js\src\utils\Task.ts:82:23
        at async Disposable.run (C:\xampp\htdocs\sol-tools\node_modules\@metaplex-foundation\js\src\utils\Disposable.ts:34:14)
        at async Command.<anonymous> (C:\xampp\htdocs\sol-tools\src\cli.ts:263:24) {
      key: 'metaplex.errors.program.parsed_program_error',
      title: 'TokenMetadataProgram > Incorrect account owner',
      problem: 'The program [TokenMetadataProgram] at address [metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s] raised an error of code [57] that translates to "Incorrect account owner".',
      solution: 'Check the error message provided by the program.',
      source: 'program',
      sourceDetails: 'TokenMetadataProgram [metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s]',
      cause: IncorrectOwner: Incorrect account owner
          at Object.errorResolver (C:\xampp\htdocs\sol-tools\node_modules\@metaplex-foundation\js\src\plugins\nftModule\plugin.ts:70:16)
          at RpcClient.parseProgramError (C:\xampp\htdocs\sol-tools\node_modules\@metaplex-foundation\js\src\plugins\rpcModule\RpcClient.ts:299:35)
          at RpcClient.sendTransaction (C:\xampp\htdocs\sol-tools\node_modules\@metaplex-foundation\js\src\plugins\rpcModule\RpcClient.ts:87:18)
          at processTicksAndRejections (node:internal/process/task_queues:96:5)
          at async RpcClient.sendAndConfirmTransaction (C:\xampp\htdocs\sol-tools\node_modules\@metaplex-foundation\js\src\plugins\rpcModule\RpcClient.ts:117:23)
          at async TransactionBuilder.sendAndConfirm (C:\xampp\htdocs\sol-tools\node_modules\@metaplex-foundation\js\src\utils\TransactionBuilder.ts:189:22)
          at async C:\xampp\htdocs\sol-tools\node_modules\@metaplex-foundation\js\src\utils\Task.ts:82:23
          at async Disposable.run (C:\xampp\htdocs\sol-tools\node_modules\@metaplex-foundation\js\src\utils\Disposable.ts:34:14)
          at async Command.<anonymous> (C:\xampp\htdocs\sol-tools\src\cli.ts:263:24) {
        code: 57
      },
      logs: undefined,
      program: {
        name: 'TokenMetadataProgram',
        address: PublicKey {
          _bn: <BN: b7065b1e3d17c45389d527f6b04c3cd58b86c731aa0fdb549b6d1bc03f82946>
        },
        errorResolver: [Function: errorResolver],
        gpaResolver: [Function: gpaResolver]
      }
    }
    

    And here's one of the NFTs I'm trying to update:

    https://solscan.io/token/3woKb11Ajs9VkzHhMNkiyX5za1bV3STBmSaDHoQgmBKp#metadata

    Any help would be appreciated. Thanks!

    question 
    opened by elliott-w 12
  • How to update sft metadata

    How to update sft metadata

    One problem I am running into solving Issue 313 is that I am intending to update token metadata rather than create it. In Issue 748 we created a method for adding token metadata to an asset. The function we used was:

    const { sft } = await metaplex
      .nfts()
      .createSft({
        name: "TOKEN NAME",
        uri: "URI_LINK",
        sellerFeeBasisPoints: 0,
        useExistingMint: mint
      })
      .run();
    

    Here, we used the createSft method. However, I am getting an error running the code for a second time. I'm wondering whether there is an updateSft method or what the proper process for updating metadata is. I'd appreciate any advice or guidance. Thanks!

    opened by Bhaney44 11
  • MetaplexError: AuctionHouseProgram > Account is already initialized

    MetaplexError: AuctionHouseProgram > Account is already initialized"

    I'm trying to list NFT by the following code & getting an error(Account is already initialized). const { listing, sellerTradeState, receipt } = await metaplex .auctions() .for(auctionHouse) .list({ mintAccount: new PublicKey(mintAddress), price: sol(price), printReceipt: true, }) .run();

    question 
    opened by samia-invozone 11
  • AbortController is not a constructor

    AbortController is not a constructor

    I don't know resolving this problem. Maybe webpack bug..? I'm using

        "@metaplex-foundation/js": "^0.11.0",
        "@solana/wallet-adapter-base": "^0.9.5",
        "@solana/wallet-adapter-react": "^0.15.5",
        "@solana/wallet-adapter-react-ui": "^0.9.7",
        "@solana/wallet-adapter-wallets": "^0.16.1",
        "@solana/web3.js": "^1.44.0",
        "next": "12.1.6",
        "react": "18.1.0",
        "react-dom": "18.1.0"
    

    Here is my code

    import { Metaplex, Nft } from "@metaplex-foundation/js";
    import { useConnection, useWallet } from "@solana/wallet-adapter-react";
    import { PublicKey } from "@solana/web3.js";
    import { useState } from "react";
    
    export const CandyMachine: React.FC = () => {
      const { connection } = useConnection();
      const { publicKey, sendTransaction } = useWallet();
      const [nfts, setNfts] = useState<Nft[]>([]);
    
      const handleClick = async () => {
        const metaplex = Metaplex.make(connection);
    
        const result = await metaplex
          .nfts()
          .findAllByCandyMachine(
            new PublicKey(MY_CANDY_MACHINE_ID)
          );
    
        console.log(result);
    
        setNfts(result);
      };
    
      return (
        <>
          <button onClick={handleClick}>List Nfts</button>
          {nfts && nfts.map((nft) => <div key={nft.name}>{nft.toString()}</div>)}
        </>
      );
    };
    

    and this is error

    Task.mjs?d5d1:42 Uncaught (in promise) TypeError: abort_controller__WEBPACK_IMPORTED_MODULE_0__.AbortController is not a constructor
        at Task.forceRun (Task.mjs?d5d1:42:38)
        at Task.run (Task.mjs?d5d1:29:1)
        at OperationClient.execute (OperationClient.mjs?3849:41:1)
        at NftClient.findAllByCandyMachine (NftClient.mjs?85a8:36:1)
        at _callee$ (CandyMachine.tsx?3d41:16:8)
        at tryCatch (runtime.js?ecd4:45:16)
        at Generator.invoke [as _invoke] (runtime.js?ecd4:274:1)
        at prototype.<computed> [as next] (runtime.js?ecd4:97:1)
        at asyncGeneratorStep (CandyMachine.tsx?3d41:1:1)
        at _next (CandyMachine.tsx?3d41:1:1)
        at eval (CandyMachine.tsx?3d41:1:1)
        at new Promise (<anonymous>)
        at eval (CandyMachine.tsx?3d41:1:1)
        at handleClick (CandyMachine.tsx?3d41:11:20)
        at HTMLUnknownElement.callCallback (react-dom.development.js?ac89:4161:1)
        at Object.invokeGuardedCallbackDev (react-dom.development.js?ac89:4210:1)
        at invokeGuardedCallback (react-dom.development.js?ac89:4274:1)
        at invokeGuardedCallbackAndCatchFirstError (react-dom.development.js?ac89:4288:1)
        at executeDispatch (react-dom.development.js?ac89:9038:1)
        at processDispatchQueueItemsInOrder (react-dom.development.js?ac89:9070:1)
        at processDispatchQueue (react-dom.development.js?ac89:9083:1)
        at dispatchEventsForPlugins (react-dom.development.js?ac89:9094:1)
        at eval (react-dom.development.js?ac89:9285:1)
        at batchedUpdates$1 (react-dom.development.js?ac89:26096:1)
        at batchedUpdates (react-dom.development.js?ac89:3988:1)
        at dispatchEventForPluginEventSystem (react-dom.development.js?ac89:9284:1)
        at dispatchEventWithEnableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay (react-dom.development.js?ac89:6462:1)
        at dispatchEvent (react-dom.development.js?ac89:6454:1)
    
    opened by jon890 11
  • Issue using metaplex.nfts().create() on Quicknode

    Issue using metaplex.nfts().create() on Quicknode

    Using Quicknode either Mainnet/Devnet I get this error when I attempt to use metaplex.nfts().create()

    D:\#files\programming\solana\node_modules\@metaplex-foundation\js\dist\cjs\types\Account.cjs:32
        throw new SdkError.AccountNotFoundError(account.publicKey, name, {
              ^
    
    AccountNotFoundError [MetaplexError]: Account Not Found
    >> Source: SDK
    >> Problem: The account of type [MintAccount] was not found at the provided address [4um9a36fPUrGiqr5sudHYgeuHEkH41TyjMkuxMwp2vmK].
    >> Solution: Ensure the provided address is correct and that an account exists at this address.
    
        at assertAccountExists (D:\#files\programming\solana\node_modules\@metaplex-foundation\js\dist\cjs\types\Account.cjs:32:11)
        at Object.toMintAccount (D:\#files\programming\solana\node_modules\@metaplex-foundation\js\dist\cjs\types\Account.cjs:24:7)
        at Object.handle (D:\#files\programming\solana\node_modules\@metaplex-foundation\js\dist\cjs\plugins\nftModule\operations\findNftByMint.cjs:69:39)
        at processTicksAndRejections (node:internal/process/task_queues:96:5)
        at async Disposable.run (D:\#files\programming\solana\node_modules\@metaplex-foundation\js\dist\cjs\utils\Disposable.cjs:30:14)
        at async Object.handle (D:\#files\programming\solana\node_modules\@metaplex-foundation\js\dist\cjs\plugins\nftModule\operations\createNft.cjs:69:17)
        at async Disposable.run (D:\#files\programming\solana\node_modules\@metaplex-foundation\js\dist\cjs\utils\Disposable.cjs:30:14)
        at async D:\#files\programming\solana\compiled.js.file:388:15 {
      key: 'metaplex.errors.sdk.account_not_found',
      title: 'Account Not Found',
      problem: 'The account of type [MintAccount] was not found at the provided address [4um9a36fPUrGiqr5sudHYgeuHEkH41TyjMkuxMwp2vmK].',
      solution: 'Ensure the provided address is correct and that an account exists at this address.',
      source: 'sdk',
      sourceDetails: undefined,
      cause: undefined,
      logs: undefined
    }
    

    When I use https://api.devnet.solana.com RPC I do not get the error.

    I would like to use Quicknode though since I cannot use the solana.com RPCs for production application and to make as many API requests.

    It says "The account of type [MintAccount] was not found at the provided address [4um9a36fPUrGiqr5sudHYgeuHEkH41TyjMkuxMwp2vmK]." would you be able to loop until the mint account is found before proceeding? That may fix the issue.

    Here is the full code that will run. Only need to edit the top 2 variables. It gives an error message 50%+ of the time. pastebin.com/raw/XCWGfRGJ

    opened by indynov 10
  • Update method - Can't use this function on unsized collection

    Update method - Can't use this function on unsized collection

    Hi i'm getting this error when updating an NFT that belongs to an unsized collection:

    key: 'metaplex.errors.program.parsed_program_error', title: "TokenMetadataProgram > Can't use this function on unsized collection", problem: The program [TokenMetadataProgram] at address [metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s] raised an error of code [101] that translates to "Can't use this function on unsized collection"., solution: 'Check the error message provided by the program.', source: 'program', sourceDetails: 'TokenMetadataProgram [metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s]',

    i used the update method to update.

    const result = await metaplex.nfts().update({ nftOrSft: nft, uri: newUri }).run();

    i also tried to add a collectionIsSized: true in the params. but it still doesn't work. how do we update NFTs that belong to unsized collection now?

    opened by jesign 9
  • Error: Not enough funds to send data

    Error: Not enough funds to send data

    Hey there!

    Getting Error: Not enough funds to send data when running this command. Using Bundlr Storage. Been working well for awhile, but doesn't now. I'm wondering if something on bundlrs end changed maybe how they calculated how much is needed?

    I'm running this in devnet as well so not sure if that maybe an issue. https://devnet.bundlr.network https://api.devnet.solana.com

        const File = toMetaplexFile(ImageUrl[0], "TestImage");
    
        const offChainMetadata = {
          name: "test",
          description: "test",
          image: File,
        };
    
        const { uri } = await metaplex.nfts().uploadMetadata(offChainMetadata);
    

    Running the latest version of the js package 0.17.11

    Thanks for the insight.

    opened by rastrent 2
  • metaplex.nfts().findAllByOwner()  error

    metaplex.nfts().findAllByOwner() error

    const connection = new Connection(clusterApiUrl("mainnet-beta"));
    const metaplex = new Metaplex(connection, { cluster: 'mainnet-beta' });
    const ownerAddress = new PublicKey("C3HC8DrAoQqiWdCvo4u4nJATfmsHxwg3cZx18cUm9wuH");
    const nft = await metaplex.nfts().findAllByOwner({ owner: ownerAddress }).run();
    console.log(nft)
    

    [Error: 410 undefined: {"jsonrpc":"2.0","error":{"code": 410, "message":"The RPC call or parameters have been disabled."}, "id": "9b1b48e1-559d-42e8-aa0a-aa6402f27ab8" } ]

    opened by sunxxg 0
  • Support for Versioned Transaction

    Support for Versioned Transaction

    I want to add a new custom operation to the plugin but in that operation I need to use VersionedTransaction instead of the normal one.

    I am able to do this inside the handler as follows:

    import { Signer } from '@metaplex-foundation/js';
    import { Signer as SolanaSigner } from '@solana/web3.js';
    ..
    
    export const makeOfferOperationHandler: OperationHandler<MakeOfferOperation> = {
      async handle(
        operation: MakeOfferOperation,
        metaplex: Metaplex,
        scope: OperationScope
      ): Promise<MakeOfferOutput> {
        const builder = await makeOfferBuilder(metaplex, operation.input, scope);
    
        const { blockhash, lastValidBlockHeight } = await metaplex.connection.getLatestBlockhash();
    
        const lookupTableAccount = await metaplex.connection
          .getAddressLookupTable(operation.input.addressLookupTable)
          .then((res) => res.value);
    
        const messageV0 = new TransactionMessage({
          payerKey: builder.getFeePayer()!.publicKey,
          recentBlockhash: blockhash,
          instructions: builder.getInstructions(),
        }).compileToV0Message([lookupTableAccount!]);
    
        const transactionV0 = new VersionedTransaction(messageV0);
    
        transactionV0.sign(builder.getSigners() as SolanaSigner[]);
    
        const confirmOptions = makeConfirmOptionsFinalizedOnMainnet(metaplex, scope.confirmOptions);
    
        const signature = await metaplex.connection.sendRawTransaction(
          transactionV0.serialize(),
          confirmOptions
        );
    
        const response = await metaplex
          .rpc()
          .confirmTransaction(
            signature,
            { blockhash, lastValidBlockHeight },
            confirmOptions?.commitment
          );
    
        const output = {
          response,
          ...builder.getContext(),
        };
    
        scope.throwIfCanceled();
    
        return output;
      },
    };
    

    But getting this error while signing the transaction: Cannot read properties of undefined (reading 'slice')

    (I know type-casting the Signer was a bad idea.) Does anybody know how to solve this issue?

    opened by alchemistgo87 0
  • Upgrading metaplex breaks SPL createMint() with custom program error: 0xc / Invalid instruction

    Upgrading metaplex breaks SPL createMint() with custom program error: 0xc / Invalid instruction

    Hi Metaplex! I generally dislike raising an issue in more than one place, but there's at least a few of this experiencing issues where upgrading metaplex somehow breaks SPL. Right now people are just working around it by downgrading metaplex, but I'm interested in features and fixes from the latest metaplex, and I thought I'd make a GitHub issue as it seems to be a bug and you may not have seen it before. I can easily reproduce.

    More details on StackOverflow

    opened by mikemaccana 0
  • Bulk .findNfts operations output types are misleading.

    Bulk .findNfts operations output types are misleading.

    Operations .findNftsByCreator, findNftsByMintList, findNftsByOwner and findNftsByUpdateAuthority have output type (Metadata | Nft | Sft)[]. However, these operations might return only Metadata[].

    opened by fedorerd 0
  • storageClient fails to load nfts metadata stored in ipfs without the gateway

    storageClient fails to load nfts metadata stored in ipfs without the gateway

    image

    as shown in the above code it will fail to load the metadata if the stored metadata is an ipfs url

    eg: fetch("ipfs://bafybeibkahrvtb2i4xvz5du5xaiuagzuoy3upnpfqw5ufs7ffa4aydiiwa")

    opened by fallenangel2305 1
Releases(@metaplex-foundation/[email protected])
  • @metaplex-foundation/[email protected](Dec 17, 2022)

  • @metaplex-foundation/[email protected](Dec 17, 2022)

  • @metaplex-foundation/[email protected](Dec 17, 2022)

  • @metaplex-foundation/[email protected](Dec 16, 2022)

  • @metaplex-foundation/[email protected](Dec 16, 2022)

  • @metaplex-foundation/[email protected](Dec 16, 2022)

  • @metaplex-foundation/[email protected](Dec 13, 2022)

    Patch Changes

    • a7159835: Simply Metaplex Errors using mostly the name and message attributes
    • 6d74717a: Fix fee payer on update NFT operation
    • c752015f: Add oldCollectionAuthority input to update NFT operation
    Source code(tar.gz)
    Source code(zip)
  • @metaplex-foundation/[email protected](Dec 13, 2022)

  • @metaplex-foundation/[email protected](Dec 13, 2022)

  • @metaplex-foundation/[email protected](Dec 8, 2022)

  • @metaplex-foundation/[email protected](Dec 8, 2022)

  • @metaplex-foundation/[email protected](Dec 8, 2022)

  • js/v0.17.8(Dec 4, 2022)

  • js/v0.17.7(Dec 2, 2022)

    What's Changed

    • Simplify running local tests by @lorisleiva in https://github.com/metaplex-foundation/js/pull/410
    • Program Gate Guard by @chambaz in https://github.com/metaplex-foundation/js/pull/409
    • Make plugin install methods return void by @lorisleiva in https://github.com/metaplex-foundation/js/pull/412
    • Set up GitHub label automations by @lorisleiva in https://github.com/metaplex-foundation/js/pull/413
    • Chore: bump @metaplex-foundation/candy-machine by @stegaBOB in https://github.com/metaplex-foundation/js/pull/420

    New Contributors

    • @chambaz made their first contribution in https://github.com/metaplex-foundation/js/pull/409

    Full Changelog: https://github.com/metaplex-foundation/js/compare/js/v0.17.6...js/v0.17.7

    Source code(tar.gz)
    Source code(zip)
  • js/v0.17.6(Nov 21, 2022)

    What's Changed

    • Makes BundlrStorageDriver work in browser contexts without polyfills by @jnsdls in https://github.com/metaplex-foundation/js/pull/379
    • Documentation Error 'The amount of tokens to (mint -> send)' by @CoachChuckFF in https://github.com/metaplex-foundation/js/pull/401
    • Add support for freeze guards on Candy Machine v3 by @lorisleiva in https://github.com/metaplex-foundation/js/pull/403
    • Update Auction House program by @lorisleiva in https://github.com/metaplex-foundation/js/pull/399

    New Contributors

    • @jnsdls made their first contribution in https://github.com/metaplex-foundation/js/pull/379

    Full Changelog: https://github.com/metaplex-foundation/js/compare/js/v0.17.5...js/v0.17.6

    Source code(tar.gz)
    Source code(zip)
  • js/v0.17.5(Nov 2, 2022)

    What's Changed

    • Add support for updating the Candy Guard authority by @lorisleiva in https://github.com/metaplex-foundation/js/pull/390

    Full Changelog: https://github.com/metaplex-foundation/js/compare/js/v0.17.4...js/v0.17.5

    Source code(tar.gz)
    Source code(zip)
  • js/v0.17.4(Oct 28, 2022)

    What's Changed

    • feat: efficient findNftsBy methods by reducing RPC calls by @KartikSoneji in https://github.com/metaplex-foundation/js/pull/370
    • Update Candy Machine v3 serialization by @lorisleiva in https://github.com/metaplex-foundation/js/pull/378

    Full Changelog: https://github.com/metaplex-foundation/js/compare/js/v0.17.3...js/v0.17.4

    Source code(tar.gz)
    Source code(zip)
  • js/v0.17.3(Oct 26, 2022)

    What's Changed

    • Documentation Error 'The amount of tokens to (mint -> send)' by @CoachChuckFF in https://github.com/metaplex-foundation/js/pull/360
    • Update Auction House's find listings to allow multiple criteria by @zaxozhu in https://github.com/metaplex-foundation/js/pull/363
    • Add script to generate workspace.json by @ovasylenko in https://github.com/metaplex-foundation/js/pull/364
    • Fix MerkleTree import by @lorisleiva in https://github.com/metaplex-foundation/js/pull/371
    • Implement Find All Bids/Purchases by @zaxozhu in https://github.com/metaplex-foundation/js/pull/373

    New Contributors

    • @CoachChuckFF made their first contribution in https://github.com/metaplex-foundation/js/pull/360

    Full Changelog: https://github.com/metaplex-foundation/js/compare/js/v0.17.2...js/v0.17.3

    Source code(tar.gz)
    Source code(zip)
  • js/v0.17.2(Oct 17, 2022)

    What's Changed

    • Update token metadata package to 2.3.3 by @zaxozhu in https://github.com/metaplex-foundation/js/pull/348
    • Fix Bundlr upload transaction failure in browser by @zaxozhu in https://github.com/metaplex-foundation/js/pull/349
    • Use appropriate payers in derived identity by @lorisleiva in https://github.com/metaplex-foundation/js/pull/351

    Full Changelog: https://github.com/metaplex-foundation/js/compare/js/v0.17.1...js/v0.17.2

    Source code(tar.gz)
    Source code(zip)
  • js/v0.17.1(Oct 12, 2022)

    What's Changed

    • Fix Buffer related error in browsers by @acheroncrypto in https://github.com/metaplex-foundation/js/pull/347

    New Contributors

    • @acheroncrypto made their first contribution in https://github.com/metaplex-foundation/js/pull/347

    Full Changelog: https://github.com/metaplex-foundation/js/compare/js/v0.17.0...js/v0.17.1

    Source code(tar.gz)
    Source code(zip)
  • js/v0.17.0(Oct 10, 2022)

    What's Changed

    • New Candy Machine module by @lorisleiva in https://github.com/metaplex-foundation/js/pull/315
    • Improve the monorepo structure by @ovasylenko in https://github.com/metaplex-foundation/js/pull/274
    • Update web3.js and other dependencies by @lorisleiva in https://github.com/metaplex-foundation/js/pull/326
    • Import Amman account providers by @lorisleiva in https://github.com/metaplex-foundation/js/pull/327
    • Remove run() suffix on operations by @lorisleiva in https://github.com/metaplex-foundation/js/pull/335
    • Use finalized commitment before fetching data by @lorisleiva in https://github.com/metaplex-foundation/js/pull/336
    • Add support for Candy Guard route instructions by @lorisleiva in https://github.com/metaplex-foundation/js/pull/339
    • Update CG program and use official program libraries by @lorisleiva in https://github.com/metaplex-foundation/js/pull/340

    Breaking Changes

    The .run() suffix was removed from every operation call. That means you must now call operation as shown below. You can read more about this decision in PR #335.

    // Before.
    const { nft } = await metaplex.nfts().create({...}).run();
    
    // After.
    const { nft } = await metaplex.nfts().create({...});
    

    All operations now accept a second object argument which is the same for all operations. It enables us to provide more generic information such as the fee payer and the commitment levels to use when querying the blockchain. PR #335 also contains information about this change.

    export type OperationOptions = {
      /** The wallet that should pay for transaction fees and, potentially, rent-exempt fees to create accounts.*/
      payer?: Signer;
    
      /** The level of commitment desired when querying the state of the blockchain. */
      commitment?: Commitment;
    
      /** Options for confirming transactions as defined by the Solana web3.js library.*/
      confirmOptions?: ConfirmOptions;
    
      /** An optional set of programs that override the registered ones. */
      programs?: Program[];
    
      /** An abort signal that can be used to cancel the operation. */
      signal?: AbortSignal;
    };
    

    This means, if you were providing some of these generic parameters as part of the first argument, you will need to pass them in the second argument instead.

    // Before.
    const { nft } = await metaplex.nfts().create({ ..., payer: someOtherPayer }).run();
    
    // After, locally.
    const { nft } = await metaplex.nfts().create({...}, { payer: someOtherPayer });
    
    // After, globally (default to the current identity).
    metaplex.rpc().setDefaultFeePayer(someOtherPayer);
    const { nft } = await metaplex.nfts().create({...});
    

    Additionally, if you were using abort signals within the run() method before, you must now provide them within the second argument of the operation directly like so.

    const abortController = new AbortController();
    
    // Before.
    const { nft } = await metaplex.nfts().create({...}).run({
      signal: abortController.signal,
    });
    
    // After.
    const { nft } = await metaplex.nfts().create({...}, {
      signal: abortController.signal,
    });
    

    PDA helper methods have also been refactored to make use of Metaplex’s Program Repository which allows you to override default programs and register your own.

    // Before.
    const metadataAddress = findMetadataPda(mintAddress);
    
    // After.
    const metadataAddress = metaplex.nfts().pdas().metadata({
      mint: mintAddress
    });
    

    Whilst the new way is more lengthy, it ensures the computed PDAs are using the programs you registered via metaplex.programs().register(). You may even provide local overrides via the programs property like so.

    // After, with local program overrides.
    const metadataAddress = metaplex.nfts().pdas().metadata({
      mint: mintAddress,
      programs,
    });
    

    Last but not least, the Candy Machine V2 module has been renamed to be explicitly called CandyMachineV2 to allow the latest Candy Machine V3 iteration to become the main Candy Machine module on the SDK. Therefore, if you were using the Candy Machine V2 module before, you will need to rename your clients like this.

    // Before.
    const candyMachineV2 = metaplex.candyMachines().create({...}).run();
    
    // After.
    const candyMachineV2 = metaplex.candyMachinesV2().create({...});
    const candyMachineV3 = metaplex.candyMachines().create({...});
    

    New Contributors

    • @ovasylenko made their first contribution in https://github.com/metaplex-foundation/js/pull/274

    Full Changelog: https://github.com/metaplex-foundation/js/compare/js/v0.16.1...js/v0.17.0

    Source code(tar.gz)
    Source code(zip)
  • js/v0.16.1(Oct 3, 2022)

    What's Changed

    • Add Direct Buy & Sell operations by @zaxozhu in https://github.com/metaplex-foundation/js/pull/289
    • Add support for setting the default fee payer by @lorisleiva in https://github.com/metaplex-foundation/js/pull/325

    Full Changelog: https://github.com/metaplex-foundation/js/compare/js/v0.16.0...js/v0.16.1

    Source code(tar.gz)
    Source code(zip)
  • js/v0.16.0(Sep 30, 2022)

    What's Changed

    • Write custom typedoc plugin and add CI workflow to publish API references by @lorisleiva in https://github.com/metaplex-foundation/js/pull/243
    • Manually deploy API references instead by @lorisleiva in https://github.com/metaplex-foundation/js/pull/244
    • Add Find Listing by Receipt to Auction House by @zaxozhu in https://github.com/metaplex-foundation/js/pull/242
    • Add Find Purchase by Receipt to Auction House by @zaxozhu in https://github.com/metaplex-foundation/js/pull/246
    • Write docblock retroactively on token, system, CM and NFT modules by @lorisleiva in https://github.com/metaplex-foundation/js/pull/249
    • Refactor Auction House client by @zaxozhu in https://github.com/metaplex-foundation/js/pull/251
    • Format Amount: fix decimals with leading zeroes by @cosimo-rip in https://github.com/metaplex-foundation/js/pull/250
    • Require less data in transaction builders in Auction House by @zaxozhu in https://github.com/metaplex-foundation/js/pull/258
    • Add Deposit instruction by @zaxozhu in https://github.com/metaplex-foundation/js/pull/265
    • Add find bids, listings, purchases to Auction House by @zaxozhu in https://github.com/metaplex-foundation/js/pull/252
    • docs: fixed links by @tjkyner in https://github.com/metaplex-foundation/js/pull/278
    • Fix keypairIdentity() error on web (#202) by @KartikSoneji in https://github.com/metaplex-foundation/js/pull/268
    • Add optional publicKey to guestIdentity by @mcintyre94 in https://github.com/metaplex-foundation/js/pull/280
    • Implement Withdraw from Fees & Treasury by @zaxozhu in https://github.com/metaplex-foundation/js/pull/276
    • Auction House documentation by @zaxozhu in https://github.com/metaplex-foundation/js/pull/282
    • Add Withdraw instruction by @antey13 in https://github.com/metaplex-foundation/js/pull/275
    • Fix typo in UninitializedWalletAdapterError by @steveluscher in https://github.com/metaplex-foundation/js/pull/290
    • Add operations builders to AuctionHouseBuildersClient by @antey13 in https://github.com/metaplex-foundation/js/pull/283
    • Candy Machine: accurate Amount if a tokenMintAddress is specified, fixes [#234] by @cosimo-rip in https://github.com/metaplex-foundation/js/pull/279
    • Auction House Partial Sale by @zaxozhu in https://github.com/metaplex-foundation/js/pull/291
    • Update Solana on CI by @zaxozhu in https://github.com/metaplex-foundation/js/pull/311
    • Fix now() helper method by @lorisleiva in https://github.com/metaplex-foundation/js/pull/322
    • Fix "Can't use this function on unsized collection" error on nfts.update operation by @lorisleiva in https://github.com/metaplex-foundation/js/pull/321

    New Contributors

    • @tjkyner made their first contribution in https://github.com/metaplex-foundation/js/pull/278
    • @KartikSoneji made their first contribution in https://github.com/metaplex-foundation/js/pull/268
    • @mcintyre94 made their first contribution in https://github.com/metaplex-foundation/js/pull/280
    • @antey13 made their first contribution in https://github.com/metaplex-foundation/js/pull/275
    • @steveluscher made their first contribution in https://github.com/metaplex-foundation/js/pull/290

    Full Changelog: https://github.com/metaplex-foundation/js/compare/js/v0.15.0...js/v0.16.0

    Source code(tar.gz)
    Source code(zip)
  • js/v0.15.0(Aug 16, 2022)

    What's Changed

    • Update token and system modules so they can be used as references for other modules by @lorisleiva in https://github.com/metaplex-foundation/js/pull/231
    • Add Find Bid by Receipt to Auction House by @zaxozhu in https://github.com/metaplex-foundation/js/pull/235
    • Refactor and fix transaction builder issues in NFT and Candy Machine modules by @lorisleiva in https://github.com/metaplex-foundation/js/pull/236
    • Update docblocks and readme by @lorisleiva in https://github.com/metaplex-foundation/js/pull/240

    Breaking Changes

    All client methods now accept an object of input as a first argument. Whilst this is slightly less convenient it makes the high-level API a lot more consistent and easier to maintain in the future as we can more easily deprecate attributes and introduce new ones without adding breaking changes.

    For instance, here's how you'd fetch an NFT by mint address before and after this release.

    // Before
    const nft = await metaplex.nfts().findByMint(mintAddress).run();
    
    // After
    const nft = await metaplex.nfts().findByMint({ mintAddress }).run();
    

    The README has been updated accordingly.

    Full Changelog: https://github.com/metaplex-foundation/js/compare/js/v0.14.1...js/v0.15.0

    Source code(tar.gz)
    Source code(zip)
  • js/v0.14.1(Aug 15, 2022)

    What's Changed

    • Fix: Force version 4.3.0 on autogenerated Candy Machine library until the package gets fixed
    • Fix: file path for createNft.ts in readme by @Muhammad-Hasham-Khalid in https://github.com/metaplex-foundation/js/pull/220
    • Auction House Cancel Bid/Listing by @zaxozhu in https://github.com/metaplex-foundation/js/pull/222

    New Contributors

    • @Muhammad-Hasham-Khalid made their first contribution in https://github.com/metaplex-foundation/js/pull/220

    Full Changelog: https://github.com/metaplex-foundation/js/compare/js/v0.14.0...js/v0.14.1

    Source code(tar.gz)
    Source code(zip)
  • js/v0.14.0(Aug 5, 2022)

    What's Changed

    • Add Auctioneer delegate & extend Bid to allow Auctioneer by @zaxozhu in https://github.com/metaplex-foundation/js/pull/185
    • Add support for SFTs and refactor NFT module accordingly by @lorisleiva in https://github.com/metaplex-foundation/js/pull/206
    • Add support for verifying creators by @lorisleiva in https://github.com/metaplex-foundation/js/pull/208
    • Support use authorities by @lorisleiva in https://github.com/metaplex-foundation/js/pull/209
    • Support NFT Collections by @lorisleiva in https://github.com/metaplex-foundation/js/pull/210
    • Make SDK errors easier to reuse by adding an option object by @lorisleiva in https://github.com/metaplex-foundation/js/pull/211
    • Improve token module and ensure missing token accounts are created by @lorisleiva in https://github.com/metaplex-foundation/js/pull/212
    • Add Execute Sale operation by @zaxozhu in https://github.com/metaplex-foundation/js/pull/205
    • Add support for token delegation, token freezing and burning NFTs by @lorisleiva in https://github.com/metaplex-foundation/js/pull/215

    Full Changelog: https://github.com/metaplex-foundation/js/compare/js/v0.13.3...js/v0.14.0

    Source code(tar.gz)
    Source code(zip)
  • js/v0.13.3(Aug 5, 2022)

    What's Changed

    • Add program address and version to Candy Machine model by @lorisleiva in https://github.com/metaplex-foundation/js/pull/198

    Full Changelog: https://github.com/metaplex-foundation/js/compare/js/v0.13.2...js/v0.13.3

    Source code(tar.gz)
    Source code(zip)
  • js/v0.13.2(Jul 25, 2022)

    What's Changed

    • fix: create(input) links in README by @kquirapas in https://github.com/metaplex-foundation/js/pull/187
    • feat: Added addMetadata to nfts plugin by @stegaBOB in https://github.com/metaplex-foundation/js/pull/183
    • Fix: allow creators to be null by @stegaBOB in https://github.com/metaplex-foundation/js/pull/188
    • Delete a candy machine and withdraw its rent by @lorisleiva in https://github.com/metaplex-foundation/js/pull/192

    New Contributors

    • @kquirapas made their first contribution in https://github.com/metaplex-foundation/js/pull/187
    • @stegaBOB made their first contribution in https://github.com/metaplex-foundation/js/pull/183

    Full Changelog: https://github.com/metaplex-foundation/js/compare/js/v0.13.1...js/v0.13.2

    Source code(tar.gz)
    Source code(zip)
  • js/v0.13.1(Jul 25, 2022)

    What's Changed

    • Fix TS path resolution in nested generic types by @lorisleiva in https://github.com/metaplex-foundation/js/pull/184

    Full Changelog: https://github.com/metaplex-foundation/js/compare/js/v0.13.0...js/v0.13.1

    Source code(tar.gz)
    Source code(zip)
  • js/v0.13.0(Jul 21, 2022)

    What's Changed

    • Make the JS SDK a Monorepo by @lorisleiva in https://github.com/metaplex-foundation/js/pull/177

    Breaking Changes

    • Extracted the AWS storage driver into its own package.

    Full Changelog: https://github.com/metaplex-foundation/js/compare/v0.12.3...js/v0.13.0

    Source code(tar.gz)
    Source code(zip)
Owner
Metaplex Foundation
Metaplex Foundation
A module federation SDK which is unrelated to tool chain for module consumer.

hel-micro, 模块联邦sdk化,免构建、热更新、工具链无关的微模块方案 Demo hel-loadash codesandbox hel-loadash git Why hel-micro 如何使用远程模块 仅需要一句npm命令即可载入远程模块,查看下面例子线上示例 1 安装hel-micr

腾讯TNTWeb前端团队 319 Jan 3, 2023
🥁 Batch contract/on-chain queries to the same block. Multicall SDK for the Klaytn blockchain.

Klaytn Multicall Built for inevitable-changes/bento Inspired by makerdao/multicall and dopex-io/web3-multicall ?? Installation # Yarn yarn install kla

Inevitable (Bento) 4 Nov 7, 2022
Elizabeth Oyinlade Ojesanmi 10 Sep 14, 2022
Solana blockchain candy machine app boilerplate on top of Metaplex Candy Machine. NextJS, Tailwind, Anchor, SolanaLabs.React, dev/mainnet automation scripts.

NFT Candy Factory NOTE: This repo will prob only work on unix-based environments. The NFT Candy Factory project is designed to let users fork, customi

Kevin Faveri 261 Dec 30, 2022
This repo contains instructions on how to create your NFT in Solana(using Metaplex and Candy Machine) and mint it using your custom front-end Dapp

Solana-NFT minting Dapp Create your own NFT's on Solana, and mint them from your custom front-end Dapp. Tools used Metaplex -> Metaplex is the NFT sta

Udit Sankhadasariya 12 Nov 2, 2022
NFT vending machine proof of concept built on Solana Pay, Metaplex, Phantom Mobile and Next.js.

Solana NFT Vending Machine This is a proof of concept of an NFT vending machine built using Solana Pay, Metaplex, Phantom Mobile, and Next.js. This wa

Matt Rosenzweig 55 Dec 15, 2022
Wonka JS is the easiest way to mint Metaplex's Candy Machine NFTs with APIs.

Wonka JS Wonka JS is the easiest way to mint from Candy Machine and fetch NFTs through JS APIs. You can see an end to end example in Next.js demo proj

Wonka Labs 71 Nov 3, 2022
A full-featured Solana Metaplex Candymachine client-side library in Typescript

Candymachine Client SDK A full-featured Solana Metaplex Candymachine client-side library in Typescript Disclaimer: The SDK is currently a pre-alpha ve

Boxfish Studio 36 Nov 10, 2022
CryptoDappy is the fastest way to get started with Flow.

Demo application (testnet) Learning hub (start learning here) What's CryptoDappy? CryptoDappy is the fastest way to get started with blockchain develo

Benjamin Ebner 91 Aug 18, 2022
Functions Recipes is a library of examples to help you getting started with Salesforce Functions and get used to their main features.

Functions Recipes Introduction Salesforce Functions lets you use the Salesforce Platform for building event-driven, elastically scalable apps and expe

Trailhead Apps 172 Dec 29, 2022
Get started on Remix with TypeScript and Tailwind CSS in seconds

remix-typescript-tailwind-quickstart Get started on Remix with TypeScript and Tailwind CSS in seconds. This is an example setup of Remix building on t

Resi Respati 12 Mar 16, 2022
The fastest way to get started with a fully-fledged web3 frontend

create-web3-frontend The fastest way to get started with a fully-fledged web3 frontend setup consisting of Next.js, wagmi and Tailwind CSS. npx create

Dhaiwat Pandya 153 Dec 28, 2022
A simple template to get started with a non-profit website.

Next.js Non-Profit Website A non-profit website template powered by the Cosmic headless CMS. Uses Next.js, Tailwind CSS, and Stripe for donation payme

Cosmic 5 Sep 6, 2022
TechSquad Community is what you need to get started in Coding and Development

TechSquad Community is what you need to get started in Coding and Development This is a Community website under development. This community aims to cr

TechSquad Community 18 Dec 16, 2022
Minimal template to get started with Foundry + Hardhat

Hardhat x Foundry Template Template repository for getting started quickly with Hardhat and Foundry in one project Getting Started Use Foundry: forge

Foundry 158 Jan 3, 2023
Get started with AI vision at the edge with no coding experience at all!

No-Code Edge AI Vision with Node-RED Now you can get started with AI vision at the edge in just THREE STEPS with no coding experience at all! Prerequi

Seeed Studio 47 Dec 5, 2022
Get started with GatsbyJS straight away without having to spend a whole day configuring your usual addons.

Gatsby Starter Infinite Get started with GatsbyJS straight away without having to spend a whole day configuring your usual addons. This starter includ

Matt Patterson 3 Jun 27, 2022
🏄‍♂️ A node.js template to quickly get started building

hacky-node-template ??‍♂️ A type-safe Node.js template to quickly get started building. Tech-stack Express.js - Fast, un-opinionated, minimalist web f

Mukesh 7 Jan 4, 2023