Skip to content

Create Onchain 1155 Contracts & Tokens

The Protocol SDK can be used to prepare transactions to create 1155 contracts and tokens, using the Creator Client.

Setup/Create the Creator Client

Initialize a Creator Client with a chain id and PublicClient. The chain is used to determine the network to interact with.

import { createCreatorClient } from "@zoralabs/protocol-sdk";
import { createPublicClient, http, Chain } from 'viem';
import { zora } from "viem/chains";
 
const publicClient = createPublicClient({ 
  chain: zora as Chain, 
  transport: http() 
});
 
const creatorClient = createCreatorClient({ chainId: zora.id, publicClient });

Creating a new 1155 contract and token with Secondary Markets

The function create1155 is used to create a new 1155 contract and token. By default, the token will be created with the ZoraTimedSaleStrategyMinter as the minter, meaning that after the primary sale is complete, a secondary market powered by Uniswap will begin. The contract argument needs to be contract creation parameters. Calling this function prepares a parameters for a transaction that creates an 1155 contract at the deterministic address based on those parameters, and a token on that contract.

example.ts
import {
  useAccount,
  useChainId,
  usePublicClient,
  useWriteContract,
} from "wagmi";
import { createCreatorClient } from "@zoralabs/protocol-sdk";
 
// use wagmi hooks to get the chainId, publicClient, and account
const chainId = useChainId();
const publicClient = usePublicClient()!;
const { address } = useAccount();
 
const creatorClient = createCreatorClient({ chainId, publicClient });
 
const { parameters, contractAddress } = await creatorClient.create1155({
  // the contract will be created at a deterministic address
  contract: {
    // contract name
    name: "testContract",
    // contract metadata uri
    uri: "ipfs://DUMMY/contract.json",
  },
  token: {
    tokenMetadataURI: "ipfs://DUMMY/token.json",
  },
  // account to execute the transaction (the creator)
  account: address!,
});
 
const { writeContract } = useWriteContract();
 
writeContract(parameters);
 
export { contractAddress };

Custom parameters for secondary markets

If you are wanting to customize the default configuration parameters such as saleStart you can do that by passing in a salesConfig struct.

example.ts
import {
  useAccount,
  useChainId,
  usePublicClient,
  useWriteContract,
} from "wagmi";
import { createCreatorClient } from "@zoralabs/protocol-sdk";
 
// use wagmi hooks to get the chainId, publicClient, and account
const chainId = useChainId();
const publicClient = usePublicClient()!;
const { address } = useAccount();
 
const creatorClient = createCreatorClient({ chainId, publicClient });
 
const { parameters, contractAddress } = await creatorClient.create1155({
  // the contract will be created at a deterministic address
  contract: {
    // contract name
    name: "testContract",
    // contract metadata uri
    uri: "ipfs://DUMMY/contract.json",
  },
  token: {
    tokenMetadataURI: "ipfs://DUMMY/token.json",
    salesConfig: {
      type: "timed",
      erc20Name: "testToken", // If not provided, uses the contract name
      erc20Symbol: "TEST", // If not provided, extracts it from the name.
      saleStart: 0n, // If not provided, sets to 0
      marketCountdown: BigInt(24 * 60 * 60), // If not provided, sets to 24 hours
      minimumMarketEth: 2220000000000000n, // If not provided, sets to 200 mints worth of ETH
    },
  },
  // account to execute the transaction (the creator)
  account: address!,
});
 
const { writeContract } = useWriteContract();
 
writeContract(parameters);
 
export { contractAddress };

With the update to use the v2 sales config it introduces marketCountdown and minimumMarketEth in version 0.9.5 of the sdk.

Configuring the backing ERC20 Token Name and Symbol for the 1155 Secondary Market

When leveraging the secondary markets feature, a backing ERC20 token is created with a name and symbol for each minted 1155.
By default, the name is copied from the contract name, and the symbol is generated by converting the name into a 4 character symbol.
Alternatively these can be manually set by configuring the token.salesConfig.erc20Name and token.salesConfig.erc20Symbol properties correspondingly:

example.ts
import { createCreatorClient } from "@zoralabs/protocol-sdk";
import { publicClient, chainId, creatorAccount } from "./config";
 
const creatorClient = createCreatorClient({ chainId, publicClient });
 
const { parameters } = await creatorClient.create1155({
  contract: {
    name: "testContract",
    uri: "ipfs://DUMMY/contract.json",
  },
  token: {
    tokenMetadataURI: "ipfs://DUMMY/token.json",
    salesConfig: {
      // manually specifying the erc20 name and symbol
      erc20Name: "My Token Name", 
      erc20Symbol: "MTN", 
    },
  },
  account: creatorAccount,
});
 
// simulate the transaction
await publicClient.simulateContract(parameters);

Creating a token on an existing 1155 contract

To create a token on an existing 1155 contract, the function create1155OnExistingContract must be called with the 1155 contract address and the token creation parameters.

example.ts
import { createCreatorClient } from "@zoralabs/protocol-sdk";
import { publicClient, walletClient, chainId, creatorAccount } from "./config";
import { contractAddress } from "./createNewContract";
 
const creatorClient = createCreatorClient({ chainId, publicClient });
 
const { parameters } = await creatorClient.create1155OnExistingContract({
  // by providing a contract address, the token will be created on an existing contract
  // at that address
  contractAddress, 
  token: {
    // token metadata uri
    tokenMetadataURI: "ipfs://DUMMY/token.json",
  },
  // account to execute the transaction (the creator)
  account: creatorAccount,
});
 
// simulate the transaction
const { request } = await publicClient.simulateContract(parameters);
 
// execute the transaction
const hash = await walletClient.writeContract(request);
// wait for the response
await publicClient.waitForTransactionReceipt({ hash });

Setting a price per token

A price per token can be optionally set to earn eth additional on the primary sale when each token is minted, by setting token.salesConfig.pricePerToken.
If the pricePerToken is set to more than 0, there will be no creatorReward earned on the mint fee. If a pricePerToken is set to more than 0, then the token is setup with the ZoraCreatorFixedPriceSaleStrategy as its minter. This will also result in not being able to leverage the onchain secondary market feature for tokens minted using this minter.

example.ts
import {
  useAccount,
  useChainId,
  usePublicClient,
  useWriteContract,
} from "wagmi";
import { parseEther } from "viem";
import { createCreatorClient } from "@zoralabs/protocol-sdk";
 
// use wagmi hooks to get the chainId, publicClient, and account
const chainId = useChainId();
const publicClient = usePublicClient()!;
const { address } = useAccount();
 
const creatorClient = createCreatorClient({ chainId, publicClient });
 
const { parameters, contractAddress } = await creatorClient.create1155({
  // the contract will be created at a deterministic address
  contract: {
    // contract name
    name: "testContract",
    // contract metadata uri
    uri: "ipfs://DUMMY/contract.json",
  },
  token: {
    tokenMetadataURI: "ipfs://DUMMY/token.json",
    salesConfig: {
      // setting a price per token on the `salesConfig` will
      // result in the token being created with a fixed price in addition
      // to the mint fee.  In this case, creator rewards will not be earned
      // on the mint fee, the `ZoraCreatorFixedPriceSaleStrategy` is setup
      // as the minter for this token, and correspondingly the onchain
      // secondary market feature will NOT be used for tokens minted using
      // that minter.
      pricePerToken: parseEther("0.1"), 
    },
  },
  // account to execute the transaction (the creator)
  account: address!,
});
 
const { writeContract } = useWriteContract();
 
writeContract(parameters);
 
export { contractAddress };

Minting a token after creating

Sometimes it is desired to be able to mint a token right after creating one. This can be done with the function prepareMint that is returned from the creation functions. This function will prepare a transaction to mint a token on the token and/or contract that was created. Note that this transaction can only be executed after the token has been created onchain.

example.ts
import { createCreatorClient } from "@zoralabs/protocol-sdk";
import {
  publicClient,
  walletClient,
  chainId,
  creatorAccount,
  minterAccount,
} from "./config";
import { contractAddress } from "./createNewContract";
 
const creatorClient = createCreatorClient({ chainId, publicClient });
 
const {
  parameters: createParameters,
  prepareMint, 
} = await creatorClient.create1155OnExistingContract({
  // by providing a contract address, the token will be created on an existing contract
  // at that address
  contractAddress,
  token: {
    // token metadata uri
    tokenMetadataURI: "ipfs://DUMMY/token.json",
  },
  // account to execute the transaction (the creator)
  account: creatorAccount,
});
 
const { request } = await publicClient.simulateContract(createParameters);
 
// execute the transaction
const hash = await walletClient.writeContract(request);
// wait for the response
const createReceipt = await publicClient.waitForTransactionReceipt({ hash });
 
if (createReceipt.status !== "success") {
  throw new Error("create failed");
}
 
// the create function returns an async prepareMint function, which
// enables a mint call to be created on the token after it has been created.
// Note this can only be executed after the token has been brought onchain.
const { parameters: mintParams } = await prepareMint({
  quantityToMint: 2n,
  minterAccount,
});
 
// execute the mint transaction
const mintHash = await walletClient.writeContract(mintParams);
 
const mintReceipt = await publicClient.waitForTransactionReceipt({
  hash: mintHash,
});
 
if (mintReceipt.status !== "success") {
  throw new Error("mint failed");
}