πLimitOrderManager contracts
The `LimitOrderManager` is a critical component of the f(x) Protocol that enables users to create and execute limit orders for position management. This system allows traders to:
Open new positions when market conditions meet specific price criteria
Close existing positions at predetermined price levels
Set up stop-loss and take-profit orders for risk management
Execute complex trading strategies programmatically
Interacting with LimitOrderManager
To interact with LimitOrderManager, send a contract call to its address.
Key Functions
fillOrder(order, signature, makingAmount, takingAmount)
Executes a limit order by filling it with the specified amounts. (taker's operation)
cancelOrder(order)
Cancels an existing order (only callable by the order maker).
getOrderDetails(order)
Returns the order details (including making/taking tokens and amounts) for an order.
getExecution(orderHash)
Returns the current execution status of an order.
getOrderHash(order)
Calculates and returns the unique hash for a given order. This hash is used as the identifier for tracking order execution status.
increaseNonce()
Increments the caller's nonce, effectively invalidating all previously signed orders with the old nonce. Useful for batch cancelling multiple orders. (Basically, it means cancelAll
)
Key Concepts
Order Structure
The Order
struct contains the following key fields:
struct Order {
address maker; // Order creator
address pool; // Target pool address
uint256 positionId; // Position ID (0 for new positions)
bool positionSide; // true = long, false = short
bool orderType; // false = limit order, true = stop order
// orderType
// for limit order (orderType = true)
// orderSide = true: open order, order can be filled only oracle price is <= triggerPrice
// orderSide = false: close order, order can be filled only oracle price is >= triggerPrice
// stop order (orderType = false)
// always close order
// orderSide = true: take profit order, order can be filled only oracle price is >= triggerPrice
// orderSide = false: stop loss order, order can be filled only oracle price is <= triggerPrice
bool orderType;
bool allowPartialFill; // Allow partial execution
uint256 triggerPrice; // Price trigger condition
int256 fxUSDDelta; // fxUSD amount change
int256 collDelta; // Collateral amount change
int256 debtDelta; // Debt amount change
uint256 nonce; // Maker's nonce for batch cancellation
bytes32 salt; // Unique order identifier
uint256 deadline; // Order expiration timestamp
}
Pool Address: f(x) pool addresses, for example
WBTCLong :
0xAB709e26Fa6B0A30c119D8c55B887DeD24952473
wstETHLong:
0x6Ecfa38FeE8a5277B91eFdA204c235814F0122E8
WBTCShort:
0xA0cC8162c523998856D59065fAa254F87D20A5b0
wstETHShort:
0x25707b9e6690B52C60aE6744d711cf9C1dFC1876
LimitOrderManager: 0x112873b395B98287F3A4db266a58e2D01779Ad96
Making Amount vs Taking Amount
Making Amount: The amount of tokens the order maker is offering
Taking Amount: The amount of tokens the order maker wants to receive
These amounts are calculated based on the order type and side.
Order Hash
The Order Hash is a unique identifier for each order, calculated using the EIP712 standard. This hash serves as:
Unique Identifier: Each order has a distinct hash based on its parameters
Execution Tracker: Used to store and retrieve order execution status
Signature Target: The hash is what gets signed by the order maker
Database Key: Off-chain systems use this hash to index and track orders
The order hash is deterministic - the same order parameters will always produce the same hash. This allows for consistent tracking across different systems and ensures order integrity.
Signature
The Signature is a cryptographic proof that the order hash was authorized by the order maker. The signature content is the order hash (not the raw order data), ensuring any parameter changes invalidate the signature.
Signature Format:
EOA Signatures: 65 bytes (r, s, v) or 64 bytes (r, s) for EIP-2098 compact format
Smart Contract Signatures: Variable length, validated through EIP-1271
isValidSignature
method
Integrate Examples:
Signature Creation Example
// EIP712 Domain for f(x) Limit Order Manager
const domain = {
name: "f(x) Limit Order Manager",
version: "1",
chainId: 1, // Mainnet
verifyingContract: limitOrderManager.address
};
// EIP712 Types for Order struct
const types = {
Order: [
{ name: "maker", type: "address" },
{ name: "pool", type: "address" },
{ name: "positionId", type: "uint256" },
{ name: "positionSide", type: "bool" },
{ name: "orderType", type: "bool" },
{ name: "orderSide", type: "bool" },
{ name: "allowPartialFill", type: "bool" },
{ name: "triggerPrice", type: "uint256" },
{ name: "fxUSDDelta", type: "int256" },
{ name: "collDelta", type: "int256" },
{ name: "debtDelta", type: "int256" },
{ name: "nonce", type: "uint256" },
{ name: "salt", type: "bytes32" },
{ name: "deadline", type: "uint256" }
]
};
// Sign the order (actually signs the order hash)
async function signOrder(order, signer) {
// _signTypedData internally calculates the order hash and signs it
const signature = await signer._signTypedData(domain, types, order);
return signature; // This signature proves the signer authorized this specific order hash
}
// Verify signature before using
async function verifySignature(order, signature, expectedSigner) {
const recoveredAddress = ethers.utils.verifyTypedData(domain, types, order, signature);
return recoveredAddress.toLowerCase() === expectedSigner.toLowerCase();
}
// Usage example
const signature = await signOrder(order, signer);
const isValid = await verifySignature(order, signature, await signer.getAddress());
console.log(`Signature valid: ${isValid}`);
How to Call fillOrder
Function Signature
function fillOrder(
OrderLibrary.Order memory order,
bytes memory signature,
uint256 makingAmount,
uint256 takingAmount
) external nonReentrant
Parameters
order
: The order struct containing all order detailssignature
: EIP712 signature from the order makermakingAmount
: Amount of making tokens the filler providestakingAmount
: Amount of taking tokens the filler wants from the order
Prerequisites
Valid Signature: The order must be properly signed by the maker
Order Validation: Order parameters must pass validation checks
Price Conditions: Trigger price conditions must be met (if applicable)
Token Approvals: Filler must approve tokens to the LimitOrderManager
Sufficient Balance: Filler must have sufficient token balance
Example Integration
// Example using ethers.js
const order = {
maker: "0x...",
pool: "0x...",
positionId: 0,
positionSide: true,
orderType: false,
orderSide: true,
allowPartialFill: true,
triggerPrice: ethers.utils.parseEther("2000"),
fxUSDDelta: ethers.utils.parseEther("1000"),
collDelta: ethers.utils.parseEther("0.5"),
debtDelta: ethers.utils.parseEther("500"),
nonce: 1,
salt: "0x1234...",
deadline: Math.floor(Date.now() / 1000) + 3600
};
// Get the order hash for tracking
const orderHash = await limitOrderManager.getOrderHash(order);
console.log(`Order hash: ${orderHash}`);
// Check if order has been executed before
const execution = await limitOrderManager.getExecution(orderHash);
console.log(`Order status: ${execution.status}`);
// Get order details
const [makingToken, takingToken, makingAmount, takingAmount] =
await limitOrderManager.getOrderDetails(order);
// Approve tokens
await IERC20(takingToken).approve(limitOrderManager.address, makingAmount);
// Fill the order
await limitOrderManager.fillOrder(
order,
signature,
makingAmount,
takingAmount
);
Last updated