Docs
SDK

How to Create a Perp Market

This guide shows you how to create a new perpetual futures market using the PerpCity SDK.

Basic Perp Creation

The simplest way to create a perp market:

import { createPerp } from '@strobelabs/perpcity-sdk'

const perpId = await createPerp(context, {
  startingPrice: 3000, // Initial price (e.g., $3000)
  beacon: '0x...'      // Your beacon/oracle address
})

console.log(`Created perp with ID: ${perpId}`)

This creates a perp with default settings for all parameters.

Custom Perp Configuration

To customize your perp's parameters, provide module addresses:

import { createPerp } from '@strobelabs/perpcity-sdk'

const perpId = await createPerp(context, {
  startingPrice: 3500,  // Initial price
  beacon: '0x...',      // Index oracle

  // Optional: Custom module addresses
  fees: '0x...',                  // Custom fee structure
  marginRatios: '0x...',          // Custom margin requirements
  lockupPeriod: '0x...',          // Custom lockup period
  sqrtPriceImpactLimit: '0x...'   // Custom price impact limits
})

Understanding Module Addresses

Each module controls a specific aspect of the perp market:

Fees Module

Controls trading fees and funding rates:

  • Taker fee (paid by traders opening positions)
  • Maker fee (earned by liquidity providers)
  • Funding rate parameters

Margin Ratios Module

Defines margin requirements:

  • Initial margin ratio (required to open a position)
  • Maintenance margin ratio (minimum to avoid liquidation)

Lockup Period Module

Sets the minimum time liquidity must stay locked:

  • Prevents liquidity sniping
  • Ensures market stability

Price Impact Limits Module

Limits how much a single trade can move the price:

  • Protects against market manipulation
  • Ensures fair pricing

If you don't provide module addresses in params, the SDK falls back to the module addresses in your deployment config. Module addresses must be provided in at least one of these locations.

Complete Example

Here's a complete example of creating a custom perp market:

import { PerpCityContext, createPerp } from '@strobelabs/perpcity-sdk'
import { createWalletClient, http } from 'viem'
import { base } from 'viem/chains'
import { privateKeyToAccount } from 'viem/accounts'

async function createCustomPerp() {
  // Setup wallet
  const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`)
  const walletClient = createWalletClient({
    account,
    chain: base,
    transport: http(process.env.RPC_URL)
  })

  // Initialize context
  const context = new PerpCityContext({
    walletClient,
    rpcUrl: process.env.RPC_URL!,
    deployments: {
      perpManager: process.env.PERP_MANAGER_ADDRESS as `0x${string}`,
      usdc: process.env.USDC_ADDRESS as `0x${string}`
    }
  })

  // Create perp
  const perpId = await createPerp(context, {
    startingPrice: 3000, // Initial price
    beacon: '0x...',     // Your beacon address

    // Custom modules (optional)
    fees: process.env.FEES_MODULE_ADDRESS as `0x${string}`,
    marginRatios: process.env.MARGIN_RATIOS_MODULE_ADDRESS as `0x${string}`,
    lockupPeriod: process.env.LOCKUP_PERIOD_MODULE_ADDRESS as `0x${string}`,
    sqrtPriceImpactLimit: process.env.PRICE_IMPACT_LIMITS_MODULE_ADDRESS as `0x${string}`
  })

  console.log(`Successfully created perp with ID: ${perpId}`)
  return perpId
}

createCustomPerp()

Verifying Perp Creation

After creating a perp, verify it was created successfully:

const perpData = await context.getPerpData(perpId)

console.log({
  id: perpData.id,
  mark: perpData.mark,        // Current mark price
  beacon: perpData.beacon,    // Oracle address
  tickSpacing: perpData.tickSpacing,
  bounds: perpData.bounds,
  fees: perpData.fees
})

Common Errors

Insufficient USDC Balance

Error: Insufficient USDC balance

Solution: Ensure your wallet has enough USDC for initial liquidity plus approval.

Invalid Beacon Address

Error: Invalid beacon address

Solution: Verify the beacon contract implements the required interface and is deployed on Base.

Module Address Mismatch

Error: Module not registered

Solution: Ensure all custom module addresses are registered with the PerpManager contract.

Next Steps

After creating a perp market: