GMX Perpetual Hedging Reactor

General Overview

This contract's purpose is to hedge a delta specified by the liquidity pool using GMX long or short perpetual contracts ( The contract is responsible for maintaining the margin collateral at a specified health factor so as to ensure that the vault does not make a loss as a result of a margin account liquidation, other kinds of losses are possible.

All functions assume that the LiquidityPool has the collateral to service its needs.

This contract has identical functionality to PerpHedgingReactor.sol and will be used in tandem with it, allowing the liquidity pool to choose the option that provides the lowest fees (including slippage) at the time.

Oracle use

The pool uses a Chainlink Price feed Oracle for internal price calculations. GMX uses a combination of chainlink price feeds and its own keeper system which fetches prices from major CEXs. (

Function by Function

function sweepFunds(uint256 _amount, address _receiver) external

The contract must have an ETH balance to pay the GMX Keeper fees on each transaction. This access-controlled function allows the withdrawal of that ETH by a governor.

function hedgeDelta(int256 _delta) external

This function is responsible for hedging off a specified amount of delta using perpetual positions. The reactor must hedge off the delta that the pool passes in, so if the pool passes -1 then the reactor should hedge 1.

The function calls _changePosition() which checks the reactor's current state to determine whether any longs or shorts are already open, then contains logic to either increase or decrease those longs/shorts. Because GMX charges a borrow fee instead of a funding rate, and also treats longs and shorts on the same asset as completely separate, it is possible to be net delta neutral but be paying borrow fees on equally large long and short at the same time. _changePosition() ensures all longs are closed before opening shorts and vice-versa to stop this from happening.

Within _changePosition() are internal function calls to calculate parameters needed for the GMX position increase/decrease function calls, including calculations for how much collateral to add to a position (if increasing its size) or remove from a position (if decreasing its size).

withdraw(uint _amount) external

Withdraws any leftover collateral asset from the reactor back to the liquidity pool. Only callable by the liquidity pool.

sync() external

The contract uses its own internalDelta state variable to keep track of its open positions on GMX. Due to the architecture in _changePosition() it is assumed that if internalDelta is positive, the contract has no short positions open and vice-versa. internalDelta is updated through the callback function call gmxPositionCallback() made by a GMX keeper upon execution or rejection of the position request made by this reactor. However, in the event of a liquidation of our position no such call is made and internalDelta will become out of sync. This function will manually check all positions open by the reactor and re-sync the internalDelta value.

update() external

The function's goal is to rebalance the collateral held in open positions to make sure its health factor is at the desired healthFactor. It determines the desired collateral for the position. If the collateral is too much then remove some collateral and send it back to the liquidityPool. If the collateral is too little then get some funds from the liquidtyPool and update the margin. This function can only be called by a keeper.

getDelta() external view

This function gets the internalDelta of the reactor. Which is assumed to always hold the live delta value of the reactor.

getPoolDenominatedValue() external view

This function should return the value of the pool denominated in e18 decimals. It gets the collateral holdings of the margin account and the profit/loss of the position and returns the sum.

function checkVaultHealth() public view

Checks the health of the margin account and returns the health factor, collateral needed to bring health factor back to target (denominated in collateralAsset decimals), and the position array as given by the GMX Reader contract.

function executeIncreasePosition(bytes32 _positionKey) external

Allows us to force the execution of a position increase request made by a hedgeDelta() call if a GMX keeper has not done so within 3 minutes. Read more here

function executeDecreasePosition(bytes32 _positionKey) external

Allows us to force the execution of a position decrease request made by a hedgeDelta() call if a GMX keeper has not done so within 3 minutes. Read more here

function gmxPositionCallback(bytes32 positionKey, bool isExecuted, bool isIncrease) external

Callback function made by the GMX position router upon execution of rejection of the reactor's position request. Contains logic to handle updating state depending on whether the position was executed or not. Only callable by the GMX position router.

Last updated