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 balanceSolution: Ensure your wallet has enough USDC for initial liquidity plus approval.
Invalid Beacon Address
Error: Invalid beacon addressSolution: Verify the beacon contract implements the required interface and is deployed on Base.
Module Address Mismatch
Error: Module not registeredSolution: Ensure all custom module addresses are registered with the PerpManager contract.
Next Steps
After creating a perp market: