Skip to content

Using the SDK to Gaslessly Create 1155 Contracts and Tokens, aka Premints

Intro to Premints

The Zora Protocol allows creators to create 1155 contracts and tokens without needing to pay any gas or have eth in their wallet. This is done by creating what's called a Premint - a signed intent to create and setup an 1155 contract and/or token. It is then uploading it to an API, where it can be retrieved later to bring onchain and mint by an account willing to pay the gas to do so. This can either be the first collector, or the the original creator of the Premint. The account that brings the Premint onchain will earn the first minter reward.

In order for the Premint to be discoverable in the Zora network, it must be signed by the creator's wallet and uploaded to the Zora Premint API. Before the Premint is brought onchain, the creator of the Premint can sign a message to update or delete it.

Creator Client for Premints

The Zora Protocol SDK encapsulates the complexity for creating, updating and deleting premints, by providing methods that handle building the Premint to sign, signing the Premint, and submitting the Premint and signature to the Zora Premint API so it can be fetched later.

Premints can be collected using the Collect Client's mint().

Setup the Creator Client

Initialize the Creator Client:

import { createCreatorClient } from "@zoralabs/protocol-sdk";
import { zora } from "viem/chains";
 
const creatorClient = createCreatorClient({ chain: zora });
 
creatorClient.
create1155
createPremint
deletePremint
updatePremint

Creating a Premint

The function createPremint builds a new premint with sensible defaults, and provides methods to sign and submit it to the Zora Premint API.

Just calling createPremint does not actually submit the premint to the API; it just builds the premint object and corresponding data to sign.

One of the items returned from create is signAndSubmit which must be called with a WalletClient to sign the premint and submit the premint and signature to the Zora Premint API.

example.ts
import { createCreatorClient } from "@zoralabs/protocol-sdk";
import { walletClient, chainId, publicClient, creatorAccount } from "./config";
 
const creatorClient = createCreatorClient({ chainId, publicClient });
 
// create and sign the Premint, the Premint and signature will be uploaded to an api to be served later
const {
  // used to sign and submit the premint to the Zora Premint API
  signAndSubmit,
} = await creatorClient.createPremint({
  // collection info of collection to create.  The combination of these fields will determine the
  // deterministic collection address.
  contract: {
    // the account that will be the admin of the collection.  Must match the signer of the premint.
    contractAdmin: creatorAccount,
    contractName: "Testing Contract",
    contractURI:
      "ipfs://bafkreiainxen4b4wz4ubylvbhons6rembxdet4a262nf2lziclqvv7au3e",
  },
  // token info of token to create
  token: {
    tokenURI:
      "ipfs://bafkreice23maski3x52tsfqgxstx3kbiifnt5jotg3a5ynvve53c4soi2u",
    // address to get create referral reward
    createReferral: "0x5843c8d6007813de3D2313fC55F2Fa1Cbbc394A6",
    // maximum number of tokens that can be minted.
    maxSupply: 50000n,
    // the maximum number of tokens that can be minted to a single address.
    maxTokensPerAddress: 10n,
    // the earliest time the premint can be brought onchain.  0 for immediate.
    mintStart: 0n,
    // the duration of the mint.  0 for infinite.
    mintDuration: 0n,
    // the price in eth per token, for paid mints.  0 for it to be a free mint.
    pricePerToken: 0n,
    // address to receive creator rewards for free mints, or if its a paid mint, the paid mint sale proceeds.
    payoutRecipient: creatorAccount,
  },
});
 
// sign the new premint, and submit it to the Zora Premint API
await signAndSubmit({
  // account to sign the premint
  account: creatorAccount,
  // the walletClient will be used to sign the message.
  walletClient,
  // if true, the signature will be checked before being submitted.
  // this includes validating that the signer is authorized to create the premint.
  checkSignature: true,
});

Signing and Submitting Premint a Premint using Wagmi

Sometimes it may be desirable to sign a premint with another library, and not using the sdk's signAndSubmit method. For this case, the createPremint, updatePremint, and deletePremint functions return a typedDataDefinition which is the typed data definition for the premint and must be signed. Once the signature has been obtained, it can be submitted to the Zora Premint API using the submit method:

import { createCreatorClient } from "@zoralabs/protocol-sdk";
import { useAccount, useChainId, usePublicClient, useSignTypedData } from "wagmi";
 
const chainId = useChainId();
const publicClient = usePublicClient()!;
const { address: creatorAddress } = useAccount();
 
const creatorClient = createCreatorClient({ chainId, publicClient });
 
const {
  // data to sign
  typedDataDefinition,
  // submit will submit the signature and premint to the api
  submit
} = await creatorClient.createPremint({
  // info of the 1155 contract to create.
  contract: {
    // the account that will be the admin of the collection.  
    // Must match the signer of the premint.
    contractAdmin: creatorAddress!,
    contractName: "Testing Contract",
    contractURI:
      "ipfs://bafkreiainxen4b4wz4ubylvbhons6rembxdet4a262nf2lziclqvv7au3e",
  },
  // token info of token to create
  token: {
    tokenURI:
      "ipfs://bafkreice23maski3x52tsfqgxstx3kbiifnt5jotg3a5ynvve53c4soi2u",
    payoutRecipient: creatorAddress!,
  },
});
 
const { signTypedData, data: signature } = useSignTypedData();
 
if (signature) {
  submit({
    signature
  });
}
 
// when the user clicks to create, sign the typed data
<button onClick={() => signTypedData(typedDataDefinition)}>Create</button>

Updating a Premint

Before a Premint is brought onchain, it can be updated by the original creator of that premint, by having that creator sign a message indicating the update. This signature and updated premint is then submitted to the Zora Premint API and replaces the existing stored premint for the token with the same uid.

example.ts
import { createCreatorClient } from "@zoralabs/protocol-sdk";
import { walletClient, chainId, creatorAccount, publicClient } from "./config";
import { collection, uid } from "./create";
 
const creatorClient = createCreatorClient({ chainId, publicClient });
 
const { signAndSubmit } = await creatorClient.updatePremint({
  // the premint collection to update is returned from the `createPremint` call
  collection,
  // the id of the premint to update
  uid,
  // updates to the existing token on the premint
  tokenConfigUpdates: {
    maxTokensPerAddress: 100n,
  },
});
 
// sign and submit the update to the Premint
await signAndSubmit({
  walletClient,
  account: creatorAccount,
});

Deleting a Premint

Before a premint is brought onchain, it can be deleted by the original creator of that premint, by having that creator sign a message indicating that the premint should be deleted. This signature and deleted premint is then submitted to the Zora Premint API and causes the API to no longer serve that premint.

example.ts
import { createCreatorClient } from "@zoralabs/protocol-sdk";
import { walletClient, chainId, creatorAccount, publicClient } from "./config";
import { collection, uid } from "./create";
 
const creatorClient = createCreatorClient({ chainId, publicClient });
 
const { signAndSubmit } = await creatorClient.deletePremint({
  // Premint collection address to delete the premint from
  collection,
  // id of the premint
  uid,
});
 
// sign and submit the deletion of the Premint
await signAndSubmit({
  account: creatorAccount,
  // the walletClient will be used to sign the message.
  walletClient,
});

Earning Create Referral Referral Rewards

To earn a create referral reward, pass in the createReferral argument when creating a Premint:

const creatorClient = createCreatorClient({ chainId, publicClient });
 
await creatorClient.createPremint({
  // collection info of contract to create. 
  contract: {
    contractAdmin: creatorAccount!,
    contractName: "Testing Contract",
    contractURI:
      "ipfs://bafkreiainxen4b4wz4ubylvbhons6rembxdet4a262nf2lziclqvv7au3e",
  },
  token: {
    tokenURI:
      "ipfs://bafkreice23maski3x52tsfqgxstx3kbiifnt5jotg3a5ynvve53c4soi2u",
    payoutRecipient: creatorAccount!,
    // create referral address will get the create referral reward
    // when the token is minted.
    createReferral: "0x5843c8d6007813de3D2313fC55F2Fa1Cbbc394A6", 
  },
});