Skip to content

Commit ebd53b5

Browse files
committed
fix: up tests for isolated transfer
1 parent ea85892 commit ebd53b5

File tree

1 file changed

+92
-31
lines changed

1 file changed

+92
-31
lines changed

tests/isolatedTransferMarginChecks.ts

Lines changed: 92 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ describe('isolated transfer margin checks', () => {
4040

4141
let solUsd;
4242
let ethUsd;
43+
let btcUsd;
4344

4445
// ammInvariant == k == x * y
4546
const mantissaSqrtScale = new BN(100000);
@@ -87,9 +88,10 @@ describe('isolated transfer margin checks', () => {
8788
bankrunContextWrapper
8889
);
8990

90-
// Create oracles for SOL and ETH
91+
// Create oracles for SOL, ETH and BTC
9192
solUsd = await mockOracleNoProgram(bankrunContextWrapper, 100); // $100 per SOL
9293
ethUsd = await mockOracleNoProgram(bankrunContextWrapper, 1000); // $1000 per ETH
94+
btcUsd = await mockOracleNoProgram(bankrunContextWrapper, 100000); // $100000 per BTC
9395

9496
eventSubscriber = new EventSubscriber(
9597
bankrunContextWrapper.connection.toConnection(),
@@ -106,12 +108,13 @@ describe('isolated transfer margin checks', () => {
106108
commitment: 'confirmed',
107109
},
108110
activeSubAccountId: 0,
109-
perpMarketIndexes: [0, 1],
111+
perpMarketIndexes: [0, 1, 2],
110112
spotMarketIndexes: [0],
111113
subAccountIds: [],
112114
oracleInfos: [
113115
{ publicKey: solUsd, source: OracleSource.PYTH },
114116
{ publicKey: ethUsd, source: OracleSource.PYTH },
117+
{ publicKey: btcUsd, source: OracleSource.PYTH },
115118
],
116119
userStats: true,
117120
accountSubscription: {
@@ -149,6 +152,16 @@ describe('isolated transfer margin checks', () => {
149152
new BN(1000 * PEG_PRECISION.toNumber())
150153
);
151154

155+
// Initialize BTC-PERP market (index 2)
156+
await driftClient.initializePerpMarket(
157+
2,
158+
btcUsd,
159+
ammInitialBaseAssetAmount,
160+
ammInitialQuoteAssetAmount,
161+
periodicity,
162+
new BN(100000 * PEG_PRECISION.toNumber())
163+
);
164+
152165
// Set step sizes
153166
await driftClient.updatePerpMarketStepSizeAndTickSize(
154167
0,
@@ -160,6 +173,11 @@ describe('isolated transfer margin checks', () => {
160173
new BN(1),
161174
new BN(1)
162175
);
176+
await driftClient.updatePerpMarketStepSizeAndTickSize(
177+
2,
178+
new BN(1),
179+
new BN(1)
180+
);
163181

164182
// Set margin ratios: 50% initial, 33% maintenance
165183
await driftClient.updatePerpMarketMarginRatio(
@@ -172,6 +190,11 @@ describe('isolated transfer margin checks', () => {
172190
MARGIN_PRECISION.toNumber() / 2, // 50% IM
173191
MARGIN_PRECISION.toNumber() / 3 // 33% MM
174192
);
193+
await driftClient.updatePerpMarketMarginRatio(
194+
2,
195+
MARGIN_PRECISION.toNumber() / 2, // 50% IM
196+
MARGIN_PRECISION.toNumber() / 3 // 33% MM
197+
);
175198

176199
// Initialize user account
177200
await driftClient.initializeUserAccount();
@@ -189,6 +212,7 @@ describe('isolated transfer margin checks', () => {
189212
// Restore oracle feeds to default prices so tests start with deterministic state
190213
await setFeedPriceNoProgram(bankrunContextWrapper, 100, solUsd);
191214
await setFeedPriceNoProgram(bankrunContextWrapper, 1000, ethUsd);
215+
await setFeedPriceNoProgram(bankrunContextWrapper, 100000, btcUsd);
192216

193217
await driftClient.fetchAccounts();
194218

@@ -226,6 +250,15 @@ describe('isolated transfer margin checks', () => {
226250
} catch (e) {
227251
// Ignore
228252
}
253+
try {
254+
await driftClient.settlePNL(
255+
await driftClient.getUserAccountPublicKey(),
256+
driftClient.getUserAccount(),
257+
2
258+
);
259+
} catch (e) {
260+
// Ignore
261+
}
229262

230263
await driftClient.fetchAccounts();
231264

@@ -332,7 +365,11 @@ describe('isolated transfer margin checks', () => {
332365
);
333366
assert(false, 'Transfer should have failed - cross would fail IM');
334367
} catch (e) {
335-
assert(true, 'Transfer correctly failed');
368+
if (e.message.includes('0x1773')) {
369+
assert(true, 'Transfer correctly failed');
370+
} else {
371+
throw e;
372+
}
336373
} finally {
337374
restoreConsole();
338375
}
@@ -348,7 +385,8 @@ describe('isolated transfer margin checks', () => {
348385
it('should fail transfer when cross already fails IM', async () => {
349386
await resetUserState();
350387

351-
// Cross: $400, 10 SOL long @ $100 -> $500 IM required, cross fails IM
388+
// Cross: $600, 10 SOL long @ $100 -> $500 IM required
389+
// SOL price moves to $80, cross has $300 effective collateral, IM is 10 x 70 x .5 = $350
352390
// Transfer $100 to isolated. Should fail (cross already below IM)
353391

354392
await driftClient.deposit(
@@ -361,8 +399,8 @@ describe('isolated transfer margin checks', () => {
361399
new BN(10 * 10 ** 9),
362400
0
363401
);
364-
// 10 SOL @ 100->80: loss 200, effective 400, need 500 IM
365-
await setFeedPriceNoProgram(bankrunContextWrapper, 80, solUsd);
402+
// 10 SOL @ 100->70: loss 200, effective 300 collateral, need 350 IM
403+
await setFeedPriceNoProgram(bankrunContextWrapper, 70, solUsd);
366404
await driftClient.fetchAccounts();
367405

368406
const restoreConsole = suppressConsole();
@@ -377,7 +415,11 @@ describe('isolated transfer margin checks', () => {
377415
);
378416
assert(false, 'Transfer should have failed - cross fails IM');
379417
} catch (e) {
380-
assert(true, 'Transfer correctly failed');
418+
if (e.message.includes('0x1773')) {
419+
assert(true, 'Transfer correctly failed');
420+
} else {
421+
throw e;
422+
}
381423
} finally {
382424
restoreConsole();
383425
}
@@ -415,7 +457,11 @@ describe('isolated transfer margin checks', () => {
415457
);
416458
assert(false, 'Transfer should have failed - cross fails MM');
417459
} catch (e) {
418-
assert(true, 'Transfer correctly failed');
460+
if (e.message.includes('0x1773')) {
461+
assert(true, 'Transfer correctly failed');
462+
} else {
463+
throw e;
464+
}
419465
} finally {
420466
restoreConsole();
421467
}
@@ -426,7 +472,7 @@ describe('isolated transfer margin checks', () => {
426472
it('should fail transfer when other isolated fails MM', async () => {
427473
await resetUserState();
428474

429-
// Cross: $800, no cross positions. Other isolated: SOL 10 long with $300 collateral,
475+
// Cross: $2000, no cross positions. Other isolated: SOL 10 long with $600 collateral,
430476
// SOL at 70 -> effective $300 < $333 MM. Transfer $200 to isolated ETH.
431477
// Cross after $600, no IM. But other isolated fails MM -> FAIL
432478

@@ -435,18 +481,17 @@ describe('isolated transfer margin checks', () => {
435481
0,
436482
userUSDCAccount.publicKey
437483
);
438-
await driftClient.depositIntoIsolatedPerpPosition(
484+
await driftClient.transferIsolatedPerpPositionDeposit(
439485
new BN(600 * 10 ** 6),
440-
0,
441-
userUSDCAccount.publicKey
486+
0
442487
);
443488
await driftClient.openPosition(
444489
PositionDirection.LONG,
445490
new BN(10 * 10 ** 9),
446491
0
447492
);
448493
// SOL at 70: 10*(100-70)=300 loss, 600-300=300 < 333 MM
449-
await setFeedPriceNoProgram(bankrunContextWrapper, 70, solUsd);
494+
await setFeedPriceNoProgram(bankrunContextWrapper, 50, solUsd);
450495
await driftClient.fetchAccounts();
451496

452497
// Cross has 1400, isolated SOL has 300 effective (fails MM)
@@ -462,7 +507,11 @@ describe('isolated transfer margin checks', () => {
462507
);
463508
assert(false, 'Transfer should have failed - other isolated fails MM');
464509
} catch (e) {
465-
assert(true, 'Transfer correctly failed');
510+
if (e.message.includes('0x1773')) {
511+
assert(true, 'Transfer correctly failed');
512+
} else {
513+
throw e;
514+
}
466515
} finally {
467516
restoreConsole();
468517
}
@@ -520,12 +569,12 @@ describe('isolated transfer margin checks', () => {
520569
it('should fail when both cross would fail IM after and other isolated fails MM', async () => {
521570
await resetUserState();
522571

523-
// Cross: $700, 10 SOL long ($500 IM). Other isolated: ETH 1 long with $300,
572+
// Cross: $1000, 10 SOL long ($500 IM). Other isolated: ETH 1 long with $600,
524573
// ETH at 700 -> effective $300 < $333 MM. Transfer $250.
525574
// Cross after $450 < $500 IM. Other isolated fails MM. FAIL
526575

527576
await driftClient.deposit(
528-
new BN(1000 * 10 ** 6),
577+
new BN(700 * 10 ** 6),
529578
0,
530579
userUSDCAccount.publicKey
531580
);
@@ -544,26 +593,30 @@ describe('isolated transfer margin checks', () => {
544593
new BN(1 * 10 ** 9),
545594
1
546595
);
547-
// Cross: 1000, 10 SOL @ 100. Sol at 100, cross IM 500, cross ok.
596+
// Cross: 700, 10 SOL @ 100. Sol at 100, cross IM 500, cross ok.
548597
// ETH at 700: 1*(1000-700)=300 loss, 600-300=300 < 333 MM
549598
await setFeedPriceNoProgram(bankrunContextWrapper, 700, ethUsd);
550599
await driftClient.fetchAccounts();
551600

552-
const restoreConsole = suppressConsole();
601+
// const restoreConsole = suppressConsole();
553602
try {
554603
await driftClient.transferIsolatedPerpPositionDeposit(
555604
new BN(250 * 10 ** 6),
556-
1,
605+
2,
557606
undefined,
558607
undefined,
559608
undefined,
560609
true
561610
);
562611
assert(false, 'Transfer should have failed');
563612
} catch (e) {
564-
assert(true, 'Transfer correctly failed');
613+
if (e.message.includes('0x1773')) {
614+
assert(true, 'Transfer correctly failed');
615+
} else {
616+
throw e;
617+
}
565618
} finally {
566-
restoreConsole();
619+
// restoreConsole();
567620
}
568621
});
569622
});
@@ -572,12 +625,12 @@ describe('isolated transfer margin checks', () => {
572625
it('should fail when cross would fail IM after even if other isolated passes MM', async () => {
573626
await resetUserState();
574627

575-
// Cross: $700, 10 SOL long ($500 IM). Other isolated: ETH 1 long with $400,
576-
// ETH at 800 -> effective $400 > $333 MM. Transfer $250.
577-
// Cross after $450 < $500 IM -> FAIL (other isolated is fine)
628+
// Cross: $700, 10 SOL long ($500 IM). Other isolated: ETH 1 long with $600,
629+
// ETH at 800 -> $200 loss, effective collateral $400 > $333 MM. Transfer $250.
630+
// Cross after transfer is $450 < $500 IM -> FAIL (other isolated is fine)
578631

579632
await driftClient.deposit(
580-
new BN(1000 * 10 ** 6),
633+
new BN(700 * 10 ** 6),
581634
0,
582635
userUSDCAccount.publicKey
583636
);
@@ -612,19 +665,23 @@ describe('isolated transfer margin checks', () => {
612665
);
613666
assert(false, 'Transfer should have failed - cross would fail IM');
614667
} catch (e) {
615-
assert(true, 'Transfer correctly failed');
668+
if (e.message.includes('0x1773')) {
669+
assert(true, 'Transfer correctly failed');
670+
} else {
671+
throw e;
672+
}
616673
} finally {
617674
restoreConsole();
618675
}
619676
});
620677
});
621678

622679
describe('Multi-isolated: one passes MM one fails blocks transfer', () => {
623-
it('should fail when any of multiple other isolated fails MM', async () => {
680+
it.only('should fail when any of multiple other isolated fails MM', async () => {
624681
await resetUserState();
625682

626683
// Cross: $2000. Isolated SOL: 10 long, $400 collateral at 80 -> passes MM.
627-
// Isolated ETH: 1 long, $300 collateral at 700 -> fails MM ($333).
684+
// Isolated ETH: 1 long, $300 collateral at 600 -> fails MM ($333).
628685
// Transfer $100 to... we need a third market. We only have SOL and ETH.
629686
// So: SOL isolated passes, ETH isolated fails. Transfer cross->ETH isolated (adding to failing one)
630687
// actually that would improve ETH. Let me reconsider.
@@ -654,9 +711,9 @@ describe('isolated transfer margin checks', () => {
654711
new BN(1 * 10 ** 9),
655712
1
656713
);
657-
// SOL at 80: passes MM. ETH at 700: fails MM
714+
// SOL at 80: passes MM. ETH at 600: fails MM
658715
await setFeedPriceNoProgram(bankrunContextWrapper, 80, solUsd);
659-
await setFeedPriceNoProgram(bankrunContextWrapper, 700, ethUsd);
716+
await setFeedPriceNoProgram(bankrunContextWrapper, 600, ethUsd);
660717
await driftClient.fetchAccounts();
661718

662719
const restoreConsole = suppressConsole();
@@ -671,7 +728,11 @@ describe('isolated transfer margin checks', () => {
671728
);
672729
assert(false, 'Transfer should fail - ETH isolated fails MM');
673730
} catch (e) {
674-
assert(true, 'Transfer correctly failed');
731+
if (e.message.includes('0x1773')) {
732+
assert(true, 'Transfer correctly failed');
733+
} else {
734+
throw e;
735+
}
675736
} finally {
676737
restoreConsole();
677738
}

0 commit comments

Comments
 (0)