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.uri
should 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.