@elmntl/jlpd-sdk 0.1.9 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -3,11 +3,13 @@ import {
3
3
  PublicKey as PublicKey8,
4
4
  TransactionMessage,
5
5
  VersionedTransaction,
6
- ComputeBudgetProgram
6
+ ComputeBudgetProgram,
7
+ SystemProgram as SystemProgram2
7
8
  } from "@solana/web3.js";
8
9
  import { BN as BN5 } from "@coral-xyz/anchor";
9
10
  import {
10
11
  TOKEN_PROGRAM_ID as TOKEN_PROGRAM_ID2,
12
+ ASSOCIATED_TOKEN_PROGRAM_ID as ASSOCIATED_TOKEN_PROGRAM_ID2,
11
13
  getAssociatedTokenAddressSync as getAssociatedTokenAddressSync2
12
14
  } from "@solana/spl-token";
13
15
 
@@ -108,66 +110,71 @@ var jlp_d_program_default = {
108
110
  args: []
109
111
  },
110
112
  {
111
- name: "close_stv",
113
+ name: "claim_withdraw",
112
114
  docs: [
113
- "Close an STV account and return rent to admin",
114
- "Destructive operation - use only for cleanup/migration",
115
+ "Claim processed withdrawal (epoch-based delayed withdrawal)",
115
116
  "",
116
- "# Safety Checks",
117
- "- Validates jvX supply is 0 (no active shares)",
118
- "- Validates base_loaned is 0 (no outstanding loans)",
119
- "- Validates accrued_fees_jlx is 0 (no unclaimed fees)"
117
+ "# Flow",
118
+ "1. Verify request is processed (pps > 0) and claim period reached",
119
+ "2. Transfer base from STV to user",
120
+ "3. Close request's jvX ATA and WithdrawRequest PDA (rent to user)"
120
121
  ],
121
122
  discriminator: [
122
- 173,
123
- 189,
124
- 151,
125
- 131,
126
- 240,
127
- 39,
128
- 199,
129
- 147
123
+ 232,
124
+ 89,
125
+ 154,
126
+ 117,
127
+ 16,
128
+ 204,
129
+ 182,
130
+ 224
130
131
  ],
131
132
  accounts: [
132
133
  {
133
- name: "admin",
134
+ name: "user",
134
135
  docs: [
135
- "Admin must sign - verified via vault.has_one = admin"
136
+ "User claiming their withdrawal"
136
137
  ],
137
138
  writable: true,
138
- signer: true,
139
- relations: [
140
- "jlp_vault"
139
+ signer: true
140
+ },
141
+ {
142
+ name: "stv",
143
+ docs: [
144
+ "The STV PDA account (mut for reserved_base update)"
145
+ ],
146
+ writable: true
147
+ },
148
+ {
149
+ name: "base_mint",
150
+ docs: [
151
+ "Base asset mint (for transfer_checked)"
141
152
  ]
142
153
  },
143
154
  {
144
- name: "jlp_vault",
155
+ name: "jv_mint",
145
156
  docs: [
146
- "JLP Vault for admin validation"
157
+ "jvX mint (for ATA close verification)"
158
+ ]
159
+ },
160
+ {
161
+ name: "user_base_ata",
162
+ docs: [
163
+ "User's base token destination"
147
164
  ],
148
- pda: {
149
- seeds: [
150
- {
151
- kind: "const",
152
- value: [
153
- 106,
154
- 108,
155
- 112,
156
- 95,
157
- 118,
158
- 97,
159
- 117,
160
- 108,
161
- 116
162
- ]
163
- }
164
- ]
165
- }
165
+ writable: true
166
166
  },
167
167
  {
168
- name: "stv",
168
+ name: "stv_base_ata",
169
+ docs: [
170
+ "STV's base ATA (source for base transfer)"
171
+ ],
172
+ writable: true
173
+ },
174
+ {
175
+ name: "withdraw_request",
169
176
  docs: [
170
- "STV to close"
177
+ "WithdrawRequest PDA - closed after claim (rent to user)"
171
178
  ],
172
179
  writable: true,
173
180
  pda: {
@@ -175,33 +182,49 @@ var jlp_d_program_default = {
175
182
  {
176
183
  kind: "const",
177
184
  value: [
178
- 115,
185
+ 119,
186
+ 105,
179
187
  116,
180
- 118
188
+ 104,
189
+ 100,
190
+ 114,
191
+ 97,
192
+ 119,
193
+ 95,
194
+ 114,
195
+ 101,
196
+ 113,
197
+ 117,
198
+ 101,
199
+ 115,
200
+ 116
181
201
  ]
182
202
  },
183
203
  {
184
204
  kind: "account",
185
- path: "base_mint"
205
+ path: "stv"
206
+ },
207
+ {
208
+ kind: "account",
209
+ path: "user"
210
+ },
211
+ {
212
+ kind: "account",
213
+ path: "withdraw_request.epoch_id",
214
+ account: "WithdrawRequest"
186
215
  }
187
216
  ]
188
217
  }
189
218
  },
190
219
  {
191
- name: "jv_mint",
220
+ name: "request_jvx_ata",
192
221
  docs: [
193
- "jvX mint for this STV - used to verify no active shares"
194
- ]
195
- },
196
- {
197
- name: "base_mint",
198
- docs: [
199
- "Base asset mint for this STV"
200
- ]
222
+ "Empty jvX ATA owned by WithdrawRequest PDA (to close, rent to user)"
223
+ ],
224
+ writable: true
201
225
  },
202
226
  {
203
- name: "system_program",
204
- address: "11111111111111111111111111111111"
227
+ name: "token_program"
205
228
  }
206
229
  ],
207
230
  args: []
@@ -463,7 +486,7 @@ var jlp_d_program_default = {
463
486
  name: "jv_mint",
464
487
  docs: [
465
488
  "Vault share token mint (jvX) - STV is the mint authority",
466
- "Client generates keypair and passes it as signer"
489
+ "Uses init_if_needed in case mint exists from a previous STV initialization"
467
490
  ],
468
491
  writable: true,
469
492
  signer: true
@@ -795,6 +818,305 @@ var jlp_d_program_default = {
795
818
  }
796
819
  ]
797
820
  },
821
+ {
822
+ name: "process_epoch",
823
+ docs: [
824
+ "Process epoch: burn jvX from withdraw requests, record PPS, earmark base",
825
+ "",
826
+ "Permissionless (anyone can call after epoch ends).",
827
+ "Processes WithdrawRequest pairs from remaining_accounts.",
828
+ "Uses epoch_pps for multi-batch consistency.",
829
+ "",
830
+ "# Remaining Accounts",
831
+ "- [0-1]: Jupiter Lend accounts (if jl_mint != base_mint)",
832
+ "- [N..]: pairs of [WithdrawRequest (mut), request_jvx_ata (mut)]"
833
+ ],
834
+ discriminator: [
835
+ 115,
836
+ 194,
837
+ 215,
838
+ 160,
839
+ 113,
840
+ 154,
841
+ 81,
842
+ 5
843
+ ],
844
+ accounts: [
845
+ {
846
+ name: "payer",
847
+ docs: [
848
+ "Payer/caller - permissionless (anyone can call after epoch ends)"
849
+ ],
850
+ writable: true,
851
+ signer: true
852
+ },
853
+ {
854
+ name: "jlp_vault",
855
+ docs: [
856
+ "The JLP Vault PDA account (for pause checks)"
857
+ ]
858
+ },
859
+ {
860
+ name: "stv",
861
+ docs: [
862
+ "The STV PDA account (mut for epoch state + fee crystallization)"
863
+ ],
864
+ writable: true
865
+ },
866
+ {
867
+ name: "base_mint",
868
+ docs: [
869
+ "Base asset mint (for NAV calc)"
870
+ ]
871
+ },
872
+ {
873
+ name: "jl_mint",
874
+ docs: [
875
+ "jlX mint (for exchange rate)"
876
+ ]
877
+ },
878
+ {
879
+ name: "jv_mint",
880
+ docs: [
881
+ "jvX mint (mut for burn - supply decreases)"
882
+ ],
883
+ writable: true
884
+ },
885
+ {
886
+ name: "stv_base_ata",
887
+ docs: [
888
+ "STV's base ATA (for NAV)"
889
+ ]
890
+ },
891
+ {
892
+ name: "stv_jlx_ata",
893
+ docs: [
894
+ "STV's jlX ATA (for NAV)"
895
+ ]
896
+ },
897
+ {
898
+ name: "token_program"
899
+ }
900
+ ],
901
+ args: []
902
+ },
903
+ {
904
+ name: "request_withdraw",
905
+ docs: [
906
+ "Request withdrawal of jvX shares (epoch-based delayed withdrawal)",
907
+ "",
908
+ "# Flow",
909
+ "1. Validate epoch is active and not ended",
910
+ "2. Create or accumulate into WithdrawRequest PDA for this epoch",
911
+ "3. Transfer jvX from user to request's escrow ATA",
912
+ "",
913
+ "User must wait for process_epoch + claim_withdraw to receive base."
914
+ ],
915
+ discriminator: [
916
+ 137,
917
+ 95,
918
+ 187,
919
+ 96,
920
+ 250,
921
+ 138,
922
+ 31,
923
+ 182
924
+ ],
925
+ accounts: [
926
+ {
927
+ name: "user",
928
+ docs: [
929
+ "User requesting withdrawal"
930
+ ],
931
+ writable: true,
932
+ signer: true
933
+ },
934
+ {
935
+ name: "jlp_vault",
936
+ docs: [
937
+ "The JLP Vault PDA account (for pause checks)"
938
+ ]
939
+ },
940
+ {
941
+ name: "stv",
942
+ docs: [
943
+ "The STV PDA account (for epoch validation)"
944
+ ],
945
+ writable: true
946
+ },
947
+ {
948
+ name: "jv_mint",
949
+ docs: [
950
+ "jvX mint (vault share token)"
951
+ ]
952
+ },
953
+ {
954
+ name: "user_jvx_ata",
955
+ docs: [
956
+ "User's jvX token account (source of shares)"
957
+ ],
958
+ writable: true
959
+ },
960
+ {
961
+ name: "withdraw_request",
962
+ docs: [
963
+ "WithdrawRequest PDA - created or accumulated into"
964
+ ],
965
+ writable: true,
966
+ pda: {
967
+ seeds: [
968
+ {
969
+ kind: "const",
970
+ value: [
971
+ 119,
972
+ 105,
973
+ 116,
974
+ 104,
975
+ 100,
976
+ 114,
977
+ 97,
978
+ 119,
979
+ 95,
980
+ 114,
981
+ 101,
982
+ 113,
983
+ 117,
984
+ 101,
985
+ 115,
986
+ 116
987
+ ]
988
+ },
989
+ {
990
+ kind: "account",
991
+ path: "stv"
992
+ },
993
+ {
994
+ kind: "account",
995
+ path: "user"
996
+ },
997
+ {
998
+ kind: "arg",
999
+ path: "epoch_id"
1000
+ }
1001
+ ]
1002
+ }
1003
+ },
1004
+ {
1005
+ name: "request_jvx_ata",
1006
+ docs: [
1007
+ "jvX ATA owned by the WithdrawRequest PDA (escrow for shares)"
1008
+ ],
1009
+ writable: true,
1010
+ pda: {
1011
+ seeds: [
1012
+ {
1013
+ kind: "account",
1014
+ path: "withdraw_request"
1015
+ },
1016
+ {
1017
+ kind: "const",
1018
+ value: [
1019
+ 6,
1020
+ 221,
1021
+ 246,
1022
+ 225,
1023
+ 215,
1024
+ 101,
1025
+ 161,
1026
+ 147,
1027
+ 217,
1028
+ 203,
1029
+ 225,
1030
+ 70,
1031
+ 206,
1032
+ 235,
1033
+ 121,
1034
+ 172,
1035
+ 28,
1036
+ 180,
1037
+ 133,
1038
+ 237,
1039
+ 95,
1040
+ 91,
1041
+ 55,
1042
+ 145,
1043
+ 58,
1044
+ 140,
1045
+ 245,
1046
+ 133,
1047
+ 126,
1048
+ 255,
1049
+ 0,
1050
+ 169
1051
+ ]
1052
+ },
1053
+ {
1054
+ kind: "account",
1055
+ path: "jv_mint"
1056
+ }
1057
+ ],
1058
+ program: {
1059
+ kind: "const",
1060
+ value: [
1061
+ 140,
1062
+ 151,
1063
+ 37,
1064
+ 143,
1065
+ 78,
1066
+ 36,
1067
+ 137,
1068
+ 241,
1069
+ 187,
1070
+ 61,
1071
+ 16,
1072
+ 41,
1073
+ 20,
1074
+ 142,
1075
+ 13,
1076
+ 131,
1077
+ 11,
1078
+ 90,
1079
+ 19,
1080
+ 153,
1081
+ 218,
1082
+ 255,
1083
+ 16,
1084
+ 132,
1085
+ 4,
1086
+ 142,
1087
+ 123,
1088
+ 216,
1089
+ 219,
1090
+ 233,
1091
+ 248,
1092
+ 89
1093
+ ]
1094
+ }
1095
+ }
1096
+ },
1097
+ {
1098
+ name: "token_program"
1099
+ },
1100
+ {
1101
+ name: "associated_token_program",
1102
+ address: "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL"
1103
+ },
1104
+ {
1105
+ name: "system_program",
1106
+ address: "11111111111111111111111111111111"
1107
+ }
1108
+ ],
1109
+ args: [
1110
+ {
1111
+ name: "shares",
1112
+ type: "u64"
1113
+ },
1114
+ {
1115
+ name: "epoch_id",
1116
+ type: "u32"
1117
+ }
1118
+ ]
1119
+ },
798
1120
  {
799
1121
  name: "settle_yield",
800
1122
  docs: [
@@ -806,17 +1128,15 @@ var jlp_d_program_default = {
806
1128
  "2. Values total base_loaned across all STVs in USD",
807
1129
  "3. Distributes surplus (yield) or deficit (bad debt) proportionally",
808
1130
  "",
809
- "# Parameters",
810
- "- `jlp_rate`: Manager-provided JLP price (8 decimals), cross-checked against Pyth",
811
- "",
812
1131
  "# Security",
813
1132
  "- BTC/ETH/SOL prices come from Doves oracles (manipulation-resistant)",
814
- "- JLP price from Pyth oracle, validated against manager rate (50 bps tolerance)",
1133
+ "- JLP price computed directly from Jupiter Perps Pool account (aumUsd / jlp_supply)",
815
1134
  "- Exchange rates come from Jupiter Earn (audited, TWAP-based)",
816
1135
  "- Distribution is proportional to each STV's share of total loans",
817
1136
  "",
818
1137
  "# Accounts",
819
- "Requires all 5 STVs, 5 staging jlX ATAs, 3 Doves oracles (BTC/ETH/SOL), 1 Pyth oracle (JLP)",
1138
+ "Requires all 5 STVs, 5 staging jlX ATAs, 3 Doves oracles (BTC/ETH/SOL),",
1139
+ "Jupiter Perps Pool account, JLP mint account",
820
1140
  "",
821
1141
  "# Remaining Accounts (15 accounts)",
822
1142
  "For exchange rate calculation with time-accrued rewards:",
@@ -890,7 +1210,10 @@ var jlp_d_program_default = {
890
1210
  name: "doves_sol_usd"
891
1211
  },
892
1212
  {
893
- name: "pyth_jlp_usd"
1213
+ name: "jlp_pool"
1214
+ },
1215
+ {
1216
+ name: "jlp_mint_account"
894
1217
  },
895
1218
  {
896
1219
  name: "manager",
@@ -900,16 +1223,7 @@ var jlp_d_program_default = {
900
1223
  signer: true
901
1224
  }
902
1225
  ],
903
- args: [
904
- {
905
- name: "params",
906
- type: {
907
- defined: {
908
- name: "SettleYieldParams"
909
- }
910
- }
911
- }
912
- ]
1226
+ args: []
913
1227
  },
914
1228
  {
915
1229
  name: "swap_jlx_to_from_jlp",
@@ -1049,121 +1363,6 @@ var jlp_d_program_default = {
1049
1363
  }
1050
1364
  }
1051
1365
  ]
1052
- },
1053
- {
1054
- name: "withdraw",
1055
- docs: [
1056
- "Withdraw base asset by burning jvX shares",
1057
- "",
1058
- "# Flow",
1059
- "1. Crystallize fees inline (ensures fair PPS)",
1060
- "2. Calculate base amount from shares at post-fee PPS",
1061
- "3. Burn jvX shares from user",
1062
- "4. Transfer base from STV's base ATA to user",
1063
- "",
1064
- "# Note",
1065
- "Requires sufficient base balance in STV's base ATA.",
1066
- "Manager must ensure liquidity by converting jlX to base via",
1067
- "jup_earn_deposit_withdraw instruction before user withdrawals.",
1068
- "",
1069
- "Remaining accounts (optional, for exchange rate):",
1070
- "[0] = Jupiter Lend lending account",
1071
- "[1] = Jupiter Lend rewards rate model"
1072
- ],
1073
- discriminator: [
1074
- 183,
1075
- 18,
1076
- 70,
1077
- 156,
1078
- 148,
1079
- 109,
1080
- 161,
1081
- 34
1082
- ],
1083
- accounts: [
1084
- {
1085
- name: "user",
1086
- docs: [
1087
- "User performing the withdrawal"
1088
- ],
1089
- writable: true,
1090
- signer: true
1091
- },
1092
- {
1093
- name: "jlp_vault",
1094
- docs: [
1095
- "The JLP Vault PDA account",
1096
- "Note: PDA verified in handler via get_pda() to avoid multiple loads"
1097
- ]
1098
- },
1099
- {
1100
- name: "stv",
1101
- docs: [
1102
- "The STV PDA account",
1103
- "Note: PDA verified in handler via get_pda() to avoid multiple loads"
1104
- ],
1105
- writable: true
1106
- },
1107
- {
1108
- name: "base_mint",
1109
- docs: [
1110
- "Base asset mint (underlying token: SOL, BTC, ETH, USDC)"
1111
- ]
1112
- },
1113
- {
1114
- name: "jl_mint",
1115
- docs: [
1116
- "jlX mint (Jupiter Lend token) - used for NAV calculation"
1117
- ]
1118
- },
1119
- {
1120
- name: "jv_mint",
1121
- docs: [
1122
- "jvX mint (vault share token) - STV is mint authority",
1123
- "Verified against STV.jv_mint in handler"
1124
- ],
1125
- writable: true
1126
- },
1127
- {
1128
- name: "user_base_ata",
1129
- docs: [
1130
- "User's base asset token account (destination for withdrawal)"
1131
- ],
1132
- writable: true
1133
- },
1134
- {
1135
- name: "user_jvx_ata",
1136
- docs: [
1137
- "User's jvX token account (source - shares to burn)"
1138
- ],
1139
- writable: true
1140
- },
1141
- {
1142
- name: "stv_base_ata",
1143
- docs: [
1144
- "STV's base ATA (source for base tokens to user)"
1145
- ],
1146
- writable: true
1147
- },
1148
- {
1149
- name: "stv_jlx_ata",
1150
- docs: [
1151
- "STV's jlX ATA (used for NAV calculation)"
1152
- ]
1153
- },
1154
- {
1155
- name: "token_program",
1156
- docs: [
1157
- "Token program"
1158
- ]
1159
- }
1160
- ],
1161
- args: [
1162
- {
1163
- name: "shares_to_burn",
1164
- type: "u64"
1165
- }
1166
- ]
1167
1366
  }
1168
1367
  ],
1169
1368
  accounts: [
@@ -1192,6 +1391,19 @@ var jlp_d_program_default = {
1192
1391
  17,
1193
1392
  230
1194
1393
  ]
1394
+ },
1395
+ {
1396
+ name: "WithdrawRequest",
1397
+ discriminator: [
1398
+ 186,
1399
+ 239,
1400
+ 174,
1401
+ 191,
1402
+ 189,
1403
+ 13,
1404
+ 47,
1405
+ 196
1406
+ ]
1195
1407
  }
1196
1408
  ],
1197
1409
  events: [
@@ -1208,6 +1420,32 @@ var jlp_d_program_default = {
1208
1420
  57
1209
1421
  ]
1210
1422
  },
1423
+ {
1424
+ name: "EpochAdvanced",
1425
+ discriminator: [
1426
+ 41,
1427
+ 220,
1428
+ 14,
1429
+ 123,
1430
+ 117,
1431
+ 70,
1432
+ 117,
1433
+ 157
1434
+ ]
1435
+ },
1436
+ {
1437
+ name: "EpochProcessed",
1438
+ discriminator: [
1439
+ 18,
1440
+ 238,
1441
+ 2,
1442
+ 247,
1443
+ 238,
1444
+ 178,
1445
+ 94,
1446
+ 138
1447
+ ]
1448
+ },
1211
1449
  {
1212
1450
  name: "FeesClaimSkipped",
1213
1451
  discriminator: [
@@ -1378,16 +1616,29 @@ var jlp_d_program_default = {
1378
1616
  ]
1379
1617
  },
1380
1618
  {
1381
- name: "Withdrawn",
1619
+ name: "WithdrawClaimed",
1620
+ discriminator: [
1621
+ 77,
1622
+ 130,
1623
+ 89,
1624
+ 38,
1625
+ 239,
1626
+ 172,
1627
+ 174,
1628
+ 85
1629
+ ]
1630
+ },
1631
+ {
1632
+ name: "WithdrawRequested",
1382
1633
  discriminator: [
1383
- 20,
1384
- 89,
1385
- 223,
1386
- 198,
1387
- 194,
1388
- 124,
1389
- 219,
1390
- 13
1634
+ 114,
1635
+ 16,
1636
+ 240,
1637
+ 206,
1638
+ 93,
1639
+ 128,
1640
+ 151,
1641
+ 39
1391
1642
  ]
1392
1643
  }
1393
1644
  ],
@@ -1609,8 +1860,8 @@ var jlp_d_program_default = {
1609
1860
  },
1610
1861
  {
1611
1862
  code: 6043,
1612
- name: "JlpRateExceedsTolerance",
1613
- msg: "Manager JLP rate exceeds tolerance vs Pyth oracle (>50 bps)"
1863
+ name: "JlpPriceOutOfRange",
1864
+ msg: "JLP price out of reasonable range ($0.50 - $50.00)"
1614
1865
  },
1615
1866
  {
1616
1867
  code: 6044,
@@ -1621,6 +1872,56 @@ var jlp_d_program_default = {
1621
1872
  code: 6045,
1622
1873
  name: "NotAdmin",
1623
1874
  msg: "Unauthorized: not admin"
1875
+ },
1876
+ {
1877
+ code: 6046,
1878
+ name: "TokenAccountNotEmpty",
1879
+ msg: "Token account balance must be zero before closing"
1880
+ },
1881
+ {
1882
+ code: 6047,
1883
+ name: "TokenAccountOwnerMismatch",
1884
+ msg: "Token account not owned by expected PDA"
1885
+ },
1886
+ {
1887
+ code: 6048,
1888
+ name: "EpochEnded",
1889
+ msg: "Epoch has ended - call process_epoch first"
1890
+ },
1891
+ {
1892
+ code: 6049,
1893
+ name: "EpochNotEnded",
1894
+ msg: "Epoch has not ended yet"
1895
+ },
1896
+ {
1897
+ code: 6050,
1898
+ name: "ClaimNotAvailableYet",
1899
+ msg: "Claim not available yet - wait for next epoch"
1900
+ },
1901
+ {
1902
+ code: 6051,
1903
+ name: "InvalidEpochInterval",
1904
+ msg: "Withdraw epoch interval must be > 0"
1905
+ },
1906
+ {
1907
+ code: 6052,
1908
+ name: "ActiveWithdrawReserves",
1909
+ msg: "Cannot update epoch interval with active reserves"
1910
+ },
1911
+ {
1912
+ code: 6053,
1913
+ name: "EpochIdMismatch",
1914
+ msg: "Epoch ID mismatch"
1915
+ },
1916
+ {
1917
+ code: 6054,
1918
+ name: "WithdrawRequestNotProcessed",
1919
+ msg: "Withdraw request not processed yet"
1920
+ },
1921
+ {
1922
+ code: 6055,
1923
+ name: "WithdrawRequestAlreadyProcessed",
1924
+ msg: "Withdraw request already processed"
1624
1925
  }
1625
1926
  ],
1626
1927
  types: [
@@ -1672,6 +1973,62 @@ var jlp_d_program_default = {
1672
1973
  ]
1673
1974
  }
1674
1975
  },
1976
+ {
1977
+ name: "EpochAdvanced",
1978
+ type: {
1979
+ kind: "struct",
1980
+ fields: [
1981
+ {
1982
+ name: "stv",
1983
+ type: "pubkey"
1984
+ },
1985
+ {
1986
+ name: "new_epoch_id",
1987
+ type: "u32"
1988
+ },
1989
+ {
1990
+ name: "new_next_epoch_ts",
1991
+ type: "u32"
1992
+ }
1993
+ ]
1994
+ }
1995
+ },
1996
+ {
1997
+ name: "EpochProcessed",
1998
+ type: {
1999
+ kind: "struct",
2000
+ fields: [
2001
+ {
2002
+ name: "stv",
2003
+ type: "pubkey"
2004
+ },
2005
+ {
2006
+ name: "epoch_id",
2007
+ type: "u32"
2008
+ },
2009
+ {
2010
+ name: "pps",
2011
+ type: "u64"
2012
+ },
2013
+ {
2014
+ name: "total_shares",
2015
+ type: "u64"
2016
+ },
2017
+ {
2018
+ name: "total_base",
2019
+ type: "u64"
2020
+ },
2021
+ {
2022
+ name: "new_epoch_id",
2023
+ type: "u32"
2024
+ },
2025
+ {
2026
+ name: "new_next_epoch_ts",
2027
+ type: "u32"
2028
+ }
2029
+ ]
2030
+ }
2031
+ },
1675
2032
  {
1676
2033
  name: "FeesClaimSkipped",
1677
2034
  docs: [
@@ -1857,6 +2214,13 @@ var jlp_d_program_default = {
1857
2214
  "Minimum deposit amount in base asset (0 = no minimum)"
1858
2215
  ],
1859
2216
  type: "u64"
2217
+ },
2218
+ {
2219
+ name: "epoch_sec",
2220
+ docs: [
2221
+ "Epoch duration in seconds for delayed withdrawals"
2222
+ ],
2223
+ type: "u32"
1860
2224
  }
1861
2225
  ]
1862
2226
  }
@@ -2302,7 +2666,7 @@ var jlp_d_program_default = {
2302
2666
  docs: [
2303
2667
  "STV - Single Token Vault account",
2304
2668
  'Seeds: ["stv", base_mint.key().as_ref()]',
2305
- "Size: 8 (discriminator) + 160 (data) = 168 bytes"
2669
+ "Size: 8 (discriminator) + 200 (data) = 208 bytes"
2306
2670
  ],
2307
2671
  serialization: "bytemuck",
2308
2672
  repr: {
@@ -2384,6 +2748,50 @@ var jlp_d_program_default = {
2384
2748
  ],
2385
2749
  type: "u64"
2386
2750
  },
2751
+ {
2752
+ name: "requested_base",
2753
+ docs: [
2754
+ "Estimated base for current epoch's withdrawal requests (reset on process_epoch)",
2755
+ "Manager reads this to know how much to unwind before next epoch"
2756
+ ],
2757
+ type: "u64"
2758
+ },
2759
+ {
2760
+ name: "reserved_base",
2761
+ docs: [
2762
+ "Base earmarked for unclaimed withdrawals (+process_epoch, -claim_withdraw)",
2763
+ "Subtracted from NAV so reserved funds don't inflate PPS"
2764
+ ],
2765
+ type: "u64"
2766
+ },
2767
+ {
2768
+ name: "epoch_pps",
2769
+ docs: [
2770
+ "PPS locked at first process_epoch batch (0 = not set, reset on epoch advance)"
2771
+ ],
2772
+ type: "u64"
2773
+ },
2774
+ {
2775
+ name: "next_epoch_ts",
2776
+ docs: [
2777
+ "Unix timestamp when current epoch ends"
2778
+ ],
2779
+ type: "u32"
2780
+ },
2781
+ {
2782
+ name: "epoch_sec",
2783
+ docs: [
2784
+ "Epoch duration in seconds"
2785
+ ],
2786
+ type: "u32"
2787
+ },
2788
+ {
2789
+ name: "current_epoch_id",
2790
+ docs: [
2791
+ "Incrementing epoch counter"
2792
+ ],
2793
+ type: "u32"
2794
+ },
2387
2795
  {
2388
2796
  name: "mgmt_fee_bps",
2389
2797
  docs: [
@@ -2418,6 +2826,18 @@ var jlp_d_program_default = {
2418
2826
  "PDA bump seed"
2419
2827
  ],
2420
2828
  type: "u8"
2829
+ },
2830
+ {
2831
+ name: "_padding",
2832
+ docs: [
2833
+ "Alignment padding"
2834
+ ],
2835
+ type: {
2836
+ array: [
2837
+ "u8",
2838
+ 4
2839
+ ]
2840
+ }
2421
2841
  }
2422
2842
  ]
2423
2843
  }
@@ -2475,25 +2895,6 @@ var jlp_d_program_default = {
2475
2895
  ]
2476
2896
  }
2477
2897
  },
2478
- {
2479
- name: "SettleYieldParams",
2480
- docs: [
2481
- "Parameters for settle_yield instruction"
2482
- ],
2483
- type: {
2484
- kind: "struct",
2485
- fields: [
2486
- {
2487
- name: "jlp_rate",
2488
- docs: [
2489
- "Manager-provided JLP rate (8 decimals, e.g., 450000000 = $4.50)",
2490
- "Cross-checked against Pyth oracle, must be within 50 bps tolerance"
2491
- ],
2492
- type: "u64"
2493
- }
2494
- ]
2495
- }
2496
- },
2497
2898
  {
2498
2899
  name: "SettleYieldSkipped",
2499
2900
  docs: [
@@ -2665,120 +3066,253 @@ var jlp_d_program_default = {
2665
3066
  name: "JlxToJlp"
2666
3067
  },
2667
3068
  {
2668
- name: "JlpToJlx"
3069
+ name: "JlpToJlx"
3070
+ }
3071
+ ]
3072
+ }
3073
+ },
3074
+ {
3075
+ name: "SwapJlxJlpParams",
3076
+ docs: [
3077
+ "Parameters for the swap instruction"
3078
+ ],
3079
+ type: {
3080
+ kind: "struct",
3081
+ fields: [
3082
+ {
3083
+ name: "stv_index",
3084
+ docs: [
3085
+ "Which STV this JLP belongs to (0-4: BTC, ETH, SOL, USDC, JupUSD)"
3086
+ ],
3087
+ type: "u8"
3088
+ },
3089
+ {
3090
+ name: "direction",
3091
+ docs: [
3092
+ "Direction of the swap"
3093
+ ],
3094
+ type: {
3095
+ defined: {
3096
+ name: "SwapDirection"
3097
+ }
3098
+ }
3099
+ },
3100
+ {
3101
+ name: "amount_in",
3102
+ docs: [
3103
+ "Amount of input token being swapped"
3104
+ ],
3105
+ type: "u64"
3106
+ },
3107
+ {
3108
+ name: "expected_amount_out",
3109
+ docs: [
3110
+ "Expected output amount (used for devnet mock, verified on mainnet)"
3111
+ ],
3112
+ type: "u64"
3113
+ },
3114
+ {
3115
+ name: "jupiter_data",
3116
+ docs: [
3117
+ "Jupiter swap instruction data (includes discriminator and route)",
3118
+ "This is obtained from Jupiter API off-chain",
3119
+ "On devnet (with `devnet` feature), this can be empty"
3120
+ ],
3121
+ type: "bytes"
3122
+ }
3123
+ ]
3124
+ }
3125
+ },
3126
+ {
3127
+ name: "UpdateStvParams",
3128
+ docs: [
3129
+ "Parameters for updating an STV"
3130
+ ],
3131
+ type: {
3132
+ kind: "struct",
3133
+ fields: [
3134
+ {
3135
+ name: "mgmt_fee_bps",
3136
+ docs: [
3137
+ "Management fee in basis points (annual)"
3138
+ ],
3139
+ type: "u16"
3140
+ },
3141
+ {
3142
+ name: "perf_fee_bps",
3143
+ docs: [
3144
+ "Performance fee in basis points"
3145
+ ],
3146
+ type: "u16"
3147
+ },
3148
+ {
3149
+ name: "flags",
3150
+ docs: [
3151
+ "STV state flags"
3152
+ ],
3153
+ type: "u16"
3154
+ },
3155
+ {
3156
+ name: "max_deposit",
3157
+ docs: [
3158
+ "Maximum deposit amount in base asset (0 = unlimited)"
3159
+ ],
3160
+ type: "u64"
3161
+ },
3162
+ {
3163
+ name: "min_deposit",
3164
+ docs: [
3165
+ "Minimum deposit amount in base asset (0 = no minimum)"
3166
+ ],
3167
+ type: "u64"
3168
+ },
3169
+ {
3170
+ name: "jl_mint",
3171
+ docs: [
3172
+ "Optional new jl_mint for migrating base-only pools to Jupiter Lend"
3173
+ ],
3174
+ type: {
3175
+ option: "pubkey"
3176
+ }
3177
+ },
3178
+ {
3179
+ name: "pps",
3180
+ docs: [
3181
+ "Override price per share (9 decimals, e.g. 1_000_000_000 = 1.0)"
3182
+ ],
3183
+ type: {
3184
+ option: "u64"
3185
+ }
3186
+ },
3187
+ {
3188
+ name: "hwm",
3189
+ docs: [
3190
+ "Override high water mark (9 decimals)"
3191
+ ],
3192
+ type: {
3193
+ option: "u64"
3194
+ }
3195
+ },
3196
+ {
3197
+ name: "base_loaned",
3198
+ docs: [
3199
+ "Override base_loaned accounting field"
3200
+ ],
3201
+ type: {
3202
+ option: "u64"
3203
+ }
3204
+ },
3205
+ {
3206
+ name: "epoch_sec",
3207
+ docs: [
3208
+ "Optional new epoch duration in seconds"
3209
+ ],
3210
+ type: {
3211
+ option: "u32"
3212
+ }
2669
3213
  }
2670
3214
  ]
2671
3215
  }
2672
3216
  },
2673
3217
  {
2674
- name: "SwapJlxJlpParams",
2675
- docs: [
2676
- "Parameters for the swap instruction"
2677
- ],
3218
+ name: "WithdrawClaimed",
2678
3219
  type: {
2679
3220
  kind: "struct",
2680
3221
  fields: [
2681
3222
  {
2682
- name: "stv_index",
2683
- docs: [
2684
- "Which STV this JLP belongs to (0-4: BTC, ETH, SOL, USDC, JupUSD)"
2685
- ],
2686
- type: "u8"
3223
+ name: "stv",
3224
+ type: "pubkey"
2687
3225
  },
2688
3226
  {
2689
- name: "direction",
2690
- docs: [
2691
- "Direction of the swap"
2692
- ],
2693
- type: {
2694
- defined: {
2695
- name: "SwapDirection"
2696
- }
2697
- }
3227
+ name: "user",
3228
+ type: "pubkey"
2698
3229
  },
2699
3230
  {
2700
- name: "amount_in",
2701
- docs: [
2702
- "Amount of input token being swapped"
2703
- ],
3231
+ name: "shares",
2704
3232
  type: "u64"
2705
3233
  },
2706
3234
  {
2707
- name: "expected_amount_out",
2708
- docs: [
2709
- "Expected output amount (used for devnet mock, verified on mainnet)"
2710
- ],
3235
+ name: "base_amount",
2711
3236
  type: "u64"
2712
3237
  },
2713
3238
  {
2714
- name: "jupiter_data",
2715
- docs: [
2716
- "Jupiter swap instruction data (includes discriminator and route)",
2717
- "This is obtained from Jupiter API off-chain",
2718
- "On devnet (with `devnet` feature), this can be empty"
2719
- ],
2720
- type: "bytes"
3239
+ name: "epoch_id",
3240
+ type: "u32"
2721
3241
  }
2722
3242
  ]
2723
3243
  }
2724
3244
  },
2725
3245
  {
2726
- name: "UpdateStvParams",
3246
+ name: "WithdrawRequest",
2727
3247
  docs: [
2728
- "Parameters for updating an STV"
3248
+ "WithdrawRequest - Per-user per-epoch withdrawal request",
3249
+ 'Seeds: ["withdraw_request", stv.key(), user.key(), &epoch_id.to_le_bytes()]',
3250
+ "",
3251
+ "One PDA per user per STV per epoch. Multiple request_withdraw calls",
3252
+ "in the same epoch accumulate into the same PDA.",
3253
+ "",
3254
+ "Lifecycle:",
3255
+ "1. Created by request_withdraw (user escrows jvX into request's ATA)",
3256
+ "2. Processed by process_epoch (jvX burned, pps + claim_available_after set)",
3257
+ "3. Closed by claim_withdraw (base transferred, PDA + ATA closed)"
2729
3258
  ],
2730
3259
  type: {
2731
3260
  kind: "struct",
2732
3261
  fields: [
2733
3262
  {
2734
- name: "mgmt_fee_bps",
3263
+ name: "stv",
2735
3264
  docs: [
2736
- "Management fee in basis points (annual)"
3265
+ "Back-reference to the STV"
2737
3266
  ],
2738
- type: "u16"
3267
+ type: "pubkey"
2739
3268
  },
2740
3269
  {
2741
- name: "perf_fee_bps",
3270
+ name: "user",
2742
3271
  docs: [
2743
- "Performance fee in basis points"
3272
+ "The user who requested the withdrawal"
2744
3273
  ],
2745
- type: "u16"
3274
+ type: "pubkey"
2746
3275
  },
2747
3276
  {
2748
- name: "flags",
3277
+ name: "shares",
2749
3278
  docs: [
2750
- "STV state flags"
3279
+ "Total jvX shares escrowed (accumulated across multiple requests in same epoch)"
2751
3280
  ],
2752
- type: "u16"
3281
+ type: "u64"
2753
3282
  },
2754
3283
  {
2755
- name: "max_deposit",
3284
+ name: "pps",
2756
3285
  docs: [
2757
- "Maximum deposit amount in base asset (0 = unlimited)"
3286
+ "PPS at process time (0 = unprocessed)"
2758
3287
  ],
2759
3288
  type: "u64"
2760
3289
  },
2761
3290
  {
2762
- name: "min_deposit",
3291
+ name: "epoch_id",
2763
3292
  docs: [
2764
- "Minimum deposit amount in base asset (0 = no minimum)"
3293
+ "Epoch when request was made"
2765
3294
  ],
2766
- type: "u64"
3295
+ type: "u32"
2767
3296
  },
2768
3297
  {
2769
- name: "jl_mint",
3298
+ name: "claim_available_after",
2770
3299
  docs: [
2771
- "Optional new jl_mint for migrating base-only pools to Jupiter Lend"
3300
+ "Unix timestamp after which claim is available (0 = unprocessed)"
2772
3301
  ],
2773
- type: {
2774
- option: "pubkey"
2775
- }
3302
+ type: "u32"
3303
+ },
3304
+ {
3305
+ name: "bump",
3306
+ docs: [
3307
+ "PDA bump seed"
3308
+ ],
3309
+ type: "u8"
2776
3310
  }
2777
3311
  ]
2778
3312
  }
2779
3313
  },
2780
3314
  {
2781
- name: "Withdrawn",
3315
+ name: "WithdrawRequested",
2782
3316
  type: {
2783
3317
  kind: "struct",
2784
3318
  fields: [
@@ -2791,19 +3325,16 @@ var jlp_d_program_default = {
2791
3325
  type: "pubkey"
2792
3326
  },
2793
3327
  {
2794
- name: "shares_burned",
3328
+ name: "shares",
2795
3329
  type: "u64"
2796
3330
  },
2797
3331
  {
2798
- name: "amount_base",
2799
- docs: [
2800
- "Amount of base asset withdrawn"
2801
- ],
3332
+ name: "total_shares",
2802
3333
  type: "u64"
2803
3334
  },
2804
3335
  {
2805
- name: "pps",
2806
- type: "u64"
3336
+ name: "epoch_id",
3337
+ type: "u32"
2807
3338
  }
2808
3339
  ]
2809
3340
  }
@@ -2838,6 +3369,7 @@ var JUPITER_SWAP_PROGRAM_ID = new PublicKey(
2838
3369
  );
2839
3370
  var SEED_JLP_VAULT = "jlp_vault";
2840
3371
  var SEED_STV = "stv";
3372
+ var SEED_WITHDRAW_REQUEST = "withdraw_request";
2841
3373
  var FLAG_PAUSED = 1;
2842
3374
  var FLAG_DEPOSITS_DISABLED = 2;
2843
3375
  var FLAG_WITHDRAWALS_DISABLED = 4;
@@ -2865,15 +3397,16 @@ var ORACLES = {
2865
3397
  // Doves oracles (Jupiter Perps oracle system)
2866
3398
  DOVES_BTC_USD: new PublicKey("4HBbPx9QJdjJ7GUe6bsiJjGybvfpDhQMMPXP1UEa7VT5"),
2867
3399
  DOVES_ETH_USD: new PublicKey("5URYohbPy32nxK1t3jAHVNfdWY2xTubHiFvLrE3VhXEp"),
2868
- DOVES_SOL_USD: new PublicKey("39cWjvHrpHNz2SbXv6ME4NPhqBDBd4KsjUYv5JkHEAJU"),
2869
- // Pyth oracle for JLP price
2870
- PYTH_JLP_USD: new PublicKey("2TTGSRSezqFzeLUH8JwRUbtN66XLLaymfYsWRTMjfiMw")
3400
+ DOVES_SOL_USD: new PublicKey("39cWjvHrpHNz2SbXv6ME4NPhqBDBd4KsjUYv5JkHEAJU")
2871
3401
  };
3402
+ var JLP_POOL_PUBKEY = new PublicKey("5BUwFW4nRbftYTDMbgxykoFWqWHPzahFSNAaaaJtVKsq");
3403
+ var JUPITER_PERPS_PROGRAM_ID = new PublicKey("PERPHjGBqRHArX4DySjwM6UJHiR3sWAatqfdBS2qQJu");
2872
3404
 
2873
3405
  // src/accounts/pdas.ts
2874
3406
  import { PublicKey as PublicKey2 } from "@solana/web3.js";
2875
3407
  var SEED_JLP_VAULT_BUFFER = Buffer.from(SEED_JLP_VAULT);
2876
3408
  var SEED_STV_BUFFER = Buffer.from(SEED_STV);
3409
+ var SEED_WITHDRAW_REQUEST_BUFFER = Buffer.from(SEED_WITHDRAW_REQUEST);
2877
3410
  var pdaCache = /* @__PURE__ */ new Map();
2878
3411
  function deriveVaultPda(programId) {
2879
3412
  const key = `vault:${programId.toBase58()}`;
@@ -2899,6 +3432,20 @@ function deriveStvPda(baseMint, programId) {
2899
3432
  }
2900
3433
  return cached;
2901
3434
  }
3435
+ function deriveWithdrawRequestPda(stvPda, user, epochId, programId) {
3436
+ const key = `wr:${stvPda.toBase58()}:${user.toBase58()}:${epochId}:${programId.toBase58()}`;
3437
+ let cached = pdaCache.get(key);
3438
+ if (!cached) {
3439
+ const epochIdBuffer = Buffer.alloc(4);
3440
+ epochIdBuffer.writeUInt32LE(epochId);
3441
+ cached = PublicKey2.findProgramAddressSync(
3442
+ [SEED_WITHDRAW_REQUEST_BUFFER, stvPda.toBuffer(), user.toBuffer(), epochIdBuffer],
3443
+ programId
3444
+ );
3445
+ pdaCache.set(key, cached);
3446
+ }
3447
+ return cached;
3448
+ }
2902
3449
  function clearPdaCache() {
2903
3450
  pdaCache.clear();
2904
3451
  }
@@ -2977,7 +3524,7 @@ function parseVault(data) {
2977
3524
  // src/accounts/stv.ts
2978
3525
  import { PublicKey as PublicKey4 } from "@solana/web3.js";
2979
3526
  import { BN as BN2 } from "@coral-xyz/anchor";
2980
- var STV_DATA_SIZE = 160;
3527
+ var STV_DATA_SIZE = 200;
2981
3528
  var STV_ACCOUNT_SIZE = 8 + STV_DATA_SIZE;
2982
3529
  var STV_DISCRIMINATOR = Buffer.from([
2983
3530
  214,
@@ -3022,6 +3569,18 @@ function parseStv(data) {
3022
3569
  offset += 8;
3023
3570
  const minDeposit = new BN2(data.subarray(offset, offset + 8), "le");
3024
3571
  offset += 8;
3572
+ const requestedBase = new BN2(data.subarray(offset, offset + 8), "le");
3573
+ offset += 8;
3574
+ const reservedBase = new BN2(data.subarray(offset, offset + 8), "le");
3575
+ offset += 8;
3576
+ const epochPps = new BN2(data.subarray(offset, offset + 8), "le");
3577
+ offset += 8;
3578
+ const nextEpochTs = data.readUInt32LE(offset);
3579
+ offset += 4;
3580
+ const epochSec = data.readUInt32LE(offset);
3581
+ offset += 4;
3582
+ const currentEpochId = data.readUInt32LE(offset);
3583
+ offset += 4;
3025
3584
  const mgmtFeeBps = data.readUInt16LE(offset);
3026
3585
  offset += 2;
3027
3586
  const perfFeeBps = data.readUInt16LE(offset);
@@ -3031,7 +3590,6 @@ function parseStv(data) {
3031
3590
  const version = data.readUInt8(offset);
3032
3591
  offset += 1;
3033
3592
  const bump = data.readUInt8(offset);
3034
- offset += 1;
3035
3593
  return {
3036
3594
  baseMint,
3037
3595
  jlMint,
@@ -3043,6 +3601,12 @@ function parseStv(data) {
3043
3601
  accruedFeesJlx,
3044
3602
  maxDeposit,
3045
3603
  minDeposit,
3604
+ requestedBase,
3605
+ reservedBase,
3606
+ epochPps,
3607
+ nextEpochTs,
3608
+ epochSec,
3609
+ currentEpochId,
3046
3610
  mgmtFeeBps,
3047
3611
  perfFeeBps,
3048
3612
  flags,
@@ -3093,9 +3657,13 @@ var EXCHANGE_RATE_PRECISION_BI = BigInt(EXCHANGE_RATE_PRECISION);
3093
3657
  var RETURN_PERCENT_PRECISION = EXCHANGE_RATE_PRECISION_BI * 100n;
3094
3658
  var SECONDS_PER_YEAR = BigInt(365 * 24 * 60 * 60);
3095
3659
  var MAX_REWARDS_RATE = 50n * EXCHANGE_RATE_PRECISION_BI;
3096
- function calculateNav(stvBaseBalance, stvJlxBalance, exchangeRate, baseLoaned) {
3660
+ function calculateNav(stvBaseBalance, stvJlxBalance, exchangeRate, baseLoaned, reservedBase) {
3097
3661
  const jlxValue = stvJlxBalance.mul(new BN3(exchangeRate.toString())).div(EXCHANGE_RATE_PRECISION_BN);
3098
- return stvBaseBalance.add(jlxValue).add(baseLoaned);
3662
+ let nav = stvBaseBalance.add(jlxValue).add(baseLoaned);
3663
+ if (reservedBase && !reservedBase.isZero()) {
3664
+ nav = nav.sub(reservedBase);
3665
+ }
3666
+ return nav;
3099
3667
  }
3100
3668
  function calculatePps(nav, jvSupply) {
3101
3669
  if (jvSupply.isZero()) {
@@ -3545,7 +4113,8 @@ async function createInitializeStvInstruction(program, params, accounts) {
3545
4113
  mgmtFeeBps: params.mgmtFeeBps,
3546
4114
  perfFeeBps: params.perfFeeBps,
3547
4115
  maxDeposit: params.maxDeposit,
3548
- minDeposit: params.minDeposit
4116
+ minDeposit: params.minDeposit,
4117
+ epochSec: params.epochSec
3549
4118
  }).accounts({
3550
4119
  admin: accounts.admin,
3551
4120
  jlpVault: accounts.jlpVault,
@@ -3565,7 +4134,8 @@ async function createUpdateStvInstruction(program, params, accounts) {
3565
4134
  jlMint: params.jlMint,
3566
4135
  pps: params.pps,
3567
4136
  hwm: params.hwm,
3568
- baseLoaned: params.baseLoaned
4137
+ baseLoaned: params.baseLoaned,
4138
+ epochSec: params.epochSec
3569
4139
  }).accounts({
3570
4140
  admin: accounts.admin,
3571
4141
  jlpVault: accounts.jlpVault,
@@ -3589,20 +4159,32 @@ async function createDepositInstruction(program, amount, accounts, remainingAcco
3589
4159
  tokenProgram: accounts.tokenProgram
3590
4160
  }).remainingAccounts(remainingAccounts).instruction();
3591
4161
  }
3592
- async function createWithdrawInstruction(program, sharesToBurn, accounts, remainingAccounts = []) {
3593
- return await program.methods.withdraw(sharesToBurn).accounts({
4162
+ async function createRequestWithdrawInstruction(program, params, accounts) {
4163
+ return await program.methods.requestWithdraw(params.shares, params.epochId).accounts({
3594
4164
  user: accounts.user,
3595
4165
  jlpVault: accounts.jlpVault,
3596
4166
  stv: accounts.stv,
4167
+ jvMint: accounts.jvMint,
4168
+ userJvxAta: accounts.userJvxAta,
4169
+ withdrawRequest: accounts.withdrawRequest,
4170
+ requestJvxAta: accounts.requestJvxAta,
4171
+ tokenProgram: accounts.tokenProgram,
4172
+ associatedTokenProgram: accounts.associatedTokenProgram,
4173
+ systemProgram: accounts.systemProgram
4174
+ }).instruction();
4175
+ }
4176
+ async function createClaimWithdrawInstruction(program, accounts) {
4177
+ return await program.methods.claimWithdraw().accounts({
4178
+ user: accounts.user,
4179
+ stv: accounts.stv,
3597
4180
  baseMint: accounts.baseMint,
3598
- jlMint: accounts.jlMint,
3599
4181
  jvMint: accounts.jvMint,
3600
4182
  userBaseAta: accounts.userBaseAta,
3601
- userJvxAta: accounts.userJvxAta,
3602
4183
  stvBaseAta: accounts.stvBaseAta,
3603
- stvJlxAta: accounts.stvJlxAta,
4184
+ withdrawRequest: accounts.withdrawRequest,
4185
+ requestJvxAta: accounts.requestJvxAta,
3604
4186
  tokenProgram: accounts.tokenProgram
3605
- }).remainingAccounts(remainingAccounts).instruction();
4187
+ }).instruction();
3606
4188
  }
3607
4189
 
3608
4190
  // src/instructions/manager.ts
@@ -3644,24 +4226,6 @@ async function createMoveJlxInstruction(program, params, accounts, remainingAcco
3644
4226
  tokenProgram: accounts.tokenProgram
3645
4227
  }).remainingAccounts(remainingAccounts).instruction();
3646
4228
  }
3647
- async function createSwapJlxJlxInstruction(program, params, accounts, remainingAccounts = []) {
3648
- return await program.methods.swapJlxJlx({
3649
- fromIndex: params.fromIndex,
3650
- toIndex: params.toIndex,
3651
- amountIn: params.amountIn,
3652
- minOut: params.minOut,
3653
- jupiterData: params.jupiterData
3654
- }).accounts({
3655
- manager: accounts.manager,
3656
- jlpVault: accounts.jlpVault,
3657
- fromJlxMint: accounts.fromJlxMint,
3658
- toJlxMint: accounts.toJlxMint,
3659
- fromJlxAta: accounts.fromJlxAta,
3660
- toJlxAta: accounts.toJlxAta,
3661
- tokenProgram: accounts.tokenProgram,
3662
- jupiterProgram: accounts.jupiterProgram
3663
- }).remainingAccounts(remainingAccounts).instruction();
3664
- }
3665
4229
  async function createSwapJlxJlpInstruction(program, params, accounts, remainingAccounts = []) {
3666
4230
  return await program.methods.swapJlxToFromJlp({
3667
4231
  stvIndex: params.stvIndex,
@@ -3679,10 +4243,21 @@ async function createSwapJlxJlpInstruction(program, params, accounts, remainingA
3679
4243
  jupiterProgram: accounts.jupiterProgram
3680
4244
  }).remainingAccounts(remainingAccounts).instruction();
3681
4245
  }
4246
+ async function createProcessEpochInstruction(program, accounts, remainingAccounts = []) {
4247
+ return await program.methods.processEpoch().accounts({
4248
+ payer: accounts.payer,
4249
+ jlpVault: accounts.jlpVault,
4250
+ stv: accounts.stv,
4251
+ baseMint: accounts.baseMint,
4252
+ jlMint: accounts.jlMint,
4253
+ jvMint: accounts.jvMint,
4254
+ stvBaseAta: accounts.stvBaseAta,
4255
+ stvJlxAta: accounts.stvJlxAta,
4256
+ tokenProgram: accounts.tokenProgram
4257
+ }).remainingAccounts(remainingAccounts).instruction();
4258
+ }
3682
4259
  async function createSettleYieldInstruction(program, params, accounts, remainingAccounts = []) {
3683
- return await program.methods.settleYield({
3684
- jlpRate: params.jlpRate
3685
- }).accounts({
4260
+ return await program.methods.settleYield().accounts({
3686
4261
  jlpVault: accounts.jlpVault,
3687
4262
  vaultJlpAta: accounts.vaultJlpAta,
3688
4263
  stv0: accounts.stvBtc,
@@ -3698,7 +4273,8 @@ async function createSettleYieldInstruction(program, params, accounts, remaining
3698
4273
  dovesBtcUsd: accounts.oracleBtc,
3699
4274
  dovesEthUsd: accounts.oracleEth,
3700
4275
  dovesSolUsd: accounts.oracleSol,
3701
- pythJlpUsd: accounts.oracleJlp,
4276
+ jlpPool: accounts.jlpPool,
4277
+ jlpMintAccount: accounts.jlpMintAccount,
3702
4278
  manager: accounts.manager
3703
4279
  }).remainingAccounts(remainingAccounts).instruction();
3704
4280
  }
@@ -3969,8 +4545,8 @@ var PoolContext = class {
3969
4545
  }).compileToV0Message();
3970
4546
  return new VersionedTransaction(message);
3971
4547
  }
3972
- // Burn jvX shares and withdraw base asset
3973
- async withdraw(params) {
4548
+ // Request withdrawal: escrow jvX shares for the current epoch
4549
+ async requestWithdraw(params) {
3974
4550
  if (params.shares.isZero() || params.shares.isNeg()) {
3975
4551
  throw new JlpdClientError("Withdraw shares must be positive");
3976
4552
  }
@@ -3979,28 +4555,66 @@ var PoolContext = class {
3979
4555
  this.client.connection.getLatestBlockhash("confirmed")
3980
4556
  ]);
3981
4557
  if (!stv) throw new JlpdClientError("STV not found");
4558
+ const epochId = stv.currentEpochId;
4559
+ const [withdrawRequestPda] = deriveWithdrawRequestPda(
4560
+ this.stvPda,
4561
+ params.user,
4562
+ epochId,
4563
+ this.client.programId
4564
+ );
4565
+ const requestJvxAta = getAssociatedTokenAddressSync2(stv.jvMint, withdrawRequestPda, true);
3982
4566
  const userAtas = deriveUserAtas(this.pool.mint, stv.jvMint, params.user);
3983
- const erAccounts = this.pool.hasJupiterLend ? buildExchangeRateAccounts(this.pool) : null;
3984
- const ix = await createWithdrawInstruction(
4567
+ const ix = await createRequestWithdrawInstruction(
3985
4568
  this.client.program,
3986
- params.shares,
4569
+ { shares: params.shares, epochId },
3987
4570
  {
3988
4571
  user: params.user,
3989
4572
  jlpVault: this.client.vaultPda,
3990
4573
  stv: this.stvPda,
4574
+ jvMint: stv.jvMint,
4575
+ userJvxAta: userAtas.jvxAta,
4576
+ withdrawRequest: withdrawRequestPda,
4577
+ requestJvxAta,
4578
+ tokenProgram: TOKEN_PROGRAM_ID2,
4579
+ associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID2,
4580
+ systemProgram: SystemProgram2.programId
4581
+ }
4582
+ );
4583
+ const message = new TransactionMessage({
4584
+ payerKey: params.user,
4585
+ recentBlockhash: blockhash,
4586
+ instructions: [ix]
4587
+ }).compileToV0Message();
4588
+ return new VersionedTransaction(message);
4589
+ }
4590
+ // Claim withdrawal: receive base tokens for a processed WithdrawRequest
4591
+ async claimWithdraw(params) {
4592
+ const [stv, { blockhash }] = await Promise.all([
4593
+ this.client.fetchStv(this.pool.mint),
4594
+ this.client.connection.getLatestBlockhash("confirmed")
4595
+ ]);
4596
+ if (!stv) throw new JlpdClientError("STV not found");
4597
+ const [withdrawRequestPda] = deriveWithdrawRequestPda(
4598
+ this.stvPda,
4599
+ params.user,
4600
+ params.epochId,
4601
+ this.client.programId
4602
+ );
4603
+ const requestJvxAta = getAssociatedTokenAddressSync2(stv.jvMint, withdrawRequestPda, true);
4604
+ const userAtas = deriveUserAtas(this.pool.mint, stv.jvMint, params.user);
4605
+ const ix = await createClaimWithdrawInstruction(
4606
+ this.client.program,
4607
+ {
4608
+ user: params.user,
4609
+ stv: this.stvPda,
3991
4610
  baseMint: this.pool.mint,
3992
- jlMint: this.pool.fTokenMint,
3993
4611
  jvMint: stv.jvMint,
3994
4612
  userBaseAta: userAtas.baseAta,
3995
- userJvxAta: userAtas.jvxAta,
3996
4613
  stvBaseAta: this.stvBaseAta,
3997
- stvJlxAta: this.stvJlxAta,
4614
+ withdrawRequest: withdrawRequestPda,
4615
+ requestJvxAta,
3998
4616
  tokenProgram: TOKEN_PROGRAM_ID2
3999
- },
4000
- erAccounts ? [
4001
- { pubkey: erAccounts.lending, isSigner: false, isWritable: false },
4002
- { pubkey: erAccounts.rewardsRateModel, isSigner: false, isWritable: false }
4003
- ] : []
4617
+ }
4004
4618
  );
4005
4619
  const message = new TransactionMessage({
4006
4620
  payerKey: params.user,
@@ -4104,7 +4718,8 @@ var PoolContext = class {
4104
4718
  jlMint: params.jlMint ?? null,
4105
4719
  pps: params.pps ?? null,
4106
4720
  hwm: params.hwm ?? null,
4107
- baseLoaned: params.baseLoaned ?? null
4721
+ baseLoaned: params.baseLoaned ?? null,
4722
+ epochSec: params.epochSec ?? null
4108
4723
  },
4109
4724
  {
4110
4725
  admin: params.admin,
@@ -4191,83 +4806,6 @@ var SwapContext = class {
4191
4806
  }).compileToV0Message(params.quote.addressLookupTables);
4192
4807
  return new VersionedTransaction(message);
4193
4808
  }
4194
- // Get a quote for jlX <-> jlX swap
4195
- async quoteJlxJlx(params) {
4196
- const fromPoolConfig = getPoolByName(params.fromPool);
4197
- const toPoolConfig = getPoolByName(params.toPool);
4198
- if (!fromPoolConfig) throw new JlpdClientError(`Unknown pool: ${params.fromPool}`);
4199
- if (!toPoolConfig) throw new JlpdClientError(`Unknown pool: ${params.toPool}`);
4200
- const inputMint = fromPoolConfig.fTokenMint;
4201
- const outputMint = toPoolConfig.fTokenMint;
4202
- const quote = await getJupiterQuote(
4203
- inputMint,
4204
- outputMint,
4205
- BigInt(params.amountIn.toString()),
4206
- params.slippageBps ?? 30,
4207
- 40,
4208
- this.client.jupiterApiKey
4209
- );
4210
- const swapIxs = await getJupiterSwapInstructions(quote, this.client.vaultPda, this.client.jupiterApiKey);
4211
- const remainingAccounts = parseSwapRemainingAccounts(swapIxs.swapInstruction);
4212
- const alts = await fetchAddressLookupTables(
4213
- this.client.connection,
4214
- swapIxs.addressLookupTableAddresses
4215
- );
4216
- return {
4217
- inputMint,
4218
- outputMint,
4219
- inAmount: new BN5(quote.inAmount),
4220
- outAmount: new BN5(quote.outAmount),
4221
- minOutAmount: new BN5(quote.otherAmountThreshold),
4222
- priceImpactPct: parseFloat(quote.priceImpactPct),
4223
- route: quote.routePlan.map((r) => r.swapInfo.label || "unknown"),
4224
- jupiterData: Buffer.from(swapIxs.swapInstruction.data, "base64"),
4225
- remainingAccounts,
4226
- addressLookupTables: alts,
4227
- computeUnitLimit: swapIxs.computeUnitLimit ?? 6e5
4228
- };
4229
- }
4230
- // Build jlX <-> jlX swap transaction
4231
- async swapJlxJlx(params) {
4232
- const fromPoolConfig = getPoolByName(params.fromPool);
4233
- const toPoolConfig = getPoolByName(params.toPool);
4234
- if (!fromPoolConfig) throw new JlpdClientError(`Unknown pool: ${params.fromPool}`);
4235
- if (!toPoolConfig) throw new JlpdClientError(`Unknown pool: ${params.toPool}`);
4236
- const fromPoolCtx = this.client.pool(params.fromPool);
4237
- const toPoolCtx = this.client.pool(params.toPool);
4238
- const computeIx = ComputeBudgetProgram.setComputeUnitLimit({
4239
- units: params.quote.computeUnitLimit
4240
- });
4241
- const jupiterProgram = JUPITER_SWAP_PROGRAM_ID;
4242
- const swapIx = await createSwapJlxJlxInstruction(
4243
- this.client.program,
4244
- {
4245
- fromIndex: fromPoolConfig.stvIndex,
4246
- toIndex: toPoolConfig.stvIndex,
4247
- amountIn: params.amountIn,
4248
- minOut: params.minOut,
4249
- jupiterData: params.quote.jupiterData
4250
- },
4251
- {
4252
- manager: params.manager,
4253
- jlpVault: this.client.vaultPda,
4254
- fromJlxMint: fromPoolConfig.fTokenMint,
4255
- toJlxMint: toPoolConfig.fTokenMint,
4256
- fromJlxAta: fromPoolCtx.vaultStagingAta,
4257
- toJlxAta: toPoolCtx.vaultStagingAta,
4258
- tokenProgram: TOKEN_PROGRAM_ID2,
4259
- jupiterProgram
4260
- },
4261
- params.quote.remainingAccounts
4262
- );
4263
- const { blockhash } = await this.client.connection.getLatestBlockhash("confirmed");
4264
- const message = new TransactionMessage({
4265
- payerKey: params.manager,
4266
- recentBlockhash: blockhash,
4267
- instructions: [computeIx, swapIx]
4268
- }).compileToV0Message(params.quote.addressLookupTables);
4269
- return new VersionedTransaction(message);
4270
- }
4271
4809
  };
4272
4810
  var AdminContext = class {
4273
4811
  constructor(client) {
@@ -4305,7 +4843,8 @@ var AdminContext = class {
4305
4843
  mgmtFeeBps: params.mgmtFeeBps,
4306
4844
  perfFeeBps: params.perfFeeBps,
4307
4845
  maxDeposit: params.maxDeposit,
4308
- minDeposit: params.minDeposit
4846
+ minDeposit: params.minDeposit,
4847
+ epochSec: params.withdrawEpochSec
4309
4848
  },
4310
4849
  {
4311
4850
  admin: params.admin,
@@ -4318,6 +4857,46 @@ var AdminContext = class {
4318
4857
  );
4319
4858
  return this.client.buildTransaction(params.admin, [ix]);
4320
4859
  }
4860
+ // Process epoch for a pool (manager operation)
4861
+ async processEpoch(params) {
4862
+ const pool = getPoolByName(params.poolName);
4863
+ if (!pool) throw new JlpdClientError(`Unknown pool: ${params.poolName}`);
4864
+ const [stvPda] = deriveStvPda(pool.mint, this.client.programId);
4865
+ const stv = await this.client.fetchStv(pool.mint);
4866
+ if (!stv) throw new JlpdClientError(`STV not found for pool: ${params.poolName}`);
4867
+ const stvAtas = deriveStvAtas(pool.mint, pool.fTokenMint, stvPda);
4868
+ const erAccounts = pool.hasJupiterLend ? buildExchangeRateAccounts(pool) : null;
4869
+ const remainingAccounts = [];
4870
+ if (erAccounts) {
4871
+ remainingAccounts.push(
4872
+ { pubkey: erAccounts.lending, isSigner: false, isWritable: false },
4873
+ { pubkey: erAccounts.rewardsRateModel, isSigner: false, isWritable: false }
4874
+ );
4875
+ }
4876
+ for (const wrPubkey of params.withdrawRequests) {
4877
+ const requestJvxAta = getAssociatedTokenAddressSync2(stv.jvMint, wrPubkey, true);
4878
+ remainingAccounts.push(
4879
+ { pubkey: wrPubkey, isSigner: false, isWritable: true },
4880
+ { pubkey: requestJvxAta, isSigner: false, isWritable: true }
4881
+ );
4882
+ }
4883
+ const ix = await createProcessEpochInstruction(
4884
+ this.client.program,
4885
+ {
4886
+ payer: params.payer,
4887
+ jlpVault: this.client.vaultPda,
4888
+ stv: stvPda,
4889
+ baseMint: pool.mint,
4890
+ jlMint: pool.fTokenMint,
4891
+ jvMint: stv.jvMint,
4892
+ stvBaseAta: stvAtas.baseAta,
4893
+ stvJlxAta: stvAtas.jlxAta,
4894
+ tokenProgram: TOKEN_PROGRAM_ID2
4895
+ },
4896
+ remainingAccounts
4897
+ );
4898
+ return this.client.buildTransaction(params.payer, [ix]);
4899
+ }
4321
4900
  // Settle yield across all STVs
4322
4901
  async settleYield(params) {
4323
4902
  const poolNames = ["BTC", "ETH", "SOL", "USDC", "JupUSD"];
@@ -4348,7 +4927,7 @@ var AdminContext = class {
4348
4927
  const remainingAccounts = [...lendingAccounts, ...rewardsAccounts, ...mintAccounts];
4349
4928
  const ix = await createSettleYieldInstruction(
4350
4929
  this.client.program,
4351
- { jlpRate: params.jlpRate },
4930
+ {},
4352
4931
  {
4353
4932
  manager: params.manager,
4354
4933
  jlpVault: this.client.vaultPda,
@@ -4367,13 +4946,58 @@ var AdminContext = class {
4367
4946
  oracleBtc: ORACLES.DOVES_BTC_USD,
4368
4947
  oracleEth: ORACLES.DOVES_ETH_USD,
4369
4948
  oracleSol: ORACLES.DOVES_SOL_USD,
4370
- oracleJlp: ORACLES.PYTH_JLP_USD
4949
+ jlpPool: JLP_POOL_PUBKEY,
4950
+ jlpMintAccount: MINTS.JLP
4371
4951
  },
4372
4952
  remainingAccounts
4373
4953
  );
4374
4954
  return this.client.buildTransaction(params.manager, [ix]);
4375
4955
  }
4376
4956
  };
4957
+
4958
+ // src/accounts/withdraw_request.ts
4959
+ import { PublicKey as PublicKey9 } from "@solana/web3.js";
4960
+ import { BN as BN6 } from "@coral-xyz/anchor";
4961
+ var WITHDRAW_REQUEST_DATA_SIZE = 89;
4962
+ var WITHDRAW_REQUEST_ACCOUNT_SIZE = 8 + WITHDRAW_REQUEST_DATA_SIZE;
4963
+ var WITHDRAW_REQUEST_DISCRIMINATOR = Buffer.from([
4964
+ 186,
4965
+ 239,
4966
+ 174,
4967
+ 191,
4968
+ 189,
4969
+ 13,
4970
+ 47,
4971
+ 196
4972
+ ]);
4973
+ function parseWithdrawRequest(data) {
4974
+ if (data.length < WITHDRAW_REQUEST_ACCOUNT_SIZE) {
4975
+ throw new Error(
4976
+ `Invalid WithdrawRequest data size: expected ${WITHDRAW_REQUEST_ACCOUNT_SIZE}, got ${data.length}`
4977
+ );
4978
+ }
4979
+ const discriminator = data.subarray(0, 8);
4980
+ if (!discriminator.equals(WITHDRAW_REQUEST_DISCRIMINATOR)) {
4981
+ throw new Error(
4982
+ `Invalid WithdrawRequest discriminator: expected ${WITHDRAW_REQUEST_DISCRIMINATOR.toString("hex")}, got ${discriminator.toString("hex")}`
4983
+ );
4984
+ }
4985
+ let offset = 8;
4986
+ const stv = new PublicKey9(data.subarray(offset, offset + 32));
4987
+ offset += 32;
4988
+ const user = new PublicKey9(data.subarray(offset, offset + 32));
4989
+ offset += 32;
4990
+ const shares = new BN6(data.subarray(offset, offset + 8), "le");
4991
+ offset += 8;
4992
+ const pps = new BN6(data.subarray(offset, offset + 8), "le");
4993
+ offset += 8;
4994
+ const epochId = data.readUInt32LE(offset);
4995
+ offset += 4;
4996
+ const claimAvailableAfter = data.readUInt32LE(offset);
4997
+ offset += 4;
4998
+ const bump = data.readUInt8(offset);
4999
+ return { stv, user, shares, pps, epochId, claimAvailableAfter, bump };
5000
+ }
4377
5001
  export {
4378
5002
  AdminContext,
4379
5003
  EXCHANGE_RATE_PRECISION,
@@ -4383,10 +5007,12 @@ export {
4383
5007
  FLAG_REBALANCE_DISABLED,
4384
5008
  FLAG_WITHDRAWALS_DISABLED,
4385
5009
  JLPD_PROGRAM_ID,
5010
+ JLP_POOL_PUBKEY,
4386
5011
  JLP_VAULT_ACCOUNT_SIZE,
4387
5012
  JLP_VAULT_DATA_SIZE,
4388
5013
  JLP_VAULT_DISCRIMINATOR,
4389
5014
  JUPITER_LEND_PROGRAM_ID,
5015
+ JUPITER_PERPS_PROGRAM_ID,
4390
5016
  JUPITER_SWAP_PROGRAM_ID,
4391
5017
  JUPUSD_POOL,
4392
5018
  JUPITER_LEND_PROGRAM_ID2 as JUP_LEND_PROGRAM_ID,
@@ -4402,6 +5028,7 @@ export {
4402
5028
  PoolContext,
4403
5029
  SEED_JLP_VAULT,
4404
5030
  SEED_STV,
5031
+ SEED_WITHDRAW_REQUEST,
4405
5032
  STV_ACCOUNT_SIZE,
4406
5033
  STV_DATA_SIZE,
4407
5034
  STV_DISCRIMINATOR,
@@ -4410,6 +5037,9 @@ export {
4410
5037
  USDC_POOL,
4411
5038
  WBTC_POOL,
4412
5039
  WETH_POOL,
5040
+ WITHDRAW_REQUEST_ACCOUNT_SIZE,
5041
+ WITHDRAW_REQUEST_DATA_SIZE,
5042
+ WITHDRAW_REQUEST_DISCRIMINATOR,
4413
5043
  WSOL_POOL,
4414
5044
  baseToJlx,
4415
5045
  baseToShares,
@@ -4423,23 +5053,25 @@ export {
4423
5053
  clearAtaCache,
4424
5054
  clearPdaCache,
4425
5055
  createClaimFeesInstruction,
5056
+ createClaimWithdrawInstruction,
4426
5057
  createDepositInstruction,
4427
5058
  createInitOrUpdateVaultInstruction,
4428
5059
  createInitializeStvInstruction,
4429
5060
  createJupEarnInstruction,
4430
5061
  createMoveJlxInstruction,
5062
+ createProcessEpochInstruction,
4431
5063
  createProgram,
5064
+ createRequestWithdrawInstruction,
4432
5065
  createSettleYieldInstruction,
4433
5066
  createSwapJlxJlpInstruction,
4434
- createSwapJlxJlxInstruction,
4435
5067
  createUpdateStvInstruction,
4436
- createWithdrawInstruction,
4437
5068
  deriveAta,
4438
5069
  deriveStvAtas,
4439
5070
  deriveStvPda,
4440
5071
  deriveUserAtas,
4441
5072
  deriveVaultAtas,
4442
5073
  deriveVaultPda,
5074
+ deriveWithdrawRequestPda,
4443
5075
  fetchAddressLookupTables,
4444
5076
  fetchJlpRate,
4445
5077
  fetchJupiterPriceUsd,
@@ -4453,5 +5085,6 @@ export {
4453
5085
  parseStv,
4454
5086
  parseSwapRemainingAccounts,
4455
5087
  parseVault,
5088
+ parseWithdrawRequest,
4456
5089
  sharesToBase
4457
5090
  };