5/5
## Dissecting a GMX v2 Market Decrease Order Transaction This lesson delves into the specifics of closing a perpetual trading position on a GMX v2-style decentralized exchange using a market order. We will analyze the input parameters passed to the core `createOrder` function, providing a technical understanding of how a "Market Decrease" order is constructed on-chain. The analysis uses insights typically gained from inspecting transactions via tools like Tenderly. **Transaction Context: Multicall and Gas Payment** The specific transaction examined involves multiple internal calls orchestrated within a `multicall`. Before the primary order creation logic, a necessary preliminary step often occurs: paying for the anticipated execution gas fees. This is commonly handled by a function like `ExchangeRouter.sendWnt`, which transfers Wrapped Native Token (e.g., WETH on Arbitrum) to cover the costs associated with the keeper network executing the order later. **The `createOrder` Function Call** The central piece of this transaction is the call to `ExchangeRouter.createOrder`. This versatile function serves as the entry point for various actions, including market swaps, opening new perpetual positions, and, crucially for this analysis, closing existing positions. The specific behavior of `createOrder` is determined entirely by the input parameters provided within a structured object, often referred to as `params`. Our focus here is on the parameters required to initiate a market order that decreases (closes) an existing position. **Analyzing the `createOrder` Input Parameters (`params`)** Let's break down the key fields within the `params` struct passed to `createOrder` for a market decrease scenario, specifically closing a short position. ```json // Example structure of relevant inputs "params": { "addresses": { "receiver": "0x...", // User's wallet address receiving funds "cancellationReceiver": "0x00...00", // Address for refunds if cancelled "callbackContract": "0x00...00", // Optional contract for callbacks "uiFeeReceiver": "0xff...01", // Optional address for UI referral fees "market": "0x70d95587d40a2caf56bd97485ab3eeC10bee6336", // Market identifier "initialCollateralToken": "0xaf88d065e77c8cC2239327C5EDb3A432268e5831", // Current collateral token (USDC) "swapPath": [] // Empty for this closing order type }, "numbers": { "sizeDeltaUsd": "34192530496159612075846441500000", // Position size reduction (USD, 30 decimals) "initialCollateralDeltaAmount": "34220111", // Collateral withdrawal amount (USDC, 6 decimals) "triggerPrice": "0", // Not used for market orders "acceptablePrice": "3261237444595749", // Slippage protection price (relevant for execution) "executionFee": "85943861894800", // Pre-paid gas fee (wei) "callbackGasLimit": "0", "minOutputAmount": "0", // Often 0 for market closes unless complex swaps involved "orderType": 4, // Enum: MarketDecrease "decreasePositionSwapType": 0, // Enum: NoSwap // ... other number fields }, "flags": { "isLong": false, // Position being closed is short "shouldUnwrapNativeToken": false, // Whether to unwrap WETH to ETH on withdrawal "autoCancel": false }, "referralCode": "0x00...00" // Referral code, if any } ``` **Detailed Parameter Breakdown:** * **`params.addresses.market`**: This address (`0x70d...`) uniquely identifies the trading market. For instance, it could represent an ETH market where WETH is the long token, USDC is the short token, and the price feed tracks ETH/USD. * **`params.addresses.initialCollateralToken`**: This specifies the token (`0xaf8...`) currently held as collateral *for the position being closed*. In this example analysis, the address corresponds to USDC (USD Coin). * **Key Point:** Even if the user initially deposited WETH when *opening* the position, they might have configured that opening order to swap the collateral into USDC. Therefore, when submitting the *closing* order, `initialCollateralToken` must reflect the actual collateral asset held against the position at that moment, which is USDC in this case. Verification on a block explorer like Arbiscan confirms `0xaf8...` is USDC's contract address. * **`params.numbers.initialCollateralDeltaAmount`**: This value (`34220111`) represents the quantity of `initialCollateralToken` (USDC) to be withdrawn from the position's collateral. Since this order aims to close the entire position, this amount corresponds to the total collateral backing it. * **Token Decimals:** It's crucial to consider token decimals. USDC uses 6 decimals. Therefore, `34220111` equates to `34220111 / 10^6 = 34.220111` USDC. This value typically reflects the collateral amount remaining in the position. * **`params.numbers.orderType`**: This is an enumeration (enum) value indicating the order's nature. The value `4` corresponds to `MarketDecrease`, as defined in the relevant `Order` smart contract. This signifies the intent to decrease (in this case, fully close) the position at the prevailing market price as soon as possible. * **`params.flags.isLong`**: This boolean flag indicates the direction of the position being modified. Since the value is `false`, it confirms that the order pertains to closing a *short* position. For closing a long position, this would be `true`. * **`params.numbers.decreasePositionSwapType`**: This enum controls how assets are handled upon position closure. It determines if any automatic token swaps should occur with the withdrawn collateral or the resulting Profit and Loss (PnL). The common options, typically defined in the `Order` contract, are: * `0`: `NoSwap`: The collateral is withdrawn in its current form (`initialCollateralToken`, which is USDC here). PnL is paid out in the market's default PnL token for that position type (often the quote asset like USDC for shorts, or the base asset like WETH for longs). No swaps occur during the closing process. * `1`: `SwapPnlTokenToCollateralToken`: Any PnL generated is automatically swapped into the `initialCollateralToken` (USDC). * `2`: `SwapCollateralTokenToPnlToken`: The withdrawn collateral (`initialCollateralToken`) is automatically swapped into the PnL token. * **In this specific transaction, the value is `0` (`NoSwap`).** This means the user elected to receive their withdrawn collateral directly as USDC and any PnL in its native form, without performing swaps within the closing transaction itself. * **`params.numbers.acceptablePrice`**: Although a market order seeks immediate execution, this parameter provides slippage protection. It defines the worst acceptable execution price (e.g., the maximum price for closing a short, or the minimum price for closing a long). If the market price moves beyond this limit before execution, the order might revert or fail, depending on the protocol's implementation. * **`params.numbers.sizeDeltaUsd`**: Represents the decrease in position size, denominated in USD with high precision (often 30 decimals). For a full close, this matches the position's current size. **Key Concepts and Takeaways** * **Multi-Purpose Functions:** Smart contract functions like `createOrder` are often designed for multiple purposes, distinguished by their input parameters. * **State-Dependent Parameters:** When closing a position, parameters like `initialCollateralToken` depend on the *current state* of that specific position, which may differ from the initial deposit parameters if swaps occurred during opening. * **Enums for Clarity:** Enums like `OrderType` and `DecreasePositionSwapType` map human-readable concepts to numerical values for efficient on-chain processing. Understanding these mappings is crucial. * **Collateral and PnL Handling:** The `decreasePositionSwapType` offers flexibility in managing withdrawn funds, allowing users to choose between receiving assets directly or having them automatically swapped. * **Decimal Precision:** Always account for token decimals when interpreting on-chain amounts (`initialCollateralDeltaAmount`) and USD values (`sizeDeltaUsd`). By dissecting the input parameters for a `MarketDecrease` order, we gain a deeper understanding of how users interact with decentralized perpetuals platforms at a technical level, essential for both developers integrating with these protocols and advanced users debugging their transactions.
This lesson delves into the specifics of closing a perpetual trading position on a GMX v2-style decentralized exchange using a market order. We will analyze the input parameters passed to the core createOrder
function, providing a technical understanding of how a "Market Decrease" order is constructed on-chain. The analysis uses insights typically gained from inspecting transactions via tools like Tenderly.
Transaction Context: Multicall and Gas Payment
The specific transaction examined involves multiple internal calls orchestrated within a multicall
. Before the primary order creation logic, a necessary preliminary step often occurs: paying for the anticipated execution gas fees. This is commonly handled by a function like ExchangeRouter.sendWnt
, which transfers Wrapped Native Token (e.g., WETH on Arbitrum) to cover the costs associated with the keeper network executing the order later.
The createOrder
Function Call
The central piece of this transaction is the call to ExchangeRouter.createOrder
. This versatile function serves as the entry point for various actions, including market swaps, opening new perpetual positions, and, crucially for this analysis, closing existing positions. The specific behavior of createOrder
is determined entirely by the input parameters provided within a structured object, often referred to as params
. Our focus here is on the parameters required to initiate a market order that decreases (closes) an existing position.
Analyzing the createOrder
Input Parameters (params
)
Let's break down the key fields within the params
struct passed to createOrder
for a market decrease scenario, specifically closing a short position.
Detailed Parameter Breakdown:
params.addresses.market
: This address (0x70d...
) uniquely identifies the trading market. For instance, it could represent an ETH market where WETH is the long token, USDC is the short token, and the price feed tracks ETH/USD.
params.addresses.initialCollateralToken
: This specifies the token (0xaf8...
) currently held as collateral for the position being closed. In this example analysis, the address corresponds to USDC (USD Coin).
Key Point: Even if the user initially deposited WETH when opening the position, they might have configured that opening order to swap the collateral into USDC. Therefore, when submitting the closing order, initialCollateralToken
must reflect the actual collateral asset held against the position at that moment, which is USDC in this case. Verification on a block explorer like Arbiscan confirms 0xaf8...
is USDC's contract address.
params.numbers.initialCollateralDeltaAmount
: This value (34220111
) represents the quantity of initialCollateralToken
(USDC) to be withdrawn from the position's collateral. Since this order aims to close the entire position, this amount corresponds to the total collateral backing it.
Token Decimals: It's crucial to consider token decimals. USDC uses 6 decimals. Therefore, 34220111
equates to 34220111 / 10^6 = 34.220111
USDC. This value typically reflects the collateral amount remaining in the position.
params.numbers.orderType
: This is an enumeration (enum) value indicating the order's nature. The value 4
corresponds to MarketDecrease
, as defined in the relevant Order
smart contract. This signifies the intent to decrease (in this case, fully close) the position at the prevailing market price as soon as possible.
params.flags.isLong
: This boolean flag indicates the direction of the position being modified. Since the value is false
, it confirms that the order pertains to closing a short position. For closing a long position, this would be true
.
params.numbers.decreasePositionSwapType
: This enum controls how assets are handled upon position closure. It determines if any automatic token swaps should occur with the withdrawn collateral or the resulting Profit and Loss (PnL). The common options, typically defined in the Order
contract, are:
0
: NoSwap
: The collateral is withdrawn in its current form (initialCollateralToken
, which is USDC here). PnL is paid out in the market's default PnL token for that position type (often the quote asset like USDC for shorts, or the base asset like WETH for longs). No swaps occur during the closing process.
1
: SwapPnlTokenToCollateralToken
: Any PnL generated is automatically swapped into the initialCollateralToken
(USDC).
2
: SwapCollateralTokenToPnlToken
: The withdrawn collateral (initialCollateralToken
) is automatically swapped into the PnL token.
In this specific transaction, the value is 0
(NoSwap
). This means the user elected to receive their withdrawn collateral directly as USDC and any PnL in its native form, without performing swaps within the closing transaction itself.
params.numbers.acceptablePrice
: Although a market order seeks immediate execution, this parameter provides slippage protection. It defines the worst acceptable execution price (e.g., the maximum price for closing a short, or the minimum price for closing a long). If the market price moves beyond this limit before execution, the order might revert or fail, depending on the protocol's implementation.
params.numbers.sizeDeltaUsd
: Represents the decrease in position size, denominated in USD with high precision (often 30 decimals). For a full close, this matches the position's current size.
Key Concepts and Takeaways
Multi-Purpose Functions: Smart contract functions like createOrder
are often designed for multiple purposes, distinguished by their input parameters.
State-Dependent Parameters: When closing a position, parameters like initialCollateralToken
depend on the current state of that specific position, which may differ from the initial deposit parameters if swaps occurred during opening.
Enums for Clarity: Enums like OrderType
and DecreasePositionSwapType
map human-readable concepts to numerical values for efficient on-chain processing. Understanding these mappings is crucial.
Collateral and PnL Handling: The decreasePositionSwapType
offers flexibility in managing withdrawn funds, allowing users to choose between receiving assets directly or having them automatically swapped.
Decimal Precision: Always account for token decimals when interpreting on-chain amounts (initialCollateralDeltaAmount
) and USD values (sizeDeltaUsd
).
By dissecting the input parameters for a MarketDecrease
order, we gain a deeper understanding of how users interact with decentralized perpetuals platforms at a technical level, essential for both developers integrating with these protocols and advanced users debugging their transactions.
A technical breakdown to GMX v2 `createOrder` for Market Decrease - Examine the specific parameters passed to the GMX v2 `createOrder` function when closing a position via market order. Learn how Tenderly helps decode crucial inputs like collateral, order type, and swap preferences.
Previous lesson
Previous
Next lesson
Next
Give us feedback
Cyfrin Updraft has partnered with GMX to provide SSCD+ certifications vouchers to the first 25 students who demonstrate the completion of this course and are building on top of GMX. Join the GMX Discord server to redeem your coupon, or navigate to the docs to learn more!
Course Overview
About the course
Mechanics and contract architecture of the GMX protocol
Token pricing and fees
Liquidity: GM pools and GLV vaults
Math, funding rates, liquidation pricing, P&L calculations
Limit orders, take profit orders, stop loss, and stop market orders
Auto-cancel and auto-deleveraging
GLP, esGMX, GMX staking and delegation
DeFi Developer
$75,000 - $200,000 (avg. salary)
Smart Contract Engineer
$100,000 - $150,000 (avg. salary)
Web3 developer
$60,000 - $150,000 (avg. salary)
Web3 Developer Relations
$85,000 - $125,000 (avg. salary)
Smart Contract Auditor
$100,000 - $200,000 (avg. salary)
Security researcher
$49,999 - $120,000 (avg. salary)
Last updated on June 26, 2025
Duration: 8min
Duration: 1h 19min
Duration: 1h 24min
Duration: 16min
Duration: 11min
Duration: 11min
Duration: 6min
Course Overview
About the course
Mechanics and contract architecture of the GMX protocol
Token pricing and fees
Liquidity: GM pools and GLV vaults
Math, funding rates, liquidation pricing, P&L calculations
Limit orders, take profit orders, stop loss, and stop market orders
Auto-cancel and auto-deleveraging
GLP, esGMX, GMX staking and delegation
DeFi Developer
$75,000 - $200,000 (avg. salary)
Smart Contract Engineer
$100,000 - $150,000 (avg. salary)
Web3 developer
$60,000 - $150,000 (avg. salary)
Web3 Developer Relations
$85,000 - $125,000 (avg. salary)
Smart Contract Auditor
$100,000 - $200,000 (avg. salary)
Security researcher
$49,999 - $120,000 (avg. salary)
Last updated on June 26, 2025