Skip to content

Actions Reference

Every 1CT intent names one action. The action determines three things: the EIP-712 type name you sign under, the ABI layout of actionData, and the permission bit required.

Action list

#ActionDescriptionactionData ABI types
0MARKET_OPENOpen at marketaddress,bool,address,address,uint96,uint128,uint128,uint128,uint128,uint24,uint96
1MARKET_CLOSEClose fullybytes32,uint24
2LIMIT_OPENPlace a limit ordersame as MARKET_OPEN
3LIMIT_CANCELCancel a limit orderbytes32
4LIMIT_UPDATE_TP_SLChange a limit order's TP/SLbytes32,uint128,uint128
5ADD_MARGINAdd marginbytes32,address,uint96
6REMOVE_MARGINRemove marginbytes32,uint96
7UPDATE_TP_SLChange a position's TP/SLbytes32,uint128,uint128
8BATCH_MARKET_CLOSEClose several positionsbytes32[],uint24
9PARTIAL_CLOSEClose part of a positionbytes32,uint128,uint24
10CANCEL_DECREASE_ORDERCancel a TP/SL orderbytes32
11BATCH_CREATE_DECREASE_ORDERSCreate TP/SL ordersbytes32,(uint8,uint128,uint128,uint24)[]
12BATCH_UPDATE_DECREASE_ORDERSUpdate TP/SL orders(bytes32,uint128,uint128,uint24)[]
13CANCEL_ALL_DECREASE_ORDERSCancel every TP/SL order on a positionbytes32

The listed ABI types are the parameters — the encoding also prepends trader, then strips it. See Building actionData; getting this wrong is the single most common 1CT integration bug.

Parameters

Opening — actions 0 and 2

PositionFieldTypeNotes
0pairBaseaddressMarket identifier
1isLongbool
2tokenInaddressERC-20 only, no native MON
3lvTokenaddressMust match tokenInsee the table
4amountInuint96tokenIn decimals, margin plus open fee
5qtyuint128Base asset, 1e10
6priceuint1281e18 — worst acceptable price (market) or limit price (limit)
7stopLossuint1281e18, 0 to disable
8takeProfituint1281e18, 0 to disable
9brokeruint24Referral id. 0 credits the default broker — see Brokers & Referrals
10extraFeeuint96Optional surcharge in tokenIn, 0 if unused

WARNING

extraFee is part of actionData for 1CT opens, where the onchain path takes it as a separate argument. There are 11 values, not 10.

Both work exactly as they do onchain: the fee share costs the trader nothing, extraFee is charged on top and paid to your broker's receiver. On the gasless path the trader's allowance to the Diamond must cover amountIn + extraFee + antiDdosFee when the execution fee is charged in the same token.

Closing — actions 1, 8, 9

ActionValues
MARKET_CLOSE[positionHash, broker]
BATCH_MARKET_CLOSE[[hashA, hashB, …], broker]
PARTIAL_CLOSE[positionHash, closeQty, broker]closeQty at 1e10

Margin — actions 5, 6

ActionValues
ADD_MARGIN[positionHash, tokenIn, amount]amount in tokenIn decimals
REMOVE_MARGIN[positionHash, lvAmount]lvAmount in lvToken decimals

TP/SL — actions 4, 7, 10, 11, 12, 13

ActionValues
LIMIT_UPDATE_TP_SL[orderHash, takeProfit, stopLoss]
UPDATE_TP_SL[positionHash, takeProfit, stopLoss]
CANCEL_DECREASE_ORDER[orderHash] — one order
CANCEL_ALL_DECREASE_ORDERS[positionHash] — every order on the position
BATCH_CREATE_DECREASE_ORDERS[positionHash, DecreaseOrderInput[]]
BATCH_UPDATE_DECREASE_ORDERS[DecreaseOrderUpdateInput[]]
DecreaseOrderInput        = (kind, triggerPrice, closeQty, broker)   // kind: 0 = TP, 1 = SL
DecreaseOrderUpdateInput  = (orderHash, triggerPrice, closeQty, broker)

Actions 10 and 13 take different hashes

Both encode as a single bytes32, so a swapped argument produces a perfectly valid signature and a well-formed actionData — it fails onchain, not at submission. CANCEL_DECREASE_ORDER (10) takes an orderHash; CANCEL_ALL_DECREASE_ORDERS (13) takes a positionHash.

The two failures do not even look alike: action 13 given an orderHash reverts NonexistentTrade, while action 10 given a positionHash reverts Error("TradingPortalFacet: not order owner") — a string revert, so a handler that only decodes custom errors will report it as Unknown error.

CANCEL_ALL_DECREASE_ORDERS clears every decrease order attached to the position — take-profit legs and the stop-loss alike — and emits one DecreaseOrderCancelled per order removed. The position itself is untouched. On a position that exists but has no orders it succeeds and does nothing; on a position that no longer exists it fails with NonexistentTrade, so cancelling after a full close is an error, not a no-op.

Behaviour matches the onchain path — both kinds may be partial, and there may be several of each up to the per-position cap. See TP/SL Orders.

Referrals

Every fee-charging action carries a broker id, and the two opens additionally accept extraFee:

ActionbrokerextraFee
MARKET_OPEN (0), LIMIT_OPEN (2)yesyes
MARKET_CLOSE (1), BATCH_MARKET_CLOSE (8), PARTIAL_CLOSE (9)yes
BATCH_CREATE_DECREASE_ORDERS (11), BATCH_UPDATE_DECREASE_ORDERS (12)per order
Actions 3–7, 10, 13

Actions 3–7, 10 and 13 charge no fee, so there is nothing to share. Note that the close broker is independent of the open broker — a broker integration has to pass its id on opens, closes, and every TP/SL order. See Brokers & Referrals.

EIP-712 type names

The primaryType is what distinguishes one action from another in a signature. The field list is identical for all of them.

ActionprimaryType
0OneClickMarketOpen
1OneClickMarketClose
2OneClickLimitOpen
3OneClickLimitCancel
4OneClickLimitUpdateTpSl
5OneClickAddMargin
6OneClickRemoveMargin
7OneClickUpdateTpSl
8OneClickBatchMarketClose
9OneClickPartialClose
10OneClickCancelDecreaseOrder
11OneClickBatchCreateDecreaseOrders
12OneClickBatchUpdateDecreaseOrders
13OneClickCancelAllDecreaseOrders

Permission bits

Bit number equals action value.

bitActionbitAction
0MARKET_OPEN7UPDATE_TP_SL
1MARKET_CLOSE8BATCH_MARKET_CLOSE
2LIMIT_OPEN9PARTIAL_CLOSE
3LIMIT_CANCEL10CANCEL_DECREASE_ORDER
4LIMIT_UPDATE_TP_SL11BATCH_CREATE_DECREASE_ORDERS
5ADD_MARGIN12BATCH_UPDATE_DECREASE_ORDERS
6REMOVE_MARGIN13CANCEL_ALL_DECREASE_ORDERS
ts
const canTrade = (1n << 0n) | (1n << 1n) | (1n << 9n)  // open, close, partial close

Action numbers are appended over time

An agent authorized with an explicit bitmask holds exactly the bits it was granted. When a new action is added, existing agents do not gain it — they keep returning skipReason = INVALID for that action until the trader calls updateAgentPermissions. Agents authorized with the type(uint256).max wildcard are unaffected and pick up new actions automatically.

Actions that require an indexed position

Some actions need the position to exist in the relayer's database so it can resolve which oracle feeds to fetch. These are:

MARKET_CLOSE · BATCH_MARKET_CLOSE · PARTIAL_CLOSE · ADD_MARGIN · REMOVE_MARGIN · BATCH_CREATE_DECREASE_ORDERS

Submitting one of these for a position that was opened moments ago can return 404 Position not found — the indexer has not caught up yet. Retry with backoff, or wait for the position to appear in getPositionsV4 first. This is the only submission failure that is not a 400.

Being addressed by positionHash is not the test — needing the relayer to look the position up is. The opens (0 and 2) consume oracle data too, but they carry pairBase and lvToken in actionData, so their feeds resolve without any lookup and they can never return this error.

The following actions only read or remove stored order state, so they need no feeds at all and are never subject to this, even though some of them take a positionHash:

LIMIT_CANCEL · LIMIT_UPDATE_TP_SL · UPDATE_TP_SL · CANCEL_DECREASE_ORDER · BATCH_UPDATE_DECREASE_ORDERS · CANCEL_ALL_DECREASE_ORDERS

In particular CANCEL_ALL_DECREASE_ORDERS (13) is positionHash-addressed but exempt: you can clear a freshly-opened position's orders without waiting for the indexer.

Next: Signing Intents.

Trading perpetuals involves risk. Nothing here is financial advice.