@@ -55,6 +55,7 @@ import {
55
55
overWriteMintAccount ,
56
56
overWritePerpMarket ,
57
57
overWriteSpotMarket ,
58
+ setFeedPriceNoProgram ,
58
59
} from './testHelpers' ;
59
60
import { startAnchor } from 'solana-bankrun' ;
60
61
import { TestBulkAccountLoader } from '../sdk/src/accounts/testBulkAccountLoader' ;
@@ -88,6 +89,7 @@ describe('LP Pool', () => {
88
89
let usdcMint : Keypair ;
89
90
let spotTokenMint : Keypair ;
90
91
let spotMarketOracle : PublicKey ;
92
+ let spotMarketOracle2 : PublicKey ;
91
93
92
94
const mantissaSqrtScale = new BN ( Math . sqrt ( PRICE_PRECISION . toNumber ( ) ) ) ;
93
95
const ammInitialQuoteAssetReserve = new anchor . BN ( 100 * 10 ** 13 ) . mul (
@@ -137,6 +139,7 @@ describe('LP Pool', () => {
137
139
usdcMint = await mockUSDCMint ( bankrunContextWrapper ) ;
138
140
spotTokenMint = await mockUSDCMint ( bankrunContextWrapper ) ;
139
141
spotMarketOracle = await mockOracleNoProgram ( bankrunContextWrapper , 200 ) ;
142
+ spotMarketOracle2 = await mockOracleNoProgram ( bankrunContextWrapper , 200 ) ;
140
143
141
144
const keypair = new Keypair ( ) ;
142
145
await bankrunContextWrapper . fundKeypair ( keypair , 10 ** 9 ) ;
@@ -243,7 +246,21 @@ describe('LP Pool', () => {
243
246
optimalUtilization ,
244
247
optimalRate ,
245
248
maxRate ,
246
- spotMarketOracle ,
249
+ spotMarketOracle2 ,
250
+ OracleSource . PYTH ,
251
+ initialAssetWeight ,
252
+ maintenanceAssetWeight ,
253
+ initialLiabilityWeight ,
254
+ maintenanceLiabilityWeight ,
255
+ imfFactor
256
+ ) ;
257
+
258
+ await adminClient . initializeSpotMarket (
259
+ spotTokenMint . publicKey ,
260
+ optimalUtilization ,
261
+ optimalRate ,
262
+ maxRate ,
263
+ spotMarketOracle2 ,
247
264
OracleSource . PYTH ,
248
265
initialAssetWeight ,
249
266
maintenanceAssetWeight ,
@@ -671,7 +688,7 @@ describe('LP Pool', () => {
671
688
) ;
672
689
} ) ;
673
690
674
- it ( 'can add constituent to LP Pool thats a derivative and get half of the target weight ' , async ( ) => {
691
+ it ( 'can add constituent to LP Pool thats a derivative and behave correctly ' , async ( ) => {
675
692
const lpPool = ( await adminClient . program . account . lpPool . fetch (
676
693
lpPoolKey
677
694
) ) as LPPoolAccount ;
@@ -723,7 +740,7 @@ describe('LP Pool', () => {
723
740
program . programId ,
724
741
lpPoolKey
725
742
) ;
726
- const constituentTargetBase =
743
+ let constituentTargetBase =
727
744
( await adminClient . program . account . constituentTargetBase . fetch (
728
745
constituentTargetBasePublicKey
729
746
) ) as ConstituentTargetBase ;
@@ -733,11 +750,88 @@ describe('LP Pool', () => {
733
750
'constituentTargetBase.targets' ,
734
751
constituentTargetBase . targets . map ( ( x ) => x . targetBase . toString ( ) )
735
752
) ;
736
- assert (
737
- constituentTargetBase . targets [ 1 ] . targetBase
738
- . sub ( constituentTargetBase . targets [ 2 ] . targetBase )
739
- . lt ( constituentTargetBase . targets [ 1 ] . targetBase . divn ( 1000 ) )
753
+ expect (
754
+ constituentTargetBase . targets [ 1 ] . targetBase . toNumber ( )
755
+ ) . to . be . approximately (
756
+ constituentTargetBase . targets [ 2 ] . targetBase . toNumber ( ) ,
757
+ 10
758
+ ) ;
759
+
760
+ // Move the oracle price to be double, so it should have half of the target base
761
+ const derivativeBalanceBefore = constituentTargetBase . targets [ 2 ] . targetBase ;
762
+ const derivative = ( await adminClient . program . account . constituent . fetch (
763
+ getConstituentPublicKey ( program . programId , lpPoolKey , 2 )
764
+ ) ) as ConstituentAccount ;
765
+ await setFeedPriceNoProgram ( bankrunContextWrapper , 400 , spotMarketOracle2 ) ;
766
+ await adminClient . updateConstituentOracleInfo ( derivative ) ;
767
+ const tx2 = new Transaction ( ) ;
768
+ tx2
769
+ . add ( await adminClient . getUpdateAmmCacheIx ( [ 0 , 1 , 2 ] ) )
770
+ . add (
771
+ await adminClient . getUpdateLpConstituentTargetBaseIx (
772
+ encodeName ( lpPoolName ) ,
773
+ [
774
+ getConstituentPublicKey ( program . programId , lpPoolKey , 0 ) ,
775
+ getConstituentPublicKey ( program . programId , lpPoolKey , 1 ) ,
776
+ getConstituentPublicKey ( program . programId , lpPoolKey , 2 ) ,
777
+ ]
778
+ )
779
+ ) ;
780
+ await adminClient . sendTransaction ( tx2 ) ;
781
+ await adminClient . updateLpPoolAum ( lpPool , [ 0 , 1 , 2 ] ) ;
782
+
783
+ constituentTargetBase =
784
+ ( await adminClient . program . account . constituentTargetBase . fetch (
785
+ constituentTargetBasePublicKey
786
+ ) ) as ConstituentTargetBase ;
787
+ const derivativeBalanceAfter = constituentTargetBase . targets [ 2 ] . targetBase ;
788
+
789
+ console . log (
790
+ 'constituentTargetBase.targets' ,
791
+ constituentTargetBase . targets . map ( ( x ) => x . targetBase . toString ( ) )
792
+ ) ;
793
+
794
+ expect ( derivativeBalanceAfter . toNumber ( ) ) . to . be . approximately (
795
+ derivativeBalanceBefore . toNumber ( ) / 2 ,
796
+ 20
740
797
) ;
798
+
799
+ // Move the oracle price to be half, so its target base should go to zero
800
+ const parentBalanceBefore = constituentTargetBase . targets [ 1 ] . targetBase ;
801
+ await setFeedPriceNoProgram ( bankrunContextWrapper , 100 , spotMarketOracle2 ) ;
802
+ await adminClient . updateConstituentOracleInfo ( derivative ) ;
803
+ const tx3 = new Transaction ( ) ;
804
+ tx3
805
+ . add ( await adminClient . getUpdateAmmCacheIx ( [ 0 , 1 , 2 ] ) )
806
+ . add (
807
+ await adminClient . getUpdateLpConstituentTargetBaseIx (
808
+ encodeName ( lpPoolName ) ,
809
+ [
810
+ getConstituentPublicKey ( program . programId , lpPoolKey , 0 ) ,
811
+ getConstituentPublicKey ( program . programId , lpPoolKey , 1 ) ,
812
+ getConstituentPublicKey ( program . programId , lpPoolKey , 2 ) ,
813
+ ]
814
+ )
815
+ ) ;
816
+ await adminClient . sendTransaction ( tx3 ) ;
817
+ await adminClient . updateLpPoolAum ( lpPool , [ 0 , 1 , 2 ] ) ;
818
+
819
+ constituentTargetBase =
820
+ ( await adminClient . program . account . constituentTargetBase . fetch (
821
+ constituentTargetBasePublicKey
822
+ ) ) as ConstituentTargetBase ;
823
+ const parentBalanceAfter = constituentTargetBase . targets [ 1 ] . targetBase ;
824
+
825
+ console . log (
826
+ 'constituentTargetBase.targets' ,
827
+ constituentTargetBase . targets . map ( ( x ) => x . targetBase . toString ( ) )
828
+ ) ;
829
+ expect ( parentBalanceAfter . toNumber ( ) ) . to . be . approximately (
830
+ parentBalanceBefore . toNumber ( ) * 2 ,
831
+ 10
832
+ ) ;
833
+ await setFeedPriceNoProgram ( bankrunContextWrapper , 200 , spotMarketOracle2 ) ;
834
+ await adminClient . updateConstituentOracleInfo ( derivative ) ;
741
835
} ) ;
742
836
743
837
it ( 'can settle pnl from perp markets into the usdc account' , async ( ) => {
@@ -1015,7 +1109,6 @@ describe('LP Pool', () => {
1015
1109
BigInt ( lpPool . lastAum . toNumber ( ) )
1016
1110
) ;
1017
1111
1018
- console . log ( 'here!' ) ;
1019
1112
const tx = new Transaction ( ) ;
1020
1113
tx . add ( await adminClient . getUpdateLpPoolAumIxs ( lpPool , [ 0 , 1 , 2 ] ) ) ;
1021
1114
tx . add (
@@ -1103,4 +1196,143 @@ describe('LP Pool', () => {
1103
1196
assert ( constituent . tokenBalance . eq ( balanceBefore . add ( owedAmount ) ) ) ;
1104
1197
assert ( lpPool . lastAum . eq ( aumBefore . add ( owedAmount ) ) ) ;
1105
1198
} ) ;
1199
+
1200
+ it ( 'can work with multiple derivatives on the same parent' , async ( ) => {
1201
+ const lpPool = ( await adminClient . program . account . lpPool . fetch (
1202
+ lpPoolKey
1203
+ ) ) as LPPoolAccount ;
1204
+
1205
+ await adminClient . initializeConstituent ( lpPool . name , {
1206
+ spotMarketIndex : 3 ,
1207
+ decimals : 6 ,
1208
+ maxWeightDeviation : new BN ( 10 ) . mul ( PERCENTAGE_PRECISION ) ,
1209
+ swapFeeMin : new BN ( 1 ) . mul ( PERCENTAGE_PRECISION ) ,
1210
+ swapFeeMax : new BN ( 2 ) . mul ( PERCENTAGE_PRECISION ) ,
1211
+ oracleStalenessThreshold : new BN ( 400 ) ,
1212
+ costToTrade : 1 ,
1213
+ derivativeWeight : PERCENTAGE_PRECISION . divn ( 4 ) ,
1214
+ volatility : new BN ( 10 ) . mul ( PERCENTAGE_PRECISION ) ,
1215
+ constituentCorrelations : [
1216
+ ZERO ,
1217
+ PERCENTAGE_PRECISION . muln ( 87 ) . divn ( 100 ) ,
1218
+ PERCENTAGE_PRECISION ,
1219
+ ] ,
1220
+ constituentDerivativeIndex : 1 ,
1221
+ } ) ;
1222
+
1223
+ await adminClient . updateConstituentParams (
1224
+ lpPool . name ,
1225
+ getConstituentPublicKey ( program . programId , lpPoolKey , 2 ) ,
1226
+ {
1227
+ derivativeWeight : PERCENTAGE_PRECISION . divn ( 4 ) ,
1228
+ }
1229
+ ) ;
1230
+
1231
+ await adminClient . updateAmmCache ( [ 0 , 1 , 2 ] ) ;
1232
+
1233
+ let constituent = ( await adminClient . program . account . constituent . fetch (
1234
+ getConstituentPublicKey ( program . programId , lpPoolKey , 3 )
1235
+ ) ) as ConstituentAccount ;
1236
+
1237
+ await adminClient . updateConstituentOracleInfo ( constituent ) ;
1238
+
1239
+ constituent = ( await adminClient . program . account . constituent . fetch (
1240
+ getConstituentPublicKey ( program . programId , lpPoolKey , 3 )
1241
+ ) ) as ConstituentAccount ;
1242
+ assert ( ! constituent . lastOraclePrice . eq ( ZERO ) ) ;
1243
+ await adminClient . updateLpPoolAum ( lpPool , [ 0 , 1 , 2 , 3 ] ) ;
1244
+
1245
+ const tx = new Transaction ( ) ;
1246
+ tx . add ( await adminClient . getUpdateAmmCacheIx ( [ 0 , 1 , 2 ] ) ) . add (
1247
+ await adminClient . getUpdateLpConstituentTargetBaseIx (
1248
+ encodeName ( lpPoolName ) ,
1249
+ [
1250
+ getConstituentPublicKey ( program . programId , lpPoolKey , 0 ) ,
1251
+ getConstituentPublicKey ( program . programId , lpPoolKey , 1 ) ,
1252
+ getConstituentPublicKey ( program . programId , lpPoolKey , 2 ) ,
1253
+ getConstituentPublicKey ( program . programId , lpPoolKey , 3 ) ,
1254
+ ]
1255
+ )
1256
+ ) ;
1257
+ await adminClient . sendTransaction ( tx ) ;
1258
+ await adminClient . updateLpPoolAum ( lpPool , [ 0 , 1 , 2 , 3 ] ) ;
1259
+
1260
+ const constituentTargetBasePublicKey = getConstituentTargetBasePublicKey (
1261
+ program . programId ,
1262
+ lpPoolKey
1263
+ ) ;
1264
+ let constituentTargetBase =
1265
+ ( await adminClient . program . account . constituentTargetBase . fetch (
1266
+ constituentTargetBasePublicKey
1267
+ ) ) as ConstituentTargetBase ;
1268
+
1269
+ expect ( constituentTargetBase ) . to . not . be . null ;
1270
+ console . log (
1271
+ 'constituentTargetBase.targets' ,
1272
+ constituentTargetBase . targets . map ( ( x ) => x . targetBase . toString ( ) )
1273
+ ) ;
1274
+ expect (
1275
+ constituentTargetBase . targets [ 2 ] . targetBase . toNumber ( )
1276
+ ) . to . be . approximately (
1277
+ constituentTargetBase . targets [ 3 ] . targetBase . toNumber ( ) ,
1278
+ 10
1279
+ ) ;
1280
+ expect (
1281
+ constituentTargetBase . targets [ 3 ] . targetBase . toNumber ( )
1282
+ ) . to . be . approximately (
1283
+ constituentTargetBase . targets [ 1 ] . targetBase . toNumber ( ) / 2 ,
1284
+ 10
1285
+ ) ;
1286
+
1287
+ // Set the derivative weights to 0
1288
+ await adminClient . updateConstituentParams (
1289
+ lpPool . name ,
1290
+ getConstituentPublicKey ( program . programId , lpPoolKey , 2 ) ,
1291
+ {
1292
+ derivativeWeight : ZERO ,
1293
+ }
1294
+ ) ;
1295
+
1296
+ await adminClient . updateConstituentParams (
1297
+ lpPool . name ,
1298
+ getConstituentPublicKey ( program . programId , lpPoolKey , 3 ) ,
1299
+ {
1300
+ derivativeWeight : ZERO ,
1301
+ }
1302
+ ) ;
1303
+
1304
+ const parentTargetBaseBefore = constituentTargetBase . targets [ 1 ] . targetBase ;
1305
+ const tx2 = new Transaction ( ) ;
1306
+ tx2
1307
+ . add ( await adminClient . getUpdateAmmCacheIx ( [ 0 , 1 , 2 ] ) )
1308
+ . add (
1309
+ await adminClient . getUpdateLpConstituentTargetBaseIx (
1310
+ encodeName ( lpPoolName ) ,
1311
+ [
1312
+ getConstituentPublicKey ( program . programId , lpPoolKey , 0 ) ,
1313
+ getConstituentPublicKey ( program . programId , lpPoolKey , 1 ) ,
1314
+ getConstituentPublicKey ( program . programId , lpPoolKey , 2 ) ,
1315
+ getConstituentPublicKey ( program . programId , lpPoolKey , 3 ) ,
1316
+ ]
1317
+ )
1318
+ ) ;
1319
+ await adminClient . sendTransaction ( tx2 ) ;
1320
+ await adminClient . updateLpPoolAum ( lpPool , [ 0 , 1 , 2 , 3 ] ) ;
1321
+
1322
+ constituentTargetBase =
1323
+ ( await adminClient . program . account . constituentTargetBase . fetch (
1324
+ constituentTargetBasePublicKey
1325
+ ) ) as ConstituentTargetBase ;
1326
+ console . log (
1327
+ 'constituentTargetBase.targets' ,
1328
+ constituentTargetBase . targets . map ( ( x ) => x . targetBase . toString ( ) )
1329
+ ) ;
1330
+
1331
+ const parentTargetBaseAfter = constituentTargetBase . targets [ 1 ] . targetBase ;
1332
+
1333
+ expect ( parentTargetBaseAfter . toNumber ( ) ) . to . be . approximately (
1334
+ parentTargetBaseBefore . toNumber ( ) * 2 ,
1335
+ 10
1336
+ ) ;
1337
+ } ) ;
1106
1338
} ) ;
0 commit comments