Creating Coins
The Coins SDK provides functions to create new coins on the Zora protocol.
Overview
Creating a coin involves generating calldata through the SDK and sending a transaction that deploys the ERC20 with protocol integrations. Use the high‑level createCoin helper to send and wait for the tx, or the low‑level createCoinCall to get raw to/data/value for your own tx flow.
Parameters
import { Address } from "viem";
import { CreateConstants, ContentCoinCurrency, StartingMarketCap } from "@zoralabs/coins-sdk";
type MetadataType = {
type: "RAW_URI";
uri: string; // e.g., an IPFS URI
};
type CreateCoinArgs = {
creator: Address; // Creator address
name: string; // Coin name (e.g., "My Awesome Coin")
symbol: string; // Ticker (e.g., "MAC")
metadata: MetadataType; // Metadata descriptor
currency: ContentCoinCurrency; // CREATOR_COIN | CREATOR_COIN_OR_ZORA | ZORA | ETH
chainId?: number; // Chain ID to deploy on (defaults to Base mainnet `8453`)
startingMarketCap?: StartingMarketCap; // LOW | HIGH (defaults to LOW)
platformReferrer?: Address; // Optional referral address
additionalOwners?: Address[];
payoutRecipientOverride?: Address;
skipMetadataValidation?: boolean; // Skip URI validation (not recommended)
};Metadata
- The
metadata.urishould point to valid metadata as described in the Metadata section. - You can use the Metadata Builder to upload assets and produce a URI. Example:
import { Address } from "viem";
import { createMetadataBuilder, createZoraUploaderForCreator } from "@zoralabs/coins-sdk";
const creatorAddress = "0xYourAddress" as Address;
const { createMetadataParameters } = await createMetadataBuilder()
.withName("Test ZORA Coin")
.withSymbol("TZC")
.withDescription("Test Description")
.withImage(new File(["FILE"], "test.png", { type: "image/png" }))
.upload(createZoraUploaderForCreator(creatorAddress));
// createMetadataParameters can be used to spread in the createCoin call to handle metadata (name, symbol, and uri)Currency
enum ContentCoinCurrencies {
CREATOR_COIN = "CREATOR_COIN",
CREATOR_COIN_OR_ZORA = "CREATOR_COIN_OR_ZORA", // If no creator coin is deployed, use ZORA
ZORA = "ZORA",
ETH = "ETH",
}Choose the denomination for the coin’s market. Note that ZORA, CREATOR_COIN, and CREATOR_COIN_OR_ZORA are not available on Base Sepolia.
Starting Market Cap
Starting market cap is the initial liquidity/market configuration for the coin. By default and for most coins on Zora, the starting market cap is LOW.
If the coin is from a known creator or brand it is recommended to use HIGH to prevent sniping in the initial market by setting a higher initial purchase price.
Chain ID
Provide the exact chainId you intend to deploy on (e.g., Base mainnet 8453).
Usage
High‑level: send transaction and wait for receipt
import { createCoin, CreateConstants, ContentCoinCurrency } from "@zoralabs/coins-sdk";
import { Hex, Address, createWalletClient, createPublicClient, http } from "viem";
import { base } from "viem/chains";
const publicClient = createPublicClient({
chain: base,
transport: http("<RPC_URL>"),
});
const walletClient = createWalletClient({
account: "0x<YOUR_ACCOUNT>" as Hex,
chain: base,
transport: http("<RPC_URL>"),
});
const args = {
creator: "0xYourAddress" as Address,
name: "My Awesome Coin",
symbol: "MAC",
metadata: { type: "RAW_URI" as const, uri: "ipfs://bafy..." },
currency: CreateConstants.ContentCoinCurrencies.ZORA,
chainId: base.id,
startingMarketCap: CreateConstants.StartingMarketCaps.LOW,
platformReferrerAddress: "0xOptionalReferrer" as Address,
};
const result = await createCoin({
call: args,
walletClient,
publicClient,
options: {
// account: optional override
// skipValidateTransaction: false by default
},
});
console.log("Transaction hash:", result.hash);
console.log("Coin address:", result.address);
console.log("Deployment details:", result.deployment);Low‑level: integrate with WAGMI using a raw transaction
createCoinCall returns { to, data, value }, which can be passed to your tx‑sending flow (e.g., WAGMI useSendTransaction).
import * as React from "react";
import { createCoinCall, CreateConstants } from "@zoralabs/coins-sdk";
import { Address } from "viem";
import { useSendTransaction } from "wagmi";
import { base } from "viem/chains";
const args = {
creator: "0xYourAddress" as Address,
name: "My Awesome Coin",
symbol: "MAC",
metadata: { type: "RAW_URI" as const, uri: "ipfs://bafy..." },
currency: CreateConstants.ContentCoinCurrencies.ZORA,
chainId: base.id,
startingMarketCap: CreateConstants.StartingMarketCaps.LOW,
};
const txCalls = await createCoinCall(args);
function CreateCoinButton() {
const { sendTransaction, status } = useSendTransaction();
return (
<button
disabled={status === "pending"}
onClick={() => sendTransaction({ to: txCalls[0].to, data: txCalls[0].data, value: txCalls[0].value })}
>
{status === "pending" ? "Creating..." : "Create Coin"}
</button>
);
}Metadata Validation
By default, the SDK validates metadata.uri content. You can disable with skipMetadataValidation: true if you already ensured validity.
import { validateMetadataURIContent } from "@zoralabs/coins-sdk";
// Optional manual validation
await validateMetadataURIContent("ipfs://...");Getting Coin Address from Transaction Receipt
Once the transaction is confirmed, extract the deployed coin address from logs using getCoinCreateFromLogs.
This is already done for you in the high‑level createCoin function.
import { getCoinCreateFromLogs } from "@zoralabs/coins-sdk";
const coinDeployment = getCoinCreateFromLogs(receipt);
console.log("Deployed coin address:", coinDeployment?.coin);More Information
See Creating a Coin and Contract Architecture for protocol‑level details.
