Skip to content

Commit

Permalink
add new order margin func
Browse files Browse the repository at this point in the history
  • Loading branch information
sunnyvempati committed Aug 10, 2023
1 parent fa1857c commit 3ed90cd
Show file tree
Hide file tree
Showing 6 changed files with 92 additions and 15 deletions.
17 changes: 16 additions & 1 deletion markets/perps-market/contracts/interfaces/IAsyncOrderModule.sol
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,24 @@ interface IAsyncOrderModule {
* @param marketId id of the market.
* @param sizeDelta size of position.
* @return orderFees incurred fees.
* @return fillPrice price at which the order would be filled.
*/
function computeOrderFees(
uint128 marketId,
int128 sizeDelta
) external view returns (uint256 orderFees);
) external view returns (uint256 orderFees, uint256 fillPrice);

/**
* @notice For a given market, account id, and a position size, returns the required total account margin for this order to succeed
* @dev Useful for integrators to determine if an order will succeed or fail
* @param marketId id of the market.
* @param accountId id of the trader account.
* @param sizeDelta size of position.
* @return requiredMargin margin required for the order to succeed.
*/
function requiredMarginForOrder(
uint128 marketId,
uint128 accountId,
int128 sizeDelta
) external view returns (uint256 requiredMargin);
}
47 changes: 43 additions & 4 deletions markets/perps-market/contracts/modules/AsyncOrderModule.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ import {Account} from "@synthetixio/main/contracts/storage/Account.sol";
import {AccountRBAC} from "@synthetixio/main/contracts/storage/AccountRBAC.sol";
import {IAsyncOrderModule} from "../interfaces/IAsyncOrderModule.sol";
import {PerpsMarket} from "../storage/PerpsMarket.sol";
import {PerpsAccount} from "../storage/PerpsAccount.sol";
import {AsyncOrder} from "../storage/AsyncOrder.sol";
import {Position} from "../storage/Position.sol";
import {PerpsPrice} from "../storage/PerpsPrice.sol";
import {GlobalPerpsMarket} from "../storage/GlobalPerpsMarket.sol";
import {PerpsMarketConfiguration} from "../storage/PerpsMarketConfiguration.sol";
Expand All @@ -24,6 +26,7 @@ contract AsyncOrderModule is IAsyncOrderModule {
using PerpsPrice for PerpsPrice.Data;
using PerpsMarket for PerpsMarket.Data;
using AsyncOrder for AsyncOrder.Data;
using PerpsAccount for PerpsAccount.Data;
using SettlementStrategy for SettlementStrategy.Data;
using GlobalPerpsMarket for GlobalPerpsMarket.Data;
using PerpsMarketConfiguration for PerpsMarketConfiguration.Data;
Expand Down Expand Up @@ -89,13 +92,49 @@ contract AsyncOrderModule is IAsyncOrderModule {
function computeOrderFees(
uint128 marketId,
int128 sizeDelta
) external view override returns (uint256 orderFees) {
PerpsMarket.Data storage perpsMarket = PerpsMarket.load(marketId);
int256 skew = perpsMarket.skew;
) external view override returns (uint256 orderFees, uint256 fillPrice) {
(orderFees, fillPrice) = _computeOrderFees(marketId, sizeDelta);
}

function requiredMarginForOrder(
uint128 accountId,
uint128 marketId,
int128 sizeDelta
) external view override returns (uint256 requiredMargin) {
PerpsMarketConfiguration.Data storage marketConfig = PerpsMarketConfiguration.load(
marketId
);

Position.Data storage oldPosition = PerpsMarket.accountPosition(marketId, accountId);
(
,
uint256 currentMaintenanceMargin,
uint256 currentTotalLiquidationRewards,

) = PerpsAccount.load(accountId).getAccountRequiredMargins();
(uint256 orderFees, uint256 fillPrice) = _computeOrderFees(marketId, sizeDelta);

return
AsyncOrder.getRequiredMarginWithNewPosition(
marketConfig,
marketId,
oldPosition.size,
oldPosition.size + sizeDelta,
fillPrice,
currentMaintenanceMargin,
currentTotalLiquidationRewards
) + orderFees;
}

function _computeOrderFees(
uint128 marketId,
int128 sizeDelta
) private view returns (uint256 orderFees, uint256 fillPrice) {
int256 skew = PerpsMarket.load(marketId).skew;
PerpsMarketConfiguration.Data storage marketConfig = PerpsMarketConfiguration.load(
marketId
);
uint256 fillPrice = AsyncOrder.calculateFillPrice(
fillPrice = AsyncOrder.calculateFillPrice(
skew,
marketConfig.skewScale,
sizeDelta,
Expand Down
6 changes: 3 additions & 3 deletions markets/perps-market/contracts/storage/AsyncOrder.sol
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,7 @@ library AsyncOrder {
revert InsufficientMargin(runtime.currentAvailableMargin, runtime.orderFees);
}

oldPosition = PerpsMarket.load(runtime.marketId).positions[runtime.accountId];
oldPosition = PerpsMarket.accountPosition(runtime.marketId, runtime.accountId);

PerpsMarket.validatePositionSize(
perpsMarketData,
Expand All @@ -339,7 +339,7 @@ library AsyncOrder {

runtime.newPositionSize = oldPosition.size + runtime.sizeDelta;
runtime.totalRequiredMargin =
_getRequiredMarginWithNewPosition(
getRequiredMarginWithNewPosition(
marketConfig,
runtime.marketId,
oldPosition.size,
Expand Down Expand Up @@ -466,7 +466,7 @@ library AsyncOrder {
* @notice After the required margins are calculated with the old position, this function replaces the
* old position data with the new position margin requirements and returns them.
*/
function _getRequiredMarginWithNewPosition(
function getRequiredMarginWithNewPosition(
PerpsMarketConfiguration.Data storage marketConfig,
uint128 marketId,
int128 oldPositionSize,
Expand Down
7 changes: 7 additions & 0 deletions markets/perps-market/contracts/storage/PerpsMarket.sol
Original file line number Diff line number Diff line change
Expand Up @@ -310,4 +310,11 @@ library PerpsMarket {

return traderUnrealizedPnl + unrealizedFunding - self.debtCorrectionAccumulator;
}

function accountPosition(
uint128 marketId,
uint128 accountId
) internal view returns (Position.Data storage position) {
position = load(marketId).positions[accountId];
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ describe('Orders - margin validation', () => {
describe('openPosition 1 failure', () => {
let orderFees: ethers.BigNumber;
before('get order fees', async () => {
orderFees = await systems().PerpsMarket.computeOrderFees(51, 3);
[orderFees] = await systems().PerpsMarket.computeOrderFees(51, 3);
});

it('reverts if not enough margin', async () => {
Expand All @@ -98,6 +98,15 @@ describe('Orders - margin validation', () => {
wei(10_000)
);

const totalRequiredMargin = initialMargin
.add(getMaxLiquidationReward(liquidationMargin, wei(100), wei(500)))
.add(orderFees);

assertBn.equal(
await systems().PerpsMarket.requiredMarginForOrder(2, 51, bn(3)),
totalRequiredMargin.toBN()
);

await assertRevert(
systems()
.PerpsMarket.connect(trader1())
Expand All @@ -110,10 +119,7 @@ describe('Orders - margin validation', () => {
referrer: ethers.constants.AddressZero,
trackingCode: ethers.constants.HashZero,
}),
`InsufficientMargin("${bn(100)}", "${initialMargin
.add(getMaxLiquidationReward(liquidationMargin, wei(100), wei(500)))
.add(orderFees)
.toString(18, true)}")`
`InsufficientMargin("${bn(100)}", "${totalRequiredMargin.toString(18, true)}")`
);
});
});
Expand Down Expand Up @@ -149,7 +155,7 @@ describe('Orders - margin validation', () => {
describe('openPosition 2 failure', () => {
let orderFees: ethers.BigNumber;
before('get order fees', async () => {
orderFees = await systems().PerpsMarket.computeOrderFees(50, 5);
[orderFees] = await systems().PerpsMarket.computeOrderFees(50, 5);
});

it('reverts if not enough margin', async () => {
Expand Down Expand Up @@ -186,6 +192,11 @@ describe('Orders - margin validation', () => {
.add(liqReward)
.add(orderFees);

assertBn.equal(
await systems().PerpsMarket.requiredMarginForOrder(2, 50, bn(5)),
totalRequiredMargin.toBN()
);

await assertRevert(
systems()
.PerpsMarket.connect(trader1())
Expand Down Expand Up @@ -233,7 +244,7 @@ describe('Orders - margin validation', () => {
describe('modify position', () => {
let orderFees: ethers.BigNumber;
before('get order fees', async () => {
orderFees = await systems().PerpsMarket.computeOrderFees(50, 5);
[orderFees] = await systems().PerpsMarket.computeOrderFees(50, 5);
});

it('reverts if not enough margin', async () => {
Expand Down Expand Up @@ -270,6 +281,11 @@ describe('Orders - margin validation', () => {
.add(liqReward)
.add(orderFees);

assertBn.equal(
await systems().PerpsMarket.requiredMarginForOrder(2, 50, bn(5)),
totalRequiredMargin.toBN()
);

await assertRevert(
systems()
.PerpsMarket.connect(trader1())
Expand Down

0 comments on commit 3ed90cd

Please sign in to comment.