Skip to content

Coins SDK createCoinCall() returns 500 error on Base Sepolia #541

@estmcmxci

Description

@estmcmxci

[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

  1. Install the SDK and dependencies:
npm install @zoralabs/coins-sdk viem dotenv
  1. 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);
  1. 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:

  1. Using Newer Factory (0xaF88840...):

  2. Using Older Factory (0x777777...):

❓ Questions for Zora Team

  1. API Error: What is causing the 500 error when the backend API calls coinAddress? Is this a known issue?

  2. Factory Selection: Which factory should developers use:

    • The older factory (0x777777...) referenced in documentation?
    • The newer factory (0xaF8884...) from @zoralabs/protocol-deployments?
  3. Timeline: When will the SDK API be fixed for Base Sepolia?

  4. 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?
  5. Mainnet: Does this issue affect Base mainnet (chain ID 8453) as well?

💡 Suggested Solutions

Short-term

  1. Add the workaround to the official documentation
  2. Update error messages to suggest direct contract calls
  3. Add a createCoinDirect() helper function that bypasses the API

Long-term

  1. Fix the backend API's coinAddress call
  2. Clarify which factory is the canonical one
  3. 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions