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.
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
The following snippet shows the parameters for customizing the settings for the secondary market.
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: {
// Name of the erc20z token to create for the secondary sale. If not provided, uses the contract name
erc20Name: "testToken",
// Symbol of the erc20z token to create for the secondary sale. If not provided, extracts it from the name.
erc20Symbol: "TEST",
// Earliest time a token can be minted. If undefined or 0, then it can be minted immediately. Defaults to 0n.
saleStart: 0n,
// Market countdown, in seconds, that will start once the minimum mints for countdown is reached. Defaults to 24 hours.
marketCountdown: BigInt(24 * 60 * 60),
// Minimum quantity of mints that will trigger the countdown. Defaults to 1111n
minimumMintsForCountdown: 1111n,
},
},
// 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:
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.
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 additional ETH 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.
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.
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");
}