Skip to content

Commit 156ebeb

Browse files
committed
more tests
1 parent 1f8ff11 commit 156ebeb

File tree

2 files changed

+213
-35
lines changed

2 files changed

+213
-35
lines changed

markets/perps-market/test/integration/Account/Debt.test.ts

Lines changed: 54 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,6 @@ import { ethers } from 'ethers';
77
const accountId = 4;
88

99
const synthMarketsConfig = [
10-
{
11-
name: 'btc',
12-
token: 'snxBTC',
13-
buyPrice: bn(20_000),
14-
sellPrice: bn(20_000),
15-
},
1610
{
1711
name: 'eth',
1812
token: 'snxETH',
@@ -29,7 +23,7 @@ const orderFees = {
2923
const ethPerpsMarketId = bn(26);
3024

3125
describe('Account Debt', () => {
32-
const { systems, provider, perpsMarkets, trader1, trader2, synthMarkets } = bootstrapMarkets({
26+
const { systems, provider, perpsMarkets, trader1, synthMarkets } = bootstrapMarkets({
3327
synthMarkets: synthMarketsConfig,
3428
perpsMarkets: [
3529
{
@@ -53,7 +47,7 @@ describe('Account Debt', () => {
5347
},
5448
},
5549
],
56-
traderAccountIds: [accountId, 5],
50+
traderAccountIds: [accountId],
5751
liquidationGuards: {
5852
minLiquidationReward: bn(0),
5953
minKeeperProfitRatioD18: bn(0),
@@ -72,31 +66,27 @@ describe('Account Debt', () => {
7266
synthMarket: () => synthMarkets()[0],
7367
snxUSDAmount: () => bn(240_000),
7468
},
75-
{
76-
synthMarket: () => synthMarkets()[1],
77-
snxUSDAmount: () => bn(1_400_000),
78-
},
79-
],
80-
});
81-
82-
await depositCollateral({
83-
systems,
84-
trader: trader2,
85-
accountId: () => 5,
86-
collaterals: [
87-
{
88-
synthMarket: () => synthMarkets()[0],
89-
snxUSDAmount: () => bn(16_000),
90-
},
91-
{
92-
synthMarket: () => synthMarkets()[1],
93-
snxUSDAmount: () => bn(20_000),
94-
},
9569
],
9670
});
9771
});
9872

9973
const openAndClosePosition = (size: Wei, startingPrice: Wei, endingPrice: Wei) => {
74+
const initialFillPrice = calculateFillPrice(wei(0), wei(1000), size, startingPrice);
75+
const finalFillPrice = calculateFillPrice(size, wei(1000), size.mul(-1), endingPrice);
76+
77+
const openOrderFee = computeFees(wei(0), wei(50), initialFillPrice, orderFees);
78+
const closeOrderFee = computeFees(wei(50), wei(-50), finalFillPrice, orderFees);
79+
80+
let synthUsedForOpenOrderFee: Wei, synthUsedForCloseOrderFee: Wei;
81+
before('identify synth amount required to pay open order fee', async () => {
82+
const { synthToBurn } = await systems().SpotMarket.quoteSellExactOut(
83+
synthMarkets()[0].marketId(),
84+
openOrderFee.totalFees,
85+
bn(0)
86+
);
87+
synthUsedForOpenOrderFee = wei(synthToBurn);
88+
});
89+
10090
before(`open position size ${size.toString()}`, async () => {
10191
await perpsMarkets()[0].aggregator().mockSetCurrentPrice(startingPrice.toBN());
10292

@@ -113,9 +103,20 @@ describe('Account Debt', () => {
113103
});
114104
});
115105

116-
before('close position', async () => {
106+
before('set ending price', async () => {
117107
await perpsMarkets()[0].aggregator().mockSetCurrentPrice(endingPrice.toBN());
108+
});
109+
110+
before('identify synth amount required to pay open order fee', async () => {
111+
const { synthToBurn } = await systems().SpotMarket.quoteSellExactOut(
112+
synthMarkets()[0].marketId(),
113+
closeOrderFee.totalFees,
114+
bn(0)
115+
);
116+
synthUsedForCloseOrderFee = wei(synthToBurn);
117+
});
118118

119+
before('close position', async () => {
119120
await openPosition({
120121
systems,
121122
provider,
@@ -129,24 +130,42 @@ describe('Account Debt', () => {
129130
});
130131
});
131132

132-
const initialFillPrice = calculateFillPrice(wei(0), wei(1000), size, startingPrice);
133-
const finalFillPrice = calculateFillPrice(size, wei(1000), size.mul(-1), endingPrice);
134-
135133
return {
136-
openOrderFee: computeFees(wei(0), wei(50), initialFillPrice, orderFees),
137-
closeOrderFee: computeFees(wei(50), wei(-50), finalFillPrice, orderFees),
134+
openOrderFee,
135+
closeOrderFee,
136+
synthUsedForOpenOrderFee: () => synthUsedForOpenOrderFee,
137+
synthUsedForCloseOrderFee: () => synthUsedForCloseOrderFee,
138138
pnl: finalFillPrice.sub(initialFillPrice).mul(size),
139139
};
140140
};
141141

142142
let currentDebt: Wei;
143143
describe('negative pnl', () => {
144-
const { pnl: expectedPnl } = openAndClosePosition(wei(50), wei(2000), wei(1500));
144+
let startingCollateralAmount: Wei;
145+
before('identify collateral amount', async () => {
146+
startingCollateralAmount = wei(
147+
await systems().PerpsMarket.getCollateralAmount(accountId, synthMarkets()[0].marketId())
148+
);
149+
});
150+
151+
const {
152+
pnl: expectedPnl,
153+
synthUsedForOpenOrderFee,
154+
synthUsedForCloseOrderFee,
155+
} = openAndClosePosition(wei(50), wei(2000), wei(1500));
145156

146157
it('accrues correct amount of debt', async () => {
147158
currentDebt = expectedPnl;
148159
assertBn.equal(currentDebt.abs().toBN(), await systems().PerpsMarket.debt(accountId));
149160
});
161+
162+
it('used collateral to pay order fees', async () => {
163+
const synthUsedForFees = synthUsedForOpenOrderFee().add(synthUsedForCloseOrderFee());
164+
assertBn.equal(
165+
startingCollateralAmount.sub(synthUsedForFees).toBN(),
166+
await systems().PerpsMarket.getCollateralAmount(accountId, synthMarkets()[0].marketId())
167+
);
168+
});
150169
});
151170

152171
describe('positive pnl to lower debt', () => {
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
import { bn, bootstrapMarkets } from '../bootstrap';
2+
import assertBn from '@synthetixio/core-utils/src/utils/assertions/assert-bignumber';
3+
import assertRevert from '@synthetixio/core-utils/utils/assertions/assert-revert';
4+
import { depositCollateral, discountedValue, openPosition } from '../helpers';
5+
import Wei, { wei } from '@synthetixio/wei';
6+
import { ethers } from 'ethers';
7+
import { SpotMarketProxy } from '@synthetixio/spot-market/test/generated/typechain';
8+
9+
const accountId = 4;
10+
const perpsMarketConfig = [
11+
{
12+
requestedMarketId: 25,
13+
name: 'Bitcoin',
14+
token: 'BTC',
15+
price: bn(20_000),
16+
fundingParams: { skewScale: bn(100), maxFundingVelocity: bn(0) },
17+
liquidationParams: {
18+
initialMarginFraction: bn(2),
19+
minimumInitialMarginRatio: bn(0.01),
20+
maintenanceMarginScalar: bn(0.5),
21+
maxLiquidationLimitAccumulationMultiplier: bn(1),
22+
liquidationRewardRatio: bn(0.05),
23+
maxSecondsInLiquidationWindow: ethers.BigNumber.from(10),
24+
minimumPositionMargin: bn(1000),
25+
},
26+
settlementStrategy: {
27+
settlementReward: bn(0),
28+
},
29+
},
30+
];
31+
32+
const btcDiscountConfig = {
33+
upperLimitDiscount: bn(0.05),
34+
lowerLimitDiscount: bn(0.01),
35+
discountScalar: bn(1.5),
36+
skewScale: bn(100),
37+
};
38+
39+
const synthMarketsConfig = [
40+
{
41+
name: 'btc',
42+
token: 'snxBTC',
43+
buyPrice: bn(20_000),
44+
sellPrice: bn(20_000),
45+
...btcDiscountConfig,
46+
},
47+
];
48+
49+
describe('Account margins - Multicollateral - InsufficientCollateralAvailableForWithdraw', () => {
50+
const { systems, provider, perpsMarkets, trader1, synthMarkets } = bootstrapMarkets({
51+
synthMarkets: synthMarketsConfig,
52+
perpsMarkets: perpsMarketConfig,
53+
traderAccountIds: [accountId],
54+
liquidationGuards: {
55+
minLiquidationReward: bn(0),
56+
minKeeperProfitRatioD18: bn(0),
57+
maxLiquidationReward: bn(10_000),
58+
maxKeeperScalingRatioD18: bn(1),
59+
},
60+
});
61+
62+
before('deposit some snxETH and snxBTC', async () => {
63+
await depositCollateral({
64+
systems,
65+
trader: trader1,
66+
accountId: () => accountId,
67+
collaterals: [
68+
{
69+
synthMarket: () => synthMarkets()[0],
70+
snxUSDAmount: () => bn(240_000),
71+
},
72+
],
73+
});
74+
});
75+
76+
let btcAmount: Wei, btcMarketId: ethers.BigNumber, spotMarket: SpotMarketProxy;
77+
78+
before('identify', async () => {
79+
spotMarket = systems().SpotMarket;
80+
btcMarketId = synthMarkets()[0].marketId();
81+
btcAmount = wei(
82+
await systems().PerpsMarket.getCollateralAmount(accountId, synthMarkets()[0].marketId())
83+
);
84+
});
85+
86+
let availableTradingMargin: Wei;
87+
it('has correct available trading margin', async () => {
88+
availableTradingMargin = await discountedValue(
89+
[
90+
{
91+
amount: btcAmount,
92+
synthId: btcMarketId,
93+
config: btcDiscountConfig,
94+
},
95+
],
96+
spotMarket
97+
);
98+
99+
assertBn.equal(
100+
await systems().PerpsMarket.getAvailableMargin(accountId),
101+
availableTradingMargin.toBN()
102+
);
103+
});
104+
105+
describe('open position', () => {
106+
before(async () => {
107+
await openPosition({
108+
systems,
109+
provider,
110+
trader: trader1(),
111+
accountId,
112+
keeper: trader1(),
113+
marketId: perpsMarkets()[0].marketId(),
114+
sizeDelta: bn(10),
115+
settlementStrategyId: perpsMarkets()[0].strategyId(),
116+
price: bn(20000),
117+
});
118+
});
119+
120+
let requiredMargin: Wei;
121+
122+
before('identify required margin', async () => {
123+
const { requiredInitialMargin } = await systems().PerpsMarket.getRequiredMargins(accountId);
124+
125+
requiredMargin = wei(requiredInitialMargin);
126+
});
127+
128+
let expectedWithdrawableMargin: Wei;
129+
it('should have correct available margin', async () => {
130+
const { totalPnl } = await systems().PerpsMarket.getOpenPosition(
131+
accountId,
132+
perpsMarkets()[0].marketId()
133+
);
134+
135+
console.log(availableTradingMargin, requiredMargin, totalPnl);
136+
expectedWithdrawableMargin = availableTradingMargin.sub(requiredMargin).add(totalPnl);
137+
138+
assertBn.equal(
139+
await systems().PerpsMarket.getWithdrawableMargin(accountId),
140+
expectedWithdrawableMargin.toBN()
141+
);
142+
});
143+
144+
it('reverts when attempting to withdraw more than available', async () => {
145+
const { synthToBurn: btcSynthToWithdraw } = await systems().SpotMarket.quoteSellExactOut(
146+
btcMarketId,
147+
expectedWithdrawableMargin.add(1).toBN(),
148+
bn(0)
149+
);
150+
151+
await assertRevert(
152+
systems()
153+
.PerpsMarket.connect(trader1())
154+
.modifyCollateral(accountId, btcMarketId, btcSynthToWithdraw.mul(-1)),
155+
'InsufficientCollateralAvailableForWithdraw'
156+
);
157+
});
158+
});
159+
});

0 commit comments

Comments
 (0)