For the complete documentation index, see llms.txt. This page is also available as Markdown.
HIP-3 deployer actions
The API for deploying and operating builder-deployed perpetual dexs involves the following L1 action:
// IMPORTANT: All lists of tuples should be lexographically sorted before signingtypePerpDeployAction=|{type:"perpDeploy";registerAsset2:RegisterAsset2;}|{type:"perpDeploy";registerAsset:RegisterAsset;}|{type:"perpDeploy";setOracle:SetOracle;}|{type:"perpDeploy";setFundingMultipliers:SetFundingMultipliers;}|{type:"perpDeploy";setFundingInterestRates:SetFundingInterestRates;}|{type:"perpDeploy";haltTrading:{coin:string;isHalted:boolean};}|{type:"perpDeploy";setMarginTableIds:SetMarginTableIds;}|{type:"perpDeploy";setFeeRecipient:{dex:string;feeRecipient:address};}|{type:"perpDeploy";setOpenInterestCaps:SetOpenInterestCaps;}|{type:"perpDeploy";setSubDeployers:{dex:string;subDeployers:Array<SubDeployerInput>};}|{type:"perpDeploy";setMarginModes:SetMarginModes;}|{type:"perpDeploy";setDeployerFees:SetDeployerFees;}|{type:"perpDeploy";setPerpAnnotation:SetPerpAnnotation;}|{type:"perpDeploy";disableDex:string;};
For the following examples, feeScale is the scale field in SetDeployerFees. Assume a positive normal user fee of 1 unit and non-aligned collateral (x = y = 1). userFeeToProtocol and userFeeToDeployer are the resulting fee units charged to the user.
Builder-deployed perp markets are subject to two types of open interest caps: notional (sum of absolute position size times mark price) and size (sum of absolute position sizes).
Size-denominated open interest caps are only enforced per-asset. Size-denominated open interest caps are currently a constant 1B per asset, so a reasonable default would be to set szDecimals such that the minimal size increment is $1-10 at the initial mark price.
/**
* RegisterAsset2 can be called to initialize a new dex and register an asset at the same time.
* If schema is not provided, then RegisterAsset can be called multiple times to register additional assets
* for the provided dex.
* @param maxGas - Max gas in native token wei. If not provided, then uses current deploy auction price.
* If the max gas is 0, then a reserve deployment will be used.
* A reserve deployment allows deployment at the current price of the gas auction, even if it has ended.
* Currently, 7 + 0.2 * n_auction_deployments reserve deployments are allowed.
* IMPORTANT: A reserve deployment will be used regardless of whether the auction has completed, so deployers should query the auction status first.
* @param assetRequest - Contains new asset listing parameters. See RegisterAssetRequest2 below for details.
* @param dex - Name of the perp dex (2-4 lowercase characters)
* @param schema - Contains new perp dex parameters. See PerpDexSchemaInput below for details.
*/
type RegisterAsset2 = {
maxGas?: number;
assetRequest: RegisterAssetRequest2;
dex: string;
schema?: PerpDexSchemaInput;
};
// Same as RegisterAsset2 but uses RegisterAssetRequest
type RegisterAsset = {
maxGas?: number;
assetRequest: RegisterAssetRequest;
dex: string;
schema?: PerpDexSchemaInput;
};
type RegisterAssetRequest2 = {
coin: string;
szDecimals: number;
oraclePx: string;
marginTableId: number;
marginMode: "strictIsolated" | "noCross" | "normal"; // strictIsolated does not allow withdrawing of isolated margin from open positions
};
type RegisterAssetRequest = {
coin: string;
szDecimals: number;
oraclePx: string;
marginTableId: number;
onlyIsolated: boolean;
};
/**
* The markPxs outer list can be length 0, 1, or 2. The median of these inputs
* along with the local mark price (median(best bid, best ask, last trade price))
* is used as the new mark price update.
*
* SetOracle can be called multiple times but there must be at least 2.5 seconds between calls.
*
* Stale mark prices will be updated to the local mark price after 10 seconds of no updates.
* This fallback counts as an update for purposes of the maximal update frequency.
* This fallback behavior should not be relied upon. Deployers are expected to call setOracle every 3 seconds even with no changes.
*
* All prices are clamped to 10x the start of day value.
* markPx moves are clamped to 1% from previous markPx.
* markPx cannot be updated such that open interest would be 10x the open interest cap.
* @param dex - Name of the perp dex
* @param oraclePxs - A list (sorted by key) of asset and oracle prices.
* @param markPxs - An outer list of inner lists (inner list sorted by key) of asset and mark prices.
* @param externalPerpPxs - A list (sorted by key) of asset and external prices which prevent sudden mark price deviations.
* Ideally externally determined by deployer, but could fall back to an EMA of recent mark prices.
* Must include all assets.
*/
type SetOracle = {
dex: string;
oraclePxs: Array<[string, string]>;
markPxs: Array<Array<[string, string]>>;
externalPerpPxs: Array<[string, string]>;
};
/**
* @param fullName - Full name of the perp dex
* @param collateralToken - Collateral token index
* @param oracleUpdater - User to update oracles. If not provided, then deployer is assumed to be oracle updater.
*/
type PerpDexSchemaInput = {
fullName: string;
collateralToken: int;
oracleUpdater?: string;
};
/**
* A sorted list of asset and funding multiplier.
* Multipliers must be between 0 and 10 and are used to scale the funding rate.
*/
type SetFundingMultipliers = Array<[string, string]>;
/**
* A sorted list of asset and 8 hour interest rate.
* Interest rates must be between -0.01 and 0.01 and are used as the interest rate
* component in the funding calculation.
*/
type SetFundingInterestRates = Array<[string, string]>;
/**
* A sorted of asset and margin table ids.
* Margin table ids must be non-zero.
*/
type SetMarginTableIds = Array<[string, number]>;
/**
* Inserts margin table to dex
*/
type InsertMarginTable = {
dex: string;
marginTable: RawMarginTable;
};
/**
* marginTiers must be sorted in order of increasing lower bound and decreasing maxLeverage
* marginTiers has a maximum length of 3.
*/
type RawMarginTable = {
description: string;
marginTiers: Array<RawMarginTier>;
};
/**
* lowerBound is a position notional value above which the leverage is constrained by maxLeverage
*/
type RawMarginTier = {
lowerBound: int;
maxLeverage: MaxLeverage;
};
/**
* Max leverage is in the range [1, 50]
*/
type MaxLeverage = number;
/**
* A sorted list of asset and open interest cap notionals.
* Open interest caps must be at least the maximum of 1_000_000 (1 size unit of collateral asset) or half of the current open interest.
*/
type SetOpenInterestCaps = Array<[string, number]>;
/**
* A modification to sub-deployer permissions
*/
type SubDeployerInput = {
variant: string; // corresponds to a variant of PerpDeployAction. For example, "haltTrading" or "setOracle"
user: String;
allowed: boolean; // add or remove the subDeployer from the authorized set for the action variant
};
// A sorted list of (coin, marginMode). See RegisterAssetRequest2 for margin mode definitions.
type SetMarginModes = Array<[string, "strictIsolated" | "noCross"]>;
// Let the user normal rate be `x`. Let the user rate be `y` after accounting for aligned quote collateral.
// In other words, `x = y` for non-aligned collateral.
// User pays or receives rebate `P + D` where `P` goes to protocol and `D` goes to deployer.
// If `x > 0` and `scale < 1`, `P = y` and `D = scale * x`
// If `x > 0` and `scale > 1`, `P = y * scale` and `D = x * scale`
// If `x < 0` and `scale < 1`, `P = y / (1 + scale)` and `D = y * scale / (1 + scale)`
// If `x < 0` and `scale > 1`, `P = y / 2` and `D = y / 2`
// On Mainnet, rate limited to one change per 30 days.
// Note that there are currently no aligned quote assets on mainnet.
type SetDeployerFees = Array<
[
string,
{
scale: string; // Decimal string in [0.0, 3.0], or [0.0, 10.0) when growthMode is true
growthMode: boolean;
},
]
>;
// category <= 15 characters
// description <= 400 characters
// displayName <= 9 characters
// <= 2 keywords, each keyword <= 10 characters
type SetPerpAnnotation = {
coin: string;
category: string;
description: string;
displayName: string | null;
keywords: Array<string>;
};