-
Notifications
You must be signed in to change notification settings - Fork 184
Description
[BUG] Coins SDK createCoinCall() returns 500 error on Base Sepolia
🐛 Bug Description
The Zora Coins SDK's createCoinCall() function returns a 500 Internal Server Error when attempting to create coins on Base Sepolia testnet (chain ID 84532). The error occurs during the SDK's internal API call to pre-compute the coin address.
📋 Environment
- SDK Version:
@zoralabs/[email protected] - Network: Base Sepolia (Chain ID 84532)
- Node.js: v24.1.0
- Package Manager: npm
🔄 Steps to Reproduce
- Install the SDK and dependencies:
npm install @zoralabs/coins-sdk viem dotenv- Set up Base Sepolia configuration:
import { setApiKey, createCoinCall } from "@zoralabs/coins-sdk";
import { baseSepolia } from "viem/chains";
setApiKey("your_api_key");
const args = {
creator: "0x...",
name: "Test Coin",
symbol: "TEST",
metadata: {
type: "RAW_URI",
uri: "https://...",
},
currency: "ETH",
chainId: 84532,
payoutRecipientOverride: "0x...",
platformReferrer: "0x...",
};
const callData = await createCoinCall(args);- Observe the error:
Error: Failed to create content calldata
API Response: 500 Internal Server Error
🔍 Investigation Results
Root Cause
The SDK's backend API (https://api-sdk.zora.engineering/create/content) fails when calling the coinAddress function on the ZoraFactory contract:
The contract function "coinAddress" returned no data ("0x").
Contract Call:
address: 0xaF88840cb637F2684A9E460316b1678AD6245e4a
function: coinAddress(address msgSender, string name, string symbol, bytes poolConfig, address platformReferrer, bytes32 coinSalt)
Discovery: Two Factory Contracts
We discovered that there are two different CoinFactory contracts on Base Sepolia:
| Factory | Address | Age | Transactions | Source |
|---|---|---|---|---|
| Older | 0x777777751622c0d3258f214F9DF38E35BF45baF3 |
~273 days | ~1,931 | Zora Documentation |
| Newer | 0xaF88840cb637F2684A9E460316b1678AD6245e4a |
~167 days | ~124 | @zoralabs/protocol-deployments |
The SDK's @zoralabs/protocol-deployments package points to the newer factory, while the Zora documentation shows the older factory.
Important: Both contracts have identical source code, and the API fails with BOTH addresses.
✅ Working Workaround
We successfully deployed coins by bypassing the SDK API and calling the factory contract directly:
Complete Working Code
import {
createMetadataBuilder,
createZoraUploaderForCreator
} from "@zoralabs/coins-sdk";
import {
encodeMultiCurvePoolConfig,
coinFactoryABI,
coinFactoryAddress
} from "@zoralabs/protocol-deployments";
import {
createWalletClient,
createPublicClient,
http,
parseUnits,
zeroAddress,
encodePacked,
keccak256
} from "viem";
import { baseSepolia } from "viem/chains";
import { privateKeyToAccount } from "viem/accounts";
// Step 1: Upload metadata (SDK works fine for this)
const uploadResult = await createMetadataBuilder()
.withName("Test Coin")
.withSymbol("TEST")
.withDescription("Test description")
.withImage(imageFile)
.upload(createZoraUploaderForCreator(address));
const metadataUri = uploadResult.url.replace('ipfs://', 'https://').replace(/^https:\/\/([^\/]+)/, 'https://$1.ipfs.w3s.link');
// Step 2: Generate pool config
const poolConfig = encodeMultiCurvePoolConfig({
currency: zeroAddress,
tickLower: [-250000],
tickUpper: [-195000],
numDiscoveryPositions: [11],
maxDiscoverySupplyShare: [parseUnits("0.05", 18)],
});
// Step 3: Call factory contract directly
const factoryAddress = coinFactoryAddress[baseSepolia.id];
const { request } = await publicClient.simulateContract({
address: factoryAddress,
abi: coinFactoryABI,
functionName: "deploy",
args: [
address, // payoutRecipient
[address], // owners
metadataUri, // uri
"Test Coin", // name
"TEST", // symbol
poolConfig, // poolConfig
address, // platformReferrer
zeroAddress, // postDeployHook
"0x", // postDeployHookData
keccak256(encodePacked(["string", "uint256"], ["test", BigInt(Date.now())])), // coinSalt
],
account: walletClient.account,
});
const hash = await walletClient.writeContract(request);
const receipt = await publicClient.waitForTransactionReceipt({ hash });Verification
We successfully deployed 2 test coins using this workaround:
-
Using Newer Factory (
0xaF88840...):- Coin:
0xd64b0ed9d13d4216f70b58e9b7b037f0692de9a7 - TX:
0x7831a9f8cecc74fe4ca271f4384f679afb865d1e61bb9249e95cc591bf9b5425 - Gas: 2,181,832
- ✅ Success
- Coin:
-
Using Older Factory (
0x777777...):- Coin:
0x7cbe31f824f3e387c7ed4f75b37999d86372aeba - TX:
0x8ac9152745a01e590db6bdc27b3c7dc018c7cbffc2288d5347f8c3d115bb6eb5 - Gas: 2,181,832
- ✅ Success
- Coin:
❓ Questions for Zora Team
-
API Error: What is causing the 500 error when the backend API calls
coinAddress? Is this a known issue? -
Factory Selection: Which factory should developers use:
- The older factory (
0x777777...) referenced in documentation? - The newer factory (
0xaF8884...) from@zoralabs/protocol-deployments?
- The older factory (
-
Timeline: When will the SDK API be fixed for Base Sepolia?
-
Documentation: Should the documentation be updated to:
- Reference the correct factory address?
- Include this workaround until the API is fixed?
- Explain the difference between the two factories?
-
Mainnet: Does this issue affect Base mainnet (chain ID 8453) as well?
💡 Suggested Solutions
Short-term
- Add the workaround to the official documentation
- Update error messages to suggest direct contract calls
- Add a
createCoinDirect()helper function that bypasses the API
Long-term
- Fix the backend API's
coinAddresscall - Clarify which factory is the canonical one
- Add better error handling and fallbacks in the SDK
📎 Additional Context
- The metadata upload functionality works perfectly
- Only the coin deployment API is affected
- Direct contract calls work flawlessly with both factories
- Same gas costs regardless of factory used
Environment Details:
- OS: macOS 14
- Node: v24.1.0
- npm: 10.x
- Wallet: Metamask/Private Key
- Testnet: Base Sepolia (84532)
Impact: 🔴 High - Blocks all coin deployments on Base Sepolia using the SDK
Workaround Available: ✅ Yes - Direct contract calls work perfectly