@symmetry-hq/sdk 1.0.1

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.
Files changed (121) hide show
  1. package/dist/src/constants.d.ts +23 -0
  2. package/dist/src/constants.js +38 -0
  3. package/dist/src/index.d.ts +804 -0
  4. package/dist/src/index.js +2097 -0
  5. package/dist/src/instructions/automation/auction.d.ts +6 -0
  6. package/dist/src/instructions/automation/auction.js +40 -0
  7. package/dist/src/instructions/automation/claimBounty.d.ts +12 -0
  8. package/dist/src/instructions/automation/claimBounty.js +44 -0
  9. package/dist/src/instructions/automation/flashSwap.d.ts +21 -0
  10. package/dist/src/instructions/automation/flashSwap.js +74 -0
  11. package/dist/src/instructions/automation/priceUpdate.d.ts +19 -0
  12. package/dist/src/instructions/automation/priceUpdate.js +89 -0
  13. package/dist/src/instructions/automation/rebalanceIntent.d.ts +32 -0
  14. package/dist/src/instructions/automation/rebalanceIntent.js +117 -0
  15. package/dist/src/instructions/automation/rebalanceSwap.d.ts +11 -0
  16. package/dist/src/instructions/automation/rebalanceSwap.js +42 -0
  17. package/dist/src/instructions/management/addBounty.d.ts +7 -0
  18. package/dist/src/instructions/management/addBounty.js +41 -0
  19. package/dist/src/instructions/management/admin.d.ts +9 -0
  20. package/dist/src/instructions/management/admin.js +53 -0
  21. package/dist/src/instructions/management/claimFees.d.ts +15 -0
  22. package/dist/src/instructions/management/claimFees.js +95 -0
  23. package/dist/src/instructions/management/createBasket.d.ts +21 -0
  24. package/dist/src/instructions/management/createBasket.js +98 -0
  25. package/dist/src/instructions/management/edit.d.ts +51 -0
  26. package/dist/src/instructions/management/edit.js +477 -0
  27. package/dist/src/instructions/management/luts.d.ts +30 -0
  28. package/dist/src/instructions/management/luts.js +99 -0
  29. package/dist/src/instructions/pda.d.ts +25 -0
  30. package/dist/src/instructions/pda.js +128 -0
  31. package/dist/src/instructions/user/deposit.d.ts +20 -0
  32. package/dist/src/instructions/user/deposit.js +100 -0
  33. package/dist/src/instructions/user/withdraw.d.ts +8 -0
  34. package/dist/src/instructions/user/withdraw.js +36 -0
  35. package/dist/src/jup.d.ts +49 -0
  36. package/dist/src/jup.js +80 -0
  37. package/dist/src/keeperMonitor.d.ts +52 -0
  38. package/dist/src/keeperMonitor.js +624 -0
  39. package/dist/src/layouts/basket.d.ts +191 -0
  40. package/dist/src/layouts/basket.js +51 -0
  41. package/dist/src/layouts/config.d.ts +281 -0
  42. package/dist/src/layouts/config.js +237 -0
  43. package/dist/src/layouts/fraction.d.ts +20 -0
  44. package/dist/src/layouts/fraction.js +164 -0
  45. package/dist/src/layouts/intents/bounty.d.ts +18 -0
  46. package/dist/src/layouts/intents/bounty.js +19 -0
  47. package/dist/src/layouts/intents/intent.d.ts +209 -0
  48. package/dist/src/layouts/intents/intent.js +97 -0
  49. package/dist/src/layouts/intents/rebalanceIntent.d.ts +212 -0
  50. package/dist/src/layouts/intents/rebalanceIntent.js +94 -0
  51. package/dist/src/layouts/lookupTable.d.ts +7 -0
  52. package/dist/src/layouts/lookupTable.js +10 -0
  53. package/dist/src/layouts/oracle.d.ts +63 -0
  54. package/dist/src/layouts/oracle.js +96 -0
  55. package/dist/src/states/basket.d.ts +14 -0
  56. package/dist/src/states/basket.js +479 -0
  57. package/dist/src/states/config.d.ts +3 -0
  58. package/dist/src/states/config.js +71 -0
  59. package/dist/src/states/intents/intent.d.ts +10 -0
  60. package/dist/src/states/intents/intent.js +316 -0
  61. package/dist/src/states/intents/rebalanceIntent.d.ts +42 -0
  62. package/dist/src/states/intents/rebalanceIntent.js +680 -0
  63. package/dist/src/states/oracles/constants.d.ts +9 -0
  64. package/dist/src/states/oracles/constants.js +15 -0
  65. package/dist/src/states/oracles/oracle.d.ts +24 -0
  66. package/dist/src/states/oracles/oracle.js +168 -0
  67. package/dist/src/states/oracles/pythOracle.d.ts +132 -0
  68. package/dist/src/states/oracles/pythOracle.js +609 -0
  69. package/dist/src/states/oracles/raydiumClmmOracle.d.ts +184 -0
  70. package/dist/src/states/oracles/raydiumClmmOracle.js +843 -0
  71. package/dist/src/states/oracles/raydiumCpmmOracle.d.ts +120 -0
  72. package/dist/src/states/oracles/raydiumCpmmOracle.js +540 -0
  73. package/dist/src/states/oracles/switchboardOracle.d.ts +0 -0
  74. package/dist/src/states/oracles/switchboardOracle.js +1 -0
  75. package/dist/src/states/withdrawBasketFees.d.ts +10 -0
  76. package/dist/src/states/withdrawBasketFees.js +154 -0
  77. package/dist/src/txUtils.d.ts +65 -0
  78. package/dist/src/txUtils.js +306 -0
  79. package/dist/test.d.ts +1 -0
  80. package/dist/test.js +561 -0
  81. package/package.json +31 -0
  82. package/src/constants.ts +40 -0
  83. package/src/index.ts +2431 -0
  84. package/src/instructions/automation/auction.ts +55 -0
  85. package/src/instructions/automation/claimBounty.ts +69 -0
  86. package/src/instructions/automation/flashSwap.ts +104 -0
  87. package/src/instructions/automation/priceUpdate.ts +117 -0
  88. package/src/instructions/automation/rebalanceIntent.ts +181 -0
  89. package/src/instructions/management/addBounty.ts +55 -0
  90. package/src/instructions/management/admin.ts +72 -0
  91. package/src/instructions/management/claimFees.ts +129 -0
  92. package/src/instructions/management/createBasket.ts +138 -0
  93. package/src/instructions/management/edit.ts +602 -0
  94. package/src/instructions/management/luts.ts +157 -0
  95. package/src/instructions/pda.ts +151 -0
  96. package/src/instructions/user/deposit.ts +143 -0
  97. package/src/instructions/user/withdraw.ts +53 -0
  98. package/src/jup.ts +113 -0
  99. package/src/keeperMonitor.ts +585 -0
  100. package/src/layouts/basket.ts +233 -0
  101. package/src/layouts/config.ts +576 -0
  102. package/src/layouts/fraction.ts +164 -0
  103. package/src/layouts/intents/bounty.ts +35 -0
  104. package/src/layouts/intents/intent.ts +324 -0
  105. package/src/layouts/intents/rebalanceIntent.ts +306 -0
  106. package/src/layouts/lookupTable.ts +14 -0
  107. package/src/layouts/oracle.ts +157 -0
  108. package/src/states/basket.ts +527 -0
  109. package/src/states/config.ts +62 -0
  110. package/src/states/intents/intent.ts +311 -0
  111. package/src/states/intents/rebalanceIntent.ts +751 -0
  112. package/src/states/oracles/constants.ts +13 -0
  113. package/src/states/oracles/oracle.ts +212 -0
  114. package/src/states/oracles/pythOracle.ts +874 -0
  115. package/src/states/oracles/raydiumClmmOracle.ts +1193 -0
  116. package/src/states/oracles/raydiumCpmmOracle.ts +784 -0
  117. package/src/states/oracles/switchboardOracle.ts +0 -0
  118. package/src/states/withdrawBasketFees.ts +160 -0
  119. package/src/txUtils.ts +424 -0
  120. package/test.ts +609 -0
  121. package/tsconfig.json +101 -0
@@ -0,0 +1,751 @@
1
+ import { Connection, GetProgramAccountsResponse, PublicKey } from "@solana/web3.js";
2
+ import { AuctionData, AuctionTimestamps, ClaimBountyData, DepositData, FormattedRebalanceIntent, MintData, PriceUpdatesData, REBALANCE_ACTION_STRINGS, REBALANCE_TYPE_STRINGS, RebalanceAction, RebalanceIntent, RebalanceIntentLayout, RebalanceType, RedeemData, TokenAuction, UIRebalanceIntent } from "../../layouts/intents/rebalanceIntent";
3
+ import { GetProgramAccountsFilter } from "@solana/web3.js";
4
+ import { BASKETS_V3_PROGRAM_ID, HUNDRED_PERCENT_BPS, MAX_SUPPORTED_TOKENS_PER_BASKET, MAX_TRANSFER_TOKENS } from "../../constants";
5
+ import { Fraction, fractionAdd, fractionDiv, fractionLt, fractionLte, fractionMul, fractionRoundDown, fractionRoundUp, fractionSub, fractionToDecimal } from "../../layouts/fraction";
6
+ import { getMultipleAccountsInfoBatched } from "../../txUtils";
7
+ import BN from "bn.js";
8
+ import { Basket, FormattedBasket } from "../../layouts/basket";
9
+ import { OraclePriceOnChain } from "../../layouts/oracle";
10
+ import { fetchBasket } from "../basket";
11
+
12
+ export function computeRebalanceIntentBountyAmount(
13
+ rebalance_type: RebalanceType,
14
+ num_tokens: number,
15
+ bounty_bond: number,
16
+ bounty_per_task: number,
17
+ bounty_per_price_update_task_max: number,
18
+ ): number {
19
+ let num_tasks = 0;
20
+ num_tasks += 1; // FinishPriceUpdates;
21
+ num_tasks += 1; // CancelRebalance;
22
+ if (rebalance_type == RebalanceType.Deposit) {
23
+ num_tasks += 1; // MintBasket;
24
+ }
25
+ if (rebalance_type == RebalanceType.Deposit || rebalance_type == RebalanceType.Withdraw) {
26
+ num_tasks += num_tokens; // TokenSettlement;
27
+ } else {
28
+ num_tasks += 1; // AuctionCreation;
29
+ }
30
+ let claim_bounty_tasks = (
31
+ num_tasks + MAX_TRANSFER_TOKENS - 1
32
+ ) / MAX_TRANSFER_TOKENS;
33
+
34
+ let price_update_tasks = num_tokens;
35
+ let tasks = num_tasks + claim_bounty_tasks;
36
+
37
+ let bounty_total =
38
+ bounty_per_price_update_task_max * price_update_tasks +
39
+ bounty_per_task * tasks +
40
+ bounty_bond;
41
+
42
+ return bounty_total;
43
+ }
44
+
45
+ export function formatRebalanceIntent(rebalanceIntent: RebalanceIntent, basket?: FormattedBasket): UIRebalanceIntent {
46
+ let numTokens = MAX_SUPPORTED_TOKENS_PER_BASKET;
47
+ while (numTokens > 0 && rebalanceIntent.tokens[numTokens - 1].mint.equals(PublicKey.default))
48
+ numTokens--;
49
+ rebalanceIntent.tokens = rebalanceIntent.tokens.slice(0, numTokens);
50
+ rebalanceIntent.priceUpdateTasks = rebalanceIntent.priceUpdateTasks.slice(0, numTokens);
51
+ rebalanceIntent.tokenSettlementTasks = rebalanceIntent.tokenSettlementTasks.slice(0, numTokens);
52
+ let priceUpdateTasks = [];
53
+ for (let i = 0; i < numTokens; i++) {
54
+ priceUpdateTasks.push({
55
+ completed_by: rebalanceIntent.priceUpdateTasks[i].completedBy.toBase58(),
56
+ completed_bounty: parseInt(rebalanceIntent.priceUpdateTasks[i].completedBounty.toString()),
57
+ completed_time: parseInt(rebalanceIntent.priceUpdateTasks[i].completedTime.toString()),
58
+ });
59
+ }
60
+ let tokenSettlementTasks = [];
61
+ for (let i = 0; i < numTokens; i++) {
62
+ tokenSettlementTasks.push({
63
+ completed_by: rebalanceIntent.tokenSettlementTasks[i].completedBy.toBase58(),
64
+ completed_bounty: parseInt(rebalanceIntent.tokenSettlementTasks[i].completedBounty.toString()),
65
+ completed_time: parseInt(rebalanceIntent.tokenSettlementTasks[i].completedTime.toString()),
66
+ });
67
+ }
68
+ let placeholderTask = {
69
+ completed_by: rebalanceIntent.placeholderTask.completedBy.toBase58(),
70
+ completed_bounty: parseInt(rebalanceIntent.placeholderTask.completedBounty.toString()),
71
+ completed_time: parseInt(rebalanceIntent.placeholderTask.completedTime.toString()),
72
+ };
73
+ let finishPriceUpdateTask = {
74
+ completed_by: rebalanceIntent.finishPriceUpdateTask.completedBy.toBase58(),
75
+ completed_bounty: parseInt(rebalanceIntent.finishPriceUpdateTask.completedBounty.toString()),
76
+ completed_time: parseInt(rebalanceIntent.finishPriceUpdateTask.completedTime.toString()),
77
+ };
78
+ let auctionCreationTask = {
79
+ completed_by: rebalanceIntent.auctionCreationTask.completedBy.toBase58(),
80
+ completed_bounty: parseInt(rebalanceIntent.auctionCreationTask.completedBounty.toString()),
81
+ completed_time: parseInt(rebalanceIntent.auctionCreationTask.completedTime.toString()),
82
+ };
83
+ let mintBasketTask = {
84
+ completed_by: rebalanceIntent.mintBasketTask.completedBy.toBase58(),
85
+ completed_bounty: parseInt(rebalanceIntent.mintBasketTask.completedBounty.toString()),
86
+ completed_time: parseInt(rebalanceIntent.mintBasketTask.completedTime.toString()),
87
+ };
88
+ let cancelRebalanceTask = {
89
+ completed_by: rebalanceIntent.cancelRebalanceTask.completedBy.toBase58(),
90
+ completed_bounty: parseInt(rebalanceIntent.cancelRebalanceTask.completedBounty.toString()),
91
+ completed_time: parseInt(rebalanceIntent.cancelRebalanceTask.completedTime.toString()),
92
+ };
93
+ let tasks = [
94
+ placeholderTask,
95
+ finishPriceUpdateTask,
96
+ auctionCreationTask,
97
+ mintBasketTask,
98
+ cancelRebalanceTask,
99
+ ...tokenSettlementTasks,
100
+ ...priceUpdateTasks,
101
+ ]
102
+ let depositData: DepositData = {
103
+ tokens: rebalanceIntent.tokens.map(token => ({
104
+ mint: token.mint.toBase58(),
105
+ amount: parseInt(token.amount.toString()),
106
+ })),
107
+ }
108
+ let priceUpdatesData: PriceUpdatesData = {
109
+ tokens: rebalanceIntent.priceUpdateTasks.map((task, index) => ({
110
+ mint: rebalanceIntent.tokens[index].mint.toBase58(),
111
+ updated: parseInt(task.completedTime.toString()) > 0 ? true : false,
112
+ price: fractionToDecimal(rebalanceIntent.tokens[index].price.price).toNumber(),
113
+ conf: fractionToDecimal(rebalanceIntent.tokens[index].price.conf).toNumber(),
114
+ expiration: parseInt(task.completedTime.toString()) + 60,
115
+ update_time: parseInt(task.completedTime.toString()),
116
+ })),
117
+ }
118
+ let auctionData: AuctionData = {
119
+ auction_stages: rebalanceIntent.auctions.map(auction => ({
120
+ start_time: parseInt(auction.startTime.toString()),
121
+ end_time: parseInt(auction.endTime.toString()),
122
+ })),
123
+ tokens: rebalanceIntent.tokens.map(token => ({
124
+ mint: token.mint.toBase58(),
125
+ amount: parseInt(token.amount.toString()),
126
+ target_amount: parseInt(token.targetAmount.toString()),
127
+ price: fractionToDecimal(token.price.price).toNumber(),
128
+ conf: fractionToDecimal(token.price.conf).toNumber(),
129
+ })),
130
+ }
131
+ let mintData: MintData = {
132
+ mintAmount: 0,
133
+ mintValue: 0,
134
+ fees: {
135
+ host: 0,
136
+ creator: 0,
137
+ managers: 0,
138
+ symmetry: 0,
139
+ basket: 0,
140
+ },
141
+ tokens: auctionData.tokens.map(token => ({
142
+ mint: token.mint,
143
+ contribution_amount: 0,
144
+ remaining_amount: 0,
145
+ })),
146
+ }
147
+ if (basket) {
148
+ let minRatio = 1;
149
+ for (let i = 0; i < basket.composition.length; i++) {
150
+ if (basket.composition[i].amount == 0)
151
+ continue;
152
+ let ratio = auctionData.tokens[i].amount / basket.composition[i].amount;
153
+ minRatio = Math.min(minRatio, ratio);
154
+ }
155
+ let mintValue = 0;
156
+ let remainingValue = 0;
157
+ let mintAmount = Math.floor(basket.supply_outstanding * minRatio);
158
+ for (let i = 0; i < basket.composition.length; i++) {
159
+ let contributionAmount = Math.floor(basket.composition[i].amount * minRatio);
160
+ contributionAmount = Math.min(contributionAmount, auctionData.tokens[i].amount);
161
+ mintData.tokens[i].contribution_amount = contributionAmount;
162
+ mintData.tokens[i].remaining_amount = auctionData.tokens[i].amount - contributionAmount;
163
+ mintValue += contributionAmount * auctionData.tokens[i].price;
164
+ remainingValue += (auctionData.tokens[i].amount - contributionAmount) * auctionData.tokens[i].price;
165
+ }
166
+ mintData.mintValue = mintValue;
167
+ mintData.mintAmount = mintAmount;
168
+ mintData.fees.host = Math.floor(mintValue * rebalanceIntent.basketFeeSettings.hostDepositFeeBps / HUNDRED_PERCENT_BPS);
169
+ mintData.fees.creator = Math.floor(mintValue * rebalanceIntent.basketFeeSettings.creatorDepositFeeBps / HUNDRED_PERCENT_BPS);
170
+ mintData.fees.managers = Math.floor(mintValue * rebalanceIntent.basketFeeSettings.managersDepositFeeBps / HUNDRED_PERCENT_BPS);
171
+ mintData.fees.basket = Math.floor(mintValue * rebalanceIntent.basketFeeSettings.basketDepositFeeBps / HUNDRED_PERCENT_BPS);
172
+ mintData.fees.symmetry = Math.floor(mintValue * 10 / HUNDRED_PERCENT_BPS);
173
+ mintData.mintAmount -= mintData.fees.host + mintData.fees.creator + mintData.fees.managers + mintData.fees.symmetry + mintData.fees.basket;
174
+ }
175
+ let redeemData: RedeemData = {
176
+ tokens: rebalanceIntent.tokens.map(token => ({
177
+ mint: token.mint.toBase58(),
178
+ amount: parseInt(token.amount.toString()),
179
+ })).filter(token => token.amount > 0),
180
+ }
181
+ let bountyData: ClaimBountyData = {
182
+ bounty_mint: rebalanceIntent.bounty.bountyMint.toBase58(),
183
+ keepers: [],
184
+ unused_bounty: {
185
+ pubkey: rebalanceIntent.bounty.bountyDepositor.toBase58(),
186
+ bounty_amount: parseInt(rebalanceIntent.bounty.bountyLeft.toString()),
187
+ },
188
+ rent: {
189
+ pubkey: rebalanceIntent.rentPayer.toBase58(),
190
+ sol_amount: rebalanceIntent.solBalance ?? 0,
191
+ },
192
+ }
193
+ for (let i = 0; i < tasks.length; i++) {
194
+ if (tasks[i].completed_bounty > 0) {
195
+ let indexOf = bountyData.keepers.findIndex(keeper => keeper.pubkey == tasks[i].completed_by);
196
+ if (indexOf == -1) {
197
+ bountyData.keepers.push({
198
+ pubkey: tasks[i].completed_by,
199
+ bounty_amount: tasks[i].completed_bounty,
200
+ });
201
+ bountyData.unused_bounty.bounty_amount -= tasks[i].completed_bounty;
202
+ } else {
203
+ bountyData.keepers[indexOf].bounty_amount += tasks[i].completed_bounty;
204
+ }
205
+ }
206
+ }
207
+ let formatted: FormattedRebalanceIntent = {
208
+ pubkey: rebalanceIntent.ownAddress!.toBase58(),
209
+ sol_balance: rebalanceIntent.solBalance ?? 0,
210
+ basket: rebalanceIntent.basket.toBase58(),
211
+ owner: rebalanceIntent.owner.toBase58(),
212
+ rent_payer: rebalanceIntent.rentPayer.toBase58(),
213
+ rebalance_type: REBALANCE_TYPE_STRINGS.get(rebalanceIntent.rebalanceType) ?? "basket_custom",
214
+ current_action: REBALANCE_ACTION_STRINGS.get(rebalanceIntent.currentAction) ?? "not_active",
215
+ withdraw_params_burn_amount: parseInt(rebalanceIntent.withdrawParamsBurnAmount.toString()),
216
+ withdraw_params_amount_wo_fees: parseInt(rebalanceIntent.withdrawParamsAmountWoFees.toString()),
217
+ withdraw_params_keep_tokens_bitmask: rebalanceIntent.withdrawParamsKeepTokensBitmask,
218
+ withdraw_params_keep_all_tokens: rebalanceIntent.withdrawParamsKeepAllTokens == 1 ? true : false,
219
+ basket_fee_settings: {
220
+ host_deposit_fee_bps: rebalanceIntent.basketFeeSettings.hostDepositFeeBps,
221
+ host_withdraw_fee_bps: rebalanceIntent.basketFeeSettings.hostWithdrawFeeBps,
222
+ host_management_fee_bps: rebalanceIntent.basketFeeSettings.hostManagementFeeBps,
223
+ host_performance_fee_bps: rebalanceIntent.basketFeeSettings.hostPerformanceFeeBps,
224
+ creator_deposit_fee_bps: rebalanceIntent.basketFeeSettings.creatorDepositFeeBps,
225
+ creator_withdraw_fee_bps: rebalanceIntent.basketFeeSettings.creatorWithdrawFeeBps,
226
+ creator_management_fee_bps: rebalanceIntent.basketFeeSettings.creatorManagementFeeBps,
227
+ creator_performance_fee_bps: rebalanceIntent.basketFeeSettings.creatorPerformanceFeeBps,
228
+ managers_deposit_fee_bps: rebalanceIntent.basketFeeSettings.managersDepositFeeBps,
229
+ managers_withdraw_fee_bps: rebalanceIntent.basketFeeSettings.managersWithdrawFeeBps,
230
+ managers_management_fee_bps: rebalanceIntent.basketFeeSettings.managersManagementFeeBps,
231
+ managers_performance_fee_bps: rebalanceIntent.basketFeeSettings.managersPerformanceFeeBps,
232
+ basket_deposit_fee_bps: rebalanceIntent.basketFeeSettings.basketDepositFeeBps,
233
+ basket_withdraw_fee_bps: rebalanceIntent.basketFeeSettings.basketWithdrawFeeBps,
234
+ modification_delay: parseInt(rebalanceIntent.basketFeeSettings.modificationDelay.toString()),
235
+ updated_at: 0,
236
+ },
237
+ execution_start_time: parseInt(rebalanceIntent.executionStartTime.toString()),
238
+ rebalance_threshold_slippage_bps: rebalanceIntent.rebalanceThresholdSlippageBps,
239
+ per_trade_rebalance_threshold_slippage_bps: rebalanceIntent.perTradeRebalanceThresholdSlippageBps,
240
+ initial_tvl: fractionToDecimal(rebalanceIntent.initialTvl).toNumber(),
241
+ auction_update_timestamp: parseInt(rebalanceIntent.auctionUpdateTimestamp.toString()),
242
+ auctions: rebalanceIntent.auctions.map(auction => ({
243
+ start_time: parseInt(auction.startTime.toString()),
244
+ end_time: parseInt(auction.endTime.toString()),
245
+ })),
246
+ tokens: rebalanceIntent.tokens.map(token => ({
247
+ mint: token.mint.toBase58(),
248
+ amount: parseInt(token.amount.toString()),
249
+ target_amount: parseInt(token.targetAmount.toString()),
250
+ price: {
251
+ price: fractionToDecimal(token.price.price).toNumber(),
252
+ conf: fractionToDecimal(token.price.conf).toNumber(),
253
+ update_time: parseInt(token.price.updateTime.toString()),
254
+ },
255
+ keep_token: token.keepToken == 1 ? true : false,
256
+ })),
257
+ last_action_timestamp: parseInt(rebalanceIntent.lastActionTimestamp.toString()),
258
+ bounty: {
259
+ bounty_depositor: rebalanceIntent.bounty.bountyDepositor.toBase58(),
260
+ bounty_mint: rebalanceIntent.bounty.bountyMint.toBase58(),
261
+ bounty_per_price_update_task: {
262
+ min_bounty: parseInt(rebalanceIntent.bounty.bountyPerPriceUpdateTask.minBounty.toString()),
263
+ max_bounty: parseInt(rebalanceIntent.bounty.bountyPerPriceUpdateTask.maxBounty.toString()),
264
+ min_bounty_until: parseInt(rebalanceIntent.bounty.bountyPerPriceUpdateTask.minBountyUntil.toString()),
265
+ max_bounty_after: parseInt(rebalanceIntent.bounty.bountyPerPriceUpdateTask.maxBountyAfter.toString()),
266
+ },
267
+ bounty_per_task: {
268
+ min_bounty: parseInt(rebalanceIntent.bounty.bountyPerTask.minBounty.toString()),
269
+ max_bounty: parseInt(rebalanceIntent.bounty.bountyPerTask.maxBounty.toString()),
270
+ min_bounty_until: parseInt(rebalanceIntent.bounty.bountyPerTask.minBountyUntil.toString()),
271
+ max_bounty_after: parseInt(rebalanceIntent.bounty.bountyPerTask.maxBountyAfter.toString()),
272
+ },
273
+ bounty_total: parseInt(rebalanceIntent.bounty.bountyTotal.toString()),
274
+ bounty_left: parseInt(rebalanceIntent.bounty.bountyLeft.toString()),
275
+ },
276
+ bounty_adjustment_amount: parseInt(rebalanceIntent.bountyAdjustmentAmount.toString()),
277
+ placeholder_task: placeholderTask,
278
+ price_update_tasks: priceUpdateTasks,
279
+ finish_price_update_task: finishPriceUpdateTask,
280
+ auction_creation_task: auctionCreationTask,
281
+ mint_basket_task: mintBasketTask,
282
+ cancel_rebalance_task: cancelRebalanceTask,
283
+ token_settlement_tasks: tokenSettlementTasks,
284
+ };
285
+ let uiRebalanceIntent: UIRebalanceIntent = {
286
+ rebalance_type: formatted.mint_basket_task.completed_time > 0 ? "deposit" : formatted.rebalance_type,
287
+
288
+ formatted_data: formatted,
289
+ chain_data: rebalanceIntent,
290
+ deposit_data: null,
291
+ price_updates_data: null,
292
+ auction_data: null,
293
+ mint_data: null,
294
+ redeem_data: null,
295
+ claim_bounty_data: null,
296
+ }
297
+
298
+ if (formatted.current_action == "deposit_tokens") {
299
+ uiRebalanceIntent.deposit_data = depositData;
300
+ }
301
+ if (formatted.current_action == "update_prices") {
302
+ uiRebalanceIntent.price_updates_data = priceUpdatesData;
303
+ }
304
+ if (formatted.current_action == "auction") {
305
+ let now = Math.floor(Date.now() / 1000);
306
+ if (now <= auctionData.auction_stages[2].end_time) {
307
+ uiRebalanceIntent.auction_data = auctionData;
308
+ } else {
309
+ if (formatted.rebalance_type == "deposit") {
310
+ uiRebalanceIntent.mint_data = mintData;
311
+ } else
312
+ if (formatted.rebalance_type == "withdraw" && redeemData.tokens.length > 0) {
313
+ uiRebalanceIntent.redeem_data = redeemData;
314
+ } else {
315
+ uiRebalanceIntent.claim_bounty_data = bountyData;
316
+ }
317
+ }
318
+ }
319
+
320
+ return uiRebalanceIntent;
321
+ }
322
+
323
+ export async function fetchRebalanceIntent(
324
+ connection: Connection,
325
+ rebalanceIntentAddress: PublicKey,
326
+ ): Promise<UIRebalanceIntent> {
327
+ const rebalanceIntentAi = await connection.getAccountInfo(rebalanceIntentAddress);
328
+ if (!rebalanceIntentAi) throw new Error("Rebalance intent not found");
329
+ let rebalanceIntent: RebalanceIntent = RebalanceIntentLayout.decode(rebalanceIntentAi.data.slice(8));
330
+ rebalanceIntent.ownAddress = rebalanceIntentAddress;
331
+ rebalanceIntent.solBalance = rebalanceIntentAi.lamports ?? 0;
332
+ let basket = (await fetchBasket(connection, rebalanceIntent.basket)).formatted;
333
+ return formatRebalanceIntent(rebalanceIntent, basket);
334
+ }
335
+
336
+ export async function fetchRebalanceIntentsMultiple(
337
+ connection: Connection,
338
+ rebalanceIntentAddresses: PublicKey[],
339
+ ): Promise<Map<string, UIRebalanceIntent>> {
340
+ let multipleAccountsInfo = await getMultipleAccountsInfoBatched(connection, rebalanceIntentAddresses);
341
+ let rebalanceIntents: RebalanceIntent[] = rebalanceIntentAddresses.map(address => {
342
+ let ai = multipleAccountsInfo.get(address.toBase58());
343
+ if (!ai) return null;
344
+ return { ...RebalanceIntentLayout.decode(ai.data.slice(8)), ownAddress: address, solBalance: ai.lamports ?? 0 }
345
+ }).filter(rebalanceIntent => rebalanceIntent !== null);
346
+ let formattedRebalanceIntents: UIRebalanceIntent[] = rebalanceIntents.map(rebalanceIntent => formatRebalanceIntent(rebalanceIntent));
347
+ let rebalanceIntentsMap: Map<string, UIRebalanceIntent> = new Map();
348
+ for (let rebalanceIntent of formattedRebalanceIntents) rebalanceIntentsMap.set(rebalanceIntent.formatted_data.pubkey, rebalanceIntent);
349
+ return rebalanceIntentsMap;
350
+ }
351
+
352
+ export interface RebalanceIntentFilter {
353
+ type: "basket" | "owner";
354
+ pubkey: string;
355
+ }
356
+
357
+ export async function fetchRebalanceIntents(
358
+ connection: Connection,
359
+ filter?: RebalanceIntentFilter,
360
+ ): Promise<UIRebalanceIntent[]> {
361
+ let accountFilters: GetProgramAccountsFilter[] = [
362
+ { dataSize: 8 + RebalanceIntentLayout.getSpan() },
363
+ ];
364
+ if (filter?.type === "basket") {
365
+ accountFilters.push({ memcmp: {
366
+ offset: 8,
367
+ bytes: filter.pubkey
368
+ } });
369
+ } else if (filter?.type === "owner") {
370
+ accountFilters.push({ memcmp: {
371
+ offset: 8 + 32,
372
+ bytes: filter.pubkey
373
+ } });
374
+ }
375
+ const accounts: GetProgramAccountsResponse = await connection
376
+ .getProgramAccounts(
377
+ BASKETS_V3_PROGRAM_ID,
378
+ {
379
+ commitment: "confirmed",
380
+ filters: accountFilters,
381
+ encoding: 'base64'
382
+ }
383
+ );
384
+ let basket: FormattedBasket | undefined;
385
+ if (filter && filter.type === "basket") {
386
+ basket = (await fetchBasket(connection, new PublicKey(filter.pubkey))).formatted;
387
+ }
388
+ let rebalanceIntents: UIRebalanceIntent[] = accounts.map(account => {
389
+ let rebalanceIntent: RebalanceIntent = RebalanceIntentLayout.decode(account.account.data.slice(8));
390
+ rebalanceIntent.ownAddress = account.pubkey;
391
+ rebalanceIntent.solBalance = account.account.lamports ?? 0;
392
+ return formatRebalanceIntent(rebalanceIntent, basket);
393
+ });
394
+ return rebalanceIntents;
395
+ }
396
+
397
+
398
+ class RebalanceIntentRustClass {
399
+ self: RebalanceIntent;
400
+
401
+ constructor(rebalanceIntent: RebalanceIntent) {
402
+ this.self = rebalanceIntent;
403
+ }
404
+
405
+ findTokenIndex(mint: PublicKey): number | undefined {
406
+ for (let i = 0; i < this.self.priceUpdateTasks.length; i++)
407
+ if (this.self.tokens[i].mint.equals(mint)) return i;
408
+ return undefined;
409
+ }
410
+
411
+ getSelfTvl(): Fraction {
412
+ let selfTvl = { high: new BN(0), low: new BN(0) };
413
+ for (let i = 0; i < this.self.priceUpdateTasks.length; i++) {
414
+ if (this.self.priceUpdateTasks[i].completedTime.isZero()) {
415
+ continue;
416
+ }
417
+ const tokenAuction = this.self.tokens[i];
418
+ const tokenPrice = tokenAuction.price; // contains .price (mid)
419
+ if (!tokenPrice || !tokenAuction.amount) continue;
420
+ // price * amount
421
+ const tokenValue = fractionMul(tokenPrice.price, { high: new BN(tokenAuction.amount), low: new BN(0) });
422
+ selfTvl = fractionAdd(selfTvl, tokenValue);
423
+ }
424
+ return selfTvl;
425
+ }
426
+
427
+ getBasketTvlAndWeightSum(basket: Basket): { basketTvl: Fraction, weightSum: number } {
428
+ let basketTvl = { high: new BN(0), low: new BN(0) };
429
+ let weightSum = 0;
430
+ for (let i = 0; i < basket.numTokens; i++) {
431
+ const basketToken = basket.composition[i];
432
+ weightSum += basketToken.weight;
433
+ if (basketToken.amount.isZero()) {
434
+ continue;
435
+ }
436
+ const tokenIndex = this.findTokenIndex(basketToken.mint);
437
+ if (tokenIndex === undefined) throw new Error("TokenNotFound");
438
+ if (this.self.priceUpdateTasks[tokenIndex].completedTime.isZero()) throw new Error("PriceUpdateNotCompleted");
439
+ const tokenPrice = this.self.tokens[tokenIndex].price;
440
+ // price * amount
441
+ const tokenValue = fractionMul(tokenPrice.price, { high: new BN(basketToken.amount), low: new BN(0) });
442
+ basketTvl = fractionAdd(basketTvl, tokenValue);
443
+ }
444
+ return { basketTvl, weightSum };
445
+ }
446
+
447
+ private getPriceChange(price: OraclePriceOnChain, timeSinceAuctionStart: BN, auctionDuration: BN): Fraction {
448
+ // price_change = conf * 2 * time_since_auction_start / auction_duration
449
+ if (auctionDuration.isZero()) {
450
+ throw new Error("AuctionNotLive");
451
+ }
452
+ // conf * 2
453
+ const confTimes2 = fractionMul(price.conf, { high: new BN(2), low: new BN(0) });
454
+ // conf * 2 * time_since_auction_start
455
+ const confTimes2TimesTime = fractionMul(confTimes2, { high: new BN(timeSinceAuctionStart), low: new BN(0) });
456
+ // (conf * 2 * time_since_auction_start) / auction_duration
457
+ const auctionDurationFraction = { high: new BN(auctionDuration), low: new BN(0) };
458
+ return fractionDiv(confTimes2TimesTime, auctionDurationFraction);
459
+ }
460
+
461
+ private getSellPrice(price: OraclePriceOnChain, timeSinceAuctionStart: BN, auctionDuration: BN): Fraction {
462
+ // sell_price = high() - get_price_change()
463
+ // high() = price + conf
464
+ const high = fractionAdd(price.price, price.conf);
465
+ const priceChange = this.getPriceChange(price, timeSinceAuctionStart, auctionDuration);
466
+ return fractionSub(high, priceChange);
467
+ }
468
+
469
+ private getBuyPrice(price: OraclePriceOnChain, timeSinceAuctionStart: BN, auctionDuration: BN): Fraction {
470
+ // buy_price = low() + get_price_change()
471
+ // low() = price - conf
472
+ const low = fractionSub(price.price, price.conf);
473
+ const priceChange = this.getPriceChange(price, timeSinceAuctionStart, auctionDuration);
474
+ return fractionAdd(low, priceChange);
475
+ }
476
+
477
+ private getExchangeRate(
478
+ outToken: TokenAuction,
479
+ inToken: TokenAuction,
480
+ timeSinceAuctionStart: BN,
481
+ auctionDuration: BN,
482
+ ): { amountToSell: BN, amountToBuy: BN, exchangeValue: Fraction } {
483
+ const outAmount = outToken.amount;
484
+ const outTargetAmount = outToken.targetAmount;
485
+ const inAmount = inToken.amount;
486
+ const inTargetAmount = inToken.targetAmount;
487
+
488
+ if (outAmount.lte(outTargetAmount)) throw new Error("InvalidSwap");
489
+ if (inAmount.gte(inTargetAmount)) throw new Error("InvalidSwap");
490
+
491
+ const maxAmountToSell: BN = outAmount.sub(outTargetAmount);
492
+ const maxAmountToBuy: BN = inTargetAmount.sub(inAmount);
493
+
494
+ const sellRate: Fraction = this.getSellPrice(outToken.price, timeSinceAuctionStart, auctionDuration);
495
+ const buyRate: Fraction = this.getBuyPrice(inToken.price, timeSinceAuctionStart, auctionDuration);
496
+
497
+ // sellValue = sellRate * maxAmountToSell
498
+ const sellValue: Fraction = fractionMul(sellRate, { high: new BN(maxAmountToSell), low: new BN(0) });
499
+ // buyValue = buyRate * maxAmountToBuy
500
+ const buyValue: Fraction = fractionMul(buyRate, { high: new BN(maxAmountToBuy), low: new BN(0) });
501
+
502
+ let sellSideLimits: boolean;
503
+ if (fractionLte(sellValue, buyValue)) {
504
+ sellSideLimits = true;
505
+ } else if (!outTargetAmount.isZero()) {
506
+ sellSideLimits = false;
507
+ } else {
508
+ // adjustedSellValue = sellValue * (HUNDRED_PERCENT_BPS - 100) / HUNDRED_PERCENT_BPS
509
+ const adjustmentFactor = fractionDiv(
510
+ { high: new BN(HUNDRED_PERCENT_BPS - 100), low: new BN(0) },
511
+ { high: new BN(HUNDRED_PERCENT_BPS), low: new BN(0) }
512
+ );
513
+ const adjustedSellValue = fractionMul(sellValue, adjustmentFactor);
514
+ sellSideLimits = fractionLte(adjustedSellValue, buyValue);
515
+ }
516
+
517
+ if (sellSideLimits) {
518
+ // amountToBuy = sellValue / buyRate (rounded up)
519
+ const amountToBuy = fractionRoundUp(fractionDiv(sellValue, buyRate));
520
+ return {
521
+ amountToSell: maxAmountToSell,
522
+ amountToBuy: amountToBuy,
523
+ exchangeValue: sellValue,
524
+ };
525
+ } else {
526
+ // amountToSell = buyValue / sellRate (rounded down)
527
+ const amountToSell = fractionRoundDown(fractionDiv(buyValue, sellRate));
528
+ return {
529
+ amountToSell: amountToSell,
530
+ amountToBuy: maxAmountToBuy,
531
+ exchangeValue: buyValue,
532
+ };
533
+ }
534
+ }
535
+
536
+
537
+ getSwapAmounts(
538
+ inTokenIndex: number,
539
+ outTokenIndex: number,
540
+ timeSinceAuctionStart: BN,
541
+ auctionDuration: BN,
542
+ ): { amountToSell: BN, amountToBuy: BN, exchangeValue: Fraction } {
543
+ if (inTokenIndex === outTokenIndex) throw new Error("InvalidSwap");
544
+ if (this.self.priceUpdateTasks[inTokenIndex].completedTime.isZero()) throw new Error("PriceUpdateNotCompleted");
545
+ if (this.self.priceUpdateTasks[outTokenIndex].completedTime.isZero()) throw new Error("PriceUpdateNotCompleted");
546
+ const inToken = this.self.tokens[inTokenIndex];
547
+ const outToken = this.self.tokens[outTokenIndex];
548
+
549
+ const exchangeRate = this.getExchangeRate(
550
+ outToken,
551
+ inToken,
552
+ timeSinceAuctionStart,
553
+ auctionDuration,
554
+ );
555
+
556
+ let basketBuys = exchangeRate.amountToBuy;
557
+ let basketSells = exchangeRate.amountToSell;
558
+
559
+ // inValue = inTokenPrice * basketBuys
560
+ const inValue = fractionMul(inToken.price.price, { high: new BN(basketBuys), low: new BN(0) });
561
+ // outValue = outTokenPrice * basketSells
562
+ const outValue = fractionMul(outToken.price.price, { high: new BN(basketSells), low: new BN(0) });
563
+
564
+ // slippageFactor = (HUNDRED_PERCENT_BPS - bps) / HUNDRED_PERCENT_BPS
565
+ const slippageFactor = fractionDiv(
566
+ { high: new BN(HUNDRED_PERCENT_BPS - this.self.perTradeRebalanceThresholdSlippageBps), low: new BN(0) },
567
+ { high: new BN(HUNDRED_PERCENT_BPS), low: new BN(0) }
568
+ );
569
+
570
+ // Check: inValue < outValue * slippageFactor
571
+ const outValueWithSlippage = fractionMul(outValue, slippageFactor);
572
+ if (fractionLt(inValue, outValueWithSlippage)) {
573
+ throw new Error("RebalanceSlippageExceeded");
574
+ }
575
+
576
+ const selfTvl = this.getSelfTvl();
577
+ // minSelfTvl = initialTvl * (HUNDRED_PERCENT_BPS - rebalanceThresholdSlippageBps) / HUNDRED_PERCENT_BPS
578
+ const tvlSlippageFactor = fractionDiv(
579
+ { high: new BN(HUNDRED_PERCENT_BPS - this.self.rebalanceThresholdSlippageBps), low: new BN(0) },
580
+ { high: new BN(HUNDRED_PERCENT_BPS), low: new BN(0) }
581
+ );
582
+ const minSelfTvl = fractionMul(this.self.initialTvl, tvlSlippageFactor);
583
+ if (fractionLt(selfTvl, minSelfTvl)) {
584
+ throw new Error("RebalanceSlippageExceeded");
585
+ }
586
+
587
+ return exchangeRate;
588
+ }
589
+
590
+ updateTargetAmounts(basket: Basket): void {
591
+ this.self.auctionUpdateTimestamp = new BN(Math.floor(Date.now() / 1000));
592
+
593
+ const selfTvl = this.getSelfTvl();
594
+ const { basketTvl, weightSum } = this.getBasketTvlAndWeightSum(basket);
595
+
596
+ for (let tokenIndex = 0; tokenIndex < this.self.priceUpdateTasks.length; tokenIndex++) {
597
+ if (this.self.tokens[tokenIndex].mint.equals(PublicKey.default)) {
598
+ continue;
599
+ }
600
+ if (this.self.priceUpdateTasks[tokenIndex].completedTime.isZero()) {
601
+ continue;
602
+ }
603
+ const auctionToken = this.self.tokens[tokenIndex];
604
+ const auctionTokenPrice = auctionToken.price;
605
+ const tokenPrice = auctionTokenPrice.price;
606
+ if (this.self.rebalanceType === RebalanceType.Withdraw) {
607
+ this.self.tokens[tokenIndex].targetAmount = new BN(0);
608
+ if (auctionToken.keepToken === 1) {
609
+ // targetAmount = selfTvl / tokenPrice (rounded down) * 2
610
+ const targetAmount = fractionRoundDown(fractionDiv(selfTvl, tokenPrice));
611
+ this.self.tokens[tokenIndex].targetAmount = targetAmount.mul(new BN(2));
612
+ }
613
+ continue;
614
+ }
615
+ // Find token index in basket composition
616
+ let tokenIndexInBasket: number | undefined = undefined;
617
+ for (let i = 0; i < basket.numTokens; i++) {
618
+ if (basket.composition[i].mint.equals(this.self.tokens[tokenIndex].mint)) {
619
+ tokenIndexInBasket = i;
620
+ break;
621
+ }
622
+ }
623
+ if (tokenIndexInBasket === undefined) {
624
+ this.self.tokens[tokenIndex].targetAmount = new BN(0);
625
+ continue;
626
+ }
627
+ const basketToken = basket.composition[tokenIndexInBasket];
628
+
629
+ if (this.self.rebalanceType === RebalanceType.Deposit && basket.supplyOutstanding.gt(new BN(0))) {
630
+ // targetAmount = (basketToken.amount * selfTvl) / basketTvl (rounded down)
631
+ const basketTokenAmountFraction = { high: new BN(basketToken.amount), low: new BN(0) };
632
+ const numerator = fractionMul(basketTokenAmountFraction, selfTvl);
633
+ const targetAmount = fractionRoundDown(fractionDiv(numerator, basketTvl));
634
+ this.self.tokens[tokenIndex].targetAmount = targetAmount;
635
+ }
636
+ if (this.self.rebalanceType === RebalanceType.Deposit && basket.supplyOutstanding.isZero()) {
637
+ // targetValue = selfTvl * weight / weightSum
638
+ // targetAmount = targetValue / tokenPrice (rounded down)
639
+ const targetValue = fractionDiv(
640
+ fractionMul(selfTvl, { high: new BN(basketToken.weight), low: new BN(0) }),
641
+ { high: new BN(weightSum), low: new BN(0) }
642
+ );
643
+ const targetAmount = fractionRoundDown(fractionDiv(targetValue, tokenPrice));
644
+ this.self.tokens[tokenIndex].targetAmount = targetAmount;
645
+ }
646
+ if (this.self.rebalanceType === RebalanceType.Basket || this.self.rebalanceType === RebalanceType.BasketCustom) {
647
+ // targetValue = basketTvl * weight / weightSum
648
+ // targetAmount = targetValue / tokenPrice (rounded down)
649
+ const targetValue = fractionDiv(
650
+ fractionMul(basketTvl, { high: new BN(basketToken.weight), low: new BN(0) }),
651
+ { high: new BN(weightSum), low: new BN(0) }
652
+ );
653
+ let targetAmount = fractionRoundDown(fractionDiv(targetValue, tokenPrice));
654
+ if (this.self.bounty.bountyMint.equals(auctionToken.mint)) {
655
+ targetAmount = targetAmount.add(this.self.bountyAdjustmentAmount);
656
+ }
657
+ this.self.tokens[tokenIndex].targetAmount = targetAmount;
658
+ }
659
+ }
660
+ }
661
+ }
662
+
663
+ /**
664
+ * Returns all valid swap pairs available during the rebalance auction phase.
665
+ *
666
+ * **Swap direction (basket perspective):**
667
+ * - `inMint` / `inAmount`: what the basket is supposed to **receive**.
668
+ * - `outMint` / `outAmount`: what the basket wants to **swap** (give away).
669
+ * So each pair describes an **outMint → inMint** swap. When generating swap
670
+ * transactions, use this direction: swap `outMint` → `inMint` (sell outAmount of
671
+ * outMint, receive inAmount of inMint).
672
+ *
673
+ * Only runs when the rebalance is in Auction action and the current time falls
674
+ * within one of the three auction windows. For the active auction, target amounts
675
+ * are refreshed if they haven't been updated since the auction started.
676
+ *
677
+ * Iterates over completed price-update tokens to compute exchange rates via
678
+ * getSwapAmounts (using time-since-start and auction duration). Pairs with
679
+ * positive in/out amounts are collected and sorted by value descending
680
+ * (highest value first).
681
+ *
682
+ * @param rebalanceIntent - The rebalance intent state
683
+ * @param basket - The basket (used to update target amounts when needed)
684
+ * @returns Array of swap pairs, or empty array when not in auction or outside auction windows
685
+ */
686
+ export function getSwapPairs(
687
+ rebalanceIntent: RebalanceIntent,
688
+ basket: Basket,
689
+ ): {
690
+ inMint: string;
691
+ outMint: string;
692
+ inAmount: number;
693
+ outAmount: number;
694
+ value: number;
695
+ }[] {
696
+ let rebalanceIntentRustClass = new RebalanceIntentRustClass(rebalanceIntent);
697
+ if (rebalanceIntentRustClass.self.currentAction !== RebalanceAction.Auction) return [];
698
+
699
+ const timestamp = new BN(Math.floor(Date.now() / 1000));
700
+ let currentAuction;
701
+ if (rebalanceIntentRustClass.self.auctions[0].startTime.lte(timestamp) && timestamp.lt(rebalanceIntentRustClass.self.auctions[0].endTime))
702
+ currentAuction = rebalanceIntentRustClass.self.auctions[0]; else
703
+ if (rebalanceIntentRustClass.self.auctions[1].startTime.lte(timestamp) && timestamp.lt(rebalanceIntentRustClass.self.auctions[1].endTime))
704
+ currentAuction = rebalanceIntentRustClass.self.auctions[1]; else
705
+ if (rebalanceIntentRustClass.self.auctions[2].startTime.lte(timestamp) && timestamp.lt(rebalanceIntentRustClass.self.auctions[2].endTime))
706
+ currentAuction = rebalanceIntentRustClass.self.auctions[2]; else
707
+ return [];
708
+
709
+ let start_time = currentAuction.startTime;
710
+ if (rebalanceIntentRustClass.self.auctionUpdateTimestamp.lt(start_time))
711
+ rebalanceIntentRustClass.updateTargetAmounts(basket);
712
+
713
+ let timeSinceAuctionStart = timestamp.sub(currentAuction.startTime);
714
+ let auctionDuration = currentAuction.endTime.sub(currentAuction.startTime);
715
+
716
+ let allPairs: {
717
+ inMint: string;
718
+ outMint: string;
719
+ inAmount: number;
720
+ outAmount: number;
721
+ value: number;
722
+ }[] = [];
723
+
724
+ for (let inTokenIndex = 0; inTokenIndex < rebalanceIntentRustClass.self.priceUpdateTasks.length; inTokenIndex++) {
725
+ if (rebalanceIntentRustClass.self.priceUpdateTasks[inTokenIndex].completedTime.isZero()) continue;
726
+ for (let outTokenIndex = 0; outTokenIndex < rebalanceIntentRustClass.self.priceUpdateTasks.length; outTokenIndex++) {
727
+ if (inTokenIndex === outTokenIndex) continue;
728
+ if (rebalanceIntentRustClass.self.priceUpdateTasks[outTokenIndex].completedTime.isZero()) continue;
729
+
730
+ try {
731
+ let exchangeRate = rebalanceIntentRustClass.getSwapAmounts(
732
+ inTokenIndex,
733
+ outTokenIndex,
734
+ timeSinceAuctionStart,
735
+ auctionDuration,
736
+ );
737
+ if (parseInt(exchangeRate.amountToBuy.toString()) > 0 && parseInt(exchangeRate.amountToSell.toString()) > 0) {
738
+ allPairs.push({
739
+ inMint: rebalanceIntentRustClass.self.tokens[inTokenIndex].mint.toBase58(),
740
+ outMint: rebalanceIntentRustClass.self.tokens[outTokenIndex].mint.toBase58(),
741
+ inAmount: parseInt(exchangeRate.amountToBuy.toString()),
742
+ outAmount: parseInt(exchangeRate.amountToSell.toString()),
743
+ value: fractionToDecimal(exchangeRate.exchangeValue).toNumber(),
744
+ });
745
+ }
746
+ } catch {}
747
+ }
748
+ }
749
+ allPairs.sort((a, b) => b.value - a.value);
750
+ return allPairs;
751
+ }