@symmetry-hq/sdk 1.0.2 → 1.0.4

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 (40) hide show
  1. package/dist/src/index.d.ts +28 -2
  2. package/dist/src/index.js +148 -2
  3. package/dist/src/instructions/management/edit.js +3 -3
  4. package/dist/src/jup.d.ts +1 -0
  5. package/dist/src/jup.js +28 -22
  6. package/dist/src/layouts/basket.d.ts +0 -1
  7. package/dist/src/layouts/intents/intent.d.ts +2 -1
  8. package/dist/src/layouts/oracle.d.ts +4 -1
  9. package/dist/src/layouts/oracle.js +10 -4
  10. package/dist/src/states/basket.d.ts +3 -0
  11. package/dist/src/states/basket.js +33 -2
  12. package/dist/src/states/intents/intent.js +2 -1
  13. package/dist/src/states/intents/rebalanceIntent.d.ts +1 -1
  14. package/dist/src/states/intents/rebalanceIntent.js +63 -45
  15. package/dist/src/states/oracles/oracle.d.ts +1 -1
  16. package/dist/src/states/oracles/oracle.js +11 -3
  17. package/dist/src/states/oracles/pythOracle.d.ts +10 -0
  18. package/dist/src/states/oracles/pythOracle.js +99 -45
  19. package/dist/src/states/oracles/raydiumClmmOracle.d.ts +1 -1
  20. package/dist/src/states/oracles/raydiumClmmOracle.js +29 -41
  21. package/dist/src/states/oracles/raydiumCpmmOracle.js +24 -28
  22. package/dist/src/txUtils.d.ts +2 -2
  23. package/dist/src/txUtils.js +16 -18
  24. package/dist/test.js +5 -4
  25. package/package.json +1 -1
  26. package/src/index.ts +200 -22
  27. package/src/instructions/management/edit.ts +2 -1
  28. package/src/jup.ts +21 -13
  29. package/src/layouts/basket.ts +0 -1
  30. package/src/layouts/intents/intent.ts +2 -1
  31. package/src/layouts/oracle.ts +12 -4
  32. package/src/states/basket.ts +67 -22
  33. package/src/states/intents/intent.ts +2 -1
  34. package/src/states/intents/rebalanceIntent.ts +51 -35
  35. package/src/states/oracles/oracle.ts +12 -3
  36. package/src/states/oracles/pythOracle.ts +142 -55
  37. package/src/states/oracles/raydiumClmmOracle.ts +35 -45
  38. package/src/states/oracles/raydiumCpmmOracle.ts +28 -31
  39. package/src/txUtils.ts +13 -11
  40. package/test.ts +5 -4
@@ -3,11 +3,12 @@ import { getJupTokenLedgerAndSwapInstructions } from './jup';
3
3
  import { Basket, FormattedAccumulatedFees, FormattedAddTokenSettings, FormattedAsset, FormattedAutomationSettings, FormattedBasket, FormattedCreatorSettings, FormattedCustomRebalanceSettings, FormattedDepositsSettings, FormattedFeeSettings, FormattedForceRebalanceSettings, FormattedLookupTables, FormattedLpSettings, FormattedMakeDirectSwapSettings, FormattedManagersSettings, FormattedMetadataSettings, FormattedOracle, FormattedOracleAggregator, FormattedOracleSettings, FormattedScheduleSettings, FormattedUpdateWeightsSettings, WithdrawBasketFees } from './layouts/basket';
4
4
  import { FormattedGlobalConfig, GlobalConfig } from './layouts/config';
5
5
  import { AddOrEditTokenInput, EditAddTokenSettings, EditAutomationSettings, EditCreatorSettings, EditCustomRebalanceSettings, EditDepositsSettings, EditFeeSettings, EditForceRebalanceSettings, EditLpSettings, EditMakeDirectSwapSettings, EditManagerSettings, EditMetadataSettings, EditScheduleSettings, EditUpdateWeightsSettings, FormattedBounty, FormattedBountySchedule, FormattedIntent, FormattedIntentStatus, FormattedTaskType, Intent, MakeDirectSwapInput, OracleInput, Settings, TaskContext, TaskType, UpdateWeightsInput } from './layouts/intents/intent';
6
- import { FormattedOraclePrice, FormattedRebalanceAction, FormattedRebalanceIntent, FormattedRebalanceType, FormattedTaskCompletion, FormattedTokenAuction, MintData, PriceUpdatesData, RebalanceIntent, AuctionData, RedeemData, DepositData, ClaimBountyData, UIRebalanceIntent } from './layouts/intents/rebalanceIntent';
6
+ import { AuctionData, ClaimBountyData, DepositData, FormattedOraclePrice, FormattedRebalanceAction, FormattedRebalanceIntent, FormattedRebalanceType, FormattedTaskCompletion, FormattedTokenAuction, MintData, PriceUpdatesData, RebalanceIntent, RedeemData, UIRebalanceIntent } from './layouts/intents/rebalanceIntent';
7
7
  import { FormattedOracleType } from './layouts/oracle';
8
8
  import { BasketFilter } from './states/basket';
9
9
  import { IntentFilter } from './states/intents/intent';
10
- import { getSwapPairs, isRebalanceRequired, RebalanceIntentFilter } from './states/intents/rebalanceIntent';
10
+ import { getSwapPairs, RebalanceIntentFilter, isRebalanceRequired } from './states/intents/rebalanceIntent';
11
+ import { OraclePrice } from './states/oracles/oracle';
11
12
  import { WithdrawBasketFeesFilter } from './states/withdrawBasketFees';
12
13
  import { BasketCreationTx, TxPayloadBatchSequence, VersionedTxs, Wallet } from './txUtils';
13
14
  export declare class SymmetryCore {
@@ -90,6 +91,19 @@ export declare class SymmetryCore {
90
91
  * @returns {Promise<Basket>} The basket with the price.
91
92
  */
92
93
  loadBasketPrice(basket: Basket): Promise<Basket>;
94
+ loadBasketPriceWithPythPriceOverrides(params: {
95
+ basket: Basket;
96
+ pyth_price_overrides?: Map<string, OraclePrice>;
97
+ }): Promise<Basket>;
98
+ /**
99
+ * Checks whether a basket currently meets the automation rebalance trigger.
100
+ * Uses the existing basket pricing flow.
101
+ */
102
+ isBasketRebalanceRequired(params: {
103
+ basket: string | Basket;
104
+ pyth_price_overrides?: Map<string, OraclePrice>;
105
+ }): Promise<boolean>;
106
+ private computeBasketRebalanceRequiredFromPricedBasket;
93
107
  /**
94
108
  * Fetches an intent by its public key.
95
109
  * @param {string} intentPubkey - The public key of the intent.
@@ -382,6 +396,18 @@ export declare class SymmetryCore {
382
396
  keeper: string;
383
397
  intent: string;
384
398
  }): Promise<TxPayloadBatchSequence>;
399
+ /**
400
+ * Executes an existing make-direct-swap basket intent.
401
+ * Builds the flash swap batch first and then executes the intent once the
402
+ * basket balances have been updated by the swap.
403
+ */
404
+ executeDirectSwapIntentTx(params: {
405
+ keeper: string;
406
+ intent: string;
407
+ jup_token_ledger_ix?: TransactionInstruction;
408
+ jup_swap_ix: TransactionInstruction;
409
+ jup_address_lookup_table_addresses?: PublicKey[];
410
+ }): Promise<TxPayloadBatchSequence>;
385
411
  /**
386
412
  * Cancels a basket intent. Basket intent account will get closed.
387
413
  * @param {Object} params - The parameters for the basket intent.
package/dist/src/index.js CHANGED
@@ -13,8 +13,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
13
13
  };
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
15
  exports.RebalanceHandler = exports.KeeperMonitor = exports.isRebalanceRequired = exports.getSwapPairs = exports.getJupTokenLedgerAndSwapInstructions = exports.TaskType = exports.SymmetryCore = void 0;
16
- const decimal_js_1 = __importDefault(require("decimal.js"));
17
16
  const bn_js_1 = __importDefault(require("bn.js"));
17
+ const decimal_js_1 = __importDefault(require("decimal.js"));
18
18
  const spl_token_1 = require("@solana/spl-token");
19
19
  const web3_js_1 = require("@solana/web3.js");
20
20
  const constants_1 = require("./constants");
@@ -44,8 +44,8 @@ const intent_2 = require("./states/intents/intent");
44
44
  const rebalanceIntent_3 = require("./states/intents/rebalanceIntent");
45
45
  Object.defineProperty(exports, "getSwapPairs", { enumerable: true, get: function () { return rebalanceIntent_3.getSwapPairs; } });
46
46
  Object.defineProperty(exports, "isRebalanceRequired", { enumerable: true, get: function () { return rebalanceIntent_3.isRebalanceRequired; } });
47
- const withdrawBasketFees_1 = require("./states/withdrawBasketFees");
48
47
  const pythOracle_1 = require("./states/oracles/pythOracle");
48
+ const withdrawBasketFees_1 = require("./states/withdrawBasketFees");
49
49
  const txUtils_1 = require("./txUtils");
50
50
  class SymmetryCore {
51
51
  /**
@@ -193,6 +193,84 @@ class SymmetryCore {
193
193
  return yield (0, basket_1.loadBasketPrice)(basket, this.sdkParams.connection);
194
194
  });
195
195
  }
196
+ loadBasketPriceWithPythPriceOverrides(params) {
197
+ return __awaiter(this, void 0, void 0, function* () {
198
+ return yield (0, basket_1.loadBasketPriceWithPythPriceOverrides)(params.basket, this.sdkParams.connection, params.pyth_price_overrides);
199
+ });
200
+ }
201
+ /**
202
+ * Checks whether a basket currently meets the automation rebalance trigger.
203
+ * Uses the existing basket pricing flow.
204
+ */
205
+ isBasketRebalanceRequired(params) {
206
+ return __awaiter(this, void 0, void 0, function* () {
207
+ var _a;
208
+ let basket = typeof params.basket === 'string'
209
+ ? yield this.fetchBasket(params.basket)
210
+ : params.basket;
211
+ if (!((_a = basket.formatted) === null || _a === void 0 ? void 0 : _a.automation_settings.enabled) && basket.settings.automation.allowAutomation !== 1) {
212
+ return false;
213
+ }
214
+ if (params.pyth_price_overrides && params.pyth_price_overrides.size > 0) {
215
+ basket = yield this.loadBasketPriceWithPythPriceOverrides({
216
+ basket,
217
+ pyth_price_overrides: params.pyth_price_overrides,
218
+ });
219
+ }
220
+ else {
221
+ basket = yield this.loadBasketPrice(basket);
222
+ }
223
+ return this.computeBasketRebalanceRequiredFromPricedBasket(basket);
224
+ });
225
+ }
226
+ computeBasketRebalanceRequiredFromPricedBasket(basket) {
227
+ var _a, _b, _c;
228
+ const basketTvl = (_a = basket.tvl) !== null && _a !== void 0 ? _a : basket.composition
229
+ .slice(0, basket.numTokens)
230
+ .reduce((sum, asset) => {
231
+ var _a, _b, _c;
232
+ const value = (_c = (_a = asset.value) !== null && _a !== void 0 ? _a : (_b = asset.price) === null || _b === void 0 ? void 0 : _b.getMid().mul(new decimal_js_1.default(asset.amount.toString()))) !== null && _c !== void 0 ? _c : new decimal_js_1.default(0);
233
+ return sum.add(value);
234
+ }, new decimal_js_1.default(0));
235
+ if (!basketTvl.isFinite() || basketTvl.lte(0)) {
236
+ return false;
237
+ }
238
+ const weightSum = basket.composition
239
+ .slice(0, basket.numTokens)
240
+ .reduce((sum, asset) => sum + asset.weight, 0);
241
+ if (weightSum <= 0) {
242
+ return false;
243
+ }
244
+ const requiredRelBps = new decimal_js_1.default(basket.settings.automation.rebalanceActivationThresholdRelBps);
245
+ const requiredAbsBps = new decimal_js_1.default(basket.settings.automation.rebalanceActivationThresholdAbsBps);
246
+ const bountyMint = basket.settings.bountyMint;
247
+ const hundredPercentBps = new decimal_js_1.default(10000);
248
+ for (const asset of basket.composition.slice(0, basket.numTokens)) {
249
+ if (asset.mint.equals(bountyMint)) {
250
+ continue;
251
+ }
252
+ const tokenPrice = (_b = asset.price) === null || _b === void 0 ? void 0 : _b.getMid();
253
+ if (!tokenPrice || !tokenPrice.isFinite() || tokenPrice.lte(0)) {
254
+ continue;
255
+ }
256
+ const tokenValue = (_c = asset.value) !== null && _c !== void 0 ? _c : tokenPrice.mul(new decimal_js_1.default(asset.amount.toString()));
257
+ const targetValue = basketTvl.mul(asset.weight).div(weightSum);
258
+ const valueDiff = tokenValue.sub(targetValue).abs();
259
+ if (valueDiff.eq(0)) {
260
+ continue;
261
+ }
262
+ const maxValue = decimal_js_1.default.max(tokenValue, targetValue);
263
+ if (!maxValue.isFinite() || maxValue.lte(0)) {
264
+ continue;
265
+ }
266
+ const relBps = valueDiff.div(maxValue).mul(hundredPercentBps);
267
+ const absBps = valueDiff.div(basketTvl).mul(hundredPercentBps);
268
+ if (relBps.gte(requiredRelBps) && absBps.gte(requiredAbsBps)) {
269
+ return true;
270
+ }
271
+ }
272
+ return false;
273
+ }
196
274
  /**
197
275
  * Fetches an intent by its public key.
198
276
  * @param {string} intentPubkey - The public key of the intent.
@@ -866,6 +944,74 @@ class SymmetryCore {
866
944
  return txPayloadBatchSequence;
867
945
  });
868
946
  }
947
+ /**
948
+ * Executes an existing make-direct-swap basket intent.
949
+ * Builds the flash swap batch first and then executes the intent once the
950
+ * basket balances have been updated by the swap.
951
+ */
952
+ executeDirectSwapIntentTx(params) {
953
+ return __awaiter(this, void 0, void 0, function* () {
954
+ var _a, _b;
955
+ const keeper = new web3_js_1.PublicKey(params.keeper);
956
+ const intent = yield this.fetchIntent(params.intent);
957
+ if (intent.taskType !== intent_1.TaskType.MakeDirectSwap) {
958
+ throw new Error('Intent is not a make_direct_swap intent');
959
+ }
960
+ const taskData = (_a = intent.formatted) === null || _a === void 0 ? void 0 : _a.task_data;
961
+ if (!taskData) {
962
+ throw new Error('Make direct swap intent is missing decoded task data');
963
+ }
964
+ const flashParams = {
965
+ keeper,
966
+ basket: intent.basket,
967
+ rebalanceIntent: undefined,
968
+ intent: intent.ownAddress,
969
+ mintIn: new web3_js_1.PublicKey(taskData.from_token_mint),
970
+ mintOut: new web3_js_1.PublicKey(taskData.to_token_mint),
971
+ amountIn: new bn_js_1.default(taskData.amount_from),
972
+ amountOut: new bn_js_1.default(taskData.amount_to),
973
+ mode: undefined,
974
+ };
975
+ const ixWithdraw = (0, flashSwap_1.flashWithdrawIx)(flashParams);
976
+ const ixDeposit = (0, flashSwap_1.flashDepositIx)(flashParams);
977
+ const executeIx = (0, edit_1.executeEditBasketIntentIx)({
978
+ basket: intent.basket,
979
+ intent: intent.ownAddress,
980
+ editType: intent.taskType,
981
+ manager: intent.manager,
982
+ bountyMint: intent.bounty.bountyMint,
983
+ keeper,
984
+ basketMint: undefined,
985
+ });
986
+ const flashInstructions = [
987
+ (0, spl_token_1.createAssociatedTokenAccountIdempotentInstruction)(keeper, (0, pda_1.getAta)(keeper, flashParams.mintIn), keeper, flashParams.mintIn),
988
+ (0, spl_token_1.createAssociatedTokenAccountIdempotentInstruction)(keeper, (0, pda_1.getAta)(keeper, flashParams.mintOut), keeper, flashParams.mintOut),
989
+ ];
990
+ if (params.jup_token_ledger_ix) {
991
+ flashInstructions.push(params.jup_token_ledger_ix);
992
+ }
993
+ flashInstructions.push(ixWithdraw, params.jup_swap_ix, ixDeposit, web3_js_1.ComputeBudgetProgram.setComputeUnitLimit({ units: constants_1.COMPUTE_UNITS }), web3_js_1.ComputeBudgetProgram.setComputeUnitPrice({ microLamports: this.sdkParams.priorityFee }));
994
+ const txBatchData = { batches: [
995
+ [{
996
+ payer: keeper,
997
+ instructions: flashInstructions,
998
+ lookupTables: (_b = params.jup_address_lookup_table_addresses) !== null && _b !== void 0 ? _b : [],
999
+ }],
1000
+ [{
1001
+ payer: keeper,
1002
+ instructions: [
1003
+ executeIx,
1004
+ web3_js_1.ComputeBudgetProgram.setComputeUnitLimit({ units: constants_1.COMPUTE_UNITS }),
1005
+ web3_js_1.ComputeBudgetProgram.setComputeUnitPrice({ microLamports: this.sdkParams.priorityFee }),
1006
+ ],
1007
+ lookupTables: [],
1008
+ }],
1009
+ ] };
1010
+ const versionedTxs = yield (0, txUtils_1.prepareVersionedTxs)(this.sdkParams.connection, txBatchData);
1011
+ const txPayloadBatchSequence = (0, txUtils_1.prepareTxPayloadBatchSequence)(txBatchData, versionedTxs);
1012
+ return txPayloadBatchSequence;
1013
+ });
1014
+ }
869
1015
  /**
870
1016
  * Cancels a basket intent. Basket intent account will get closed.
871
1017
  * @param {Object} params - The parameters for the basket intent.
@@ -67,7 +67,7 @@ function editPrivateBasketSettingsIx(params) {
67
67
  });
68
68
  }
69
69
  function createEditBasketIntentIx(params) {
70
- var _a, _b, _c;
70
+ var _a, _b, _c, _d, _e;
71
71
  const { manager, basket, intent, intentSeedArray, editType, editData, activationTimestamp, expirationTimestamp, minBounty, maxBounty, tokenProgram, } = params;
72
72
  let globalConfig = (0, pda_1.getGlobalConfigPda)();
73
73
  let bountyVault = (0, pda_1.getBountyVaultPda)();
@@ -279,7 +279,7 @@ function createEditBasketIntentIx(params) {
279
279
  tokenDecimals: addTokenData.oracles[i].token_decimals,
280
280
  twapSecondsAgo: new bn_js_1.default(addTokenData.oracles[i].twap_seconds_ago),
281
281
  twapSecondarySecondsAgo: new bn_js_1.default(addTokenData.oracles[i].twap_secondary_seconds_ago),
282
- quote: oracle_1.Quote.Wsol,
282
+ quote: (_d = (_c = [...oracle_1.QUOTES_STRINGS.entries()].find(([, name]) => name === addTokenData.oracles[i].quote)) === null || _c === void 0 ? void 0 : _c[0]) !== null && _d !== void 0 ? _d : oracle_1.Quote.Usd,
283
283
  side: oracle_1.Side.Base,
284
284
  },
285
285
  accountsToLoadLutIds: new Array(oracle_1.MAX_ACCOUNTS_PER_ORACLE).fill(0),
@@ -342,7 +342,7 @@ function createEditBasketIntentIx(params) {
342
342
  const weights = updateWeightsData.token_weights.slice(0, constants_1.MAX_SUPPORTED_TOKENS_PER_BASKET);
343
343
  while (weights.length < constants_1.MAX_SUPPORTED_TOKENS_PER_BASKET)
344
344
  weights.push({ mint: '', weight_bps: 0 });
345
- let tokenMintsHash = (_c = updateWeightsData.token_mints_hash) !== null && _c !== void 0 ? _c : (0, basket_1.computeTokenMintsHash)(basket.composition.slice(0, basket.numTokens)
345
+ let tokenMintsHash = (_e = updateWeightsData.token_mints_hash) !== null && _e !== void 0 ? _e : (0, basket_1.computeTokenMintsHash)(basket.composition.slice(0, basket.numTokens)
346
346
  .filter((asset) => asset.active === 1)
347
347
  .map((asset) => asset.mint.toBase58()));
348
348
  let updateWeights = {
package/dist/src/jup.d.ts CHANGED
@@ -17,6 +17,7 @@ export declare function getJupQuote(params: {
17
17
  swapMode: "exact_in" | "exact_out" | "ioc";
18
18
  apiKey: string;
19
19
  maxJupAccounts: number;
20
+ slippageBps?: number;
20
21
  }): Promise<{
21
22
  mode: string;
22
23
  inputMint: string;
package/dist/src/jup.js CHANGED
@@ -29,8 +29,17 @@ function getJupQuote(params) {
29
29
  '&outputMint=' + params.basketMintIn.toBase58() +
30
30
  '&amount=' + (params.swapMode == "exact_in" ? params.basketAmountIn : params.basketAmountOut) +
31
31
  '&swapMode=' + (params.swapMode == "exact_in" ? "ExactOut" : "ExactIn") +
32
- '&maxAccounts=' + params.maxJupAccounts;
33
- let res = yield fetch(reqUrl, options).then(res => res.json());
32
+ '&maxAccounts=' + params.maxJupAccounts +
33
+ (params.slippageBps !== undefined ? '&slippageBps=' + params.slippageBps : '');
34
+ let response = yield fetch(reqUrl, options);
35
+ if (!response.ok) {
36
+ const body = yield response.text().catch(() => '');
37
+ throw new Error(`Jupiter quote error ${response.status}: ${body}`);
38
+ }
39
+ let res = yield response.json();
40
+ if (res.error) {
41
+ throw new Error(`Jupiter quote error: ${typeof res.error === 'string' ? res.error : JSON.stringify(res.error)}`);
42
+ }
34
43
  return res;
35
44
  });
36
45
  }
@@ -51,30 +60,27 @@ function getJupSwapInstructions(params) {
51
60
  },
52
61
  body: JSON.stringify(body),
53
62
  };
54
- let res = yield fetch(reqUrl, options).then(res => res.json());
63
+ let response = yield fetch(reqUrl, options);
64
+ if (!response.ok) {
65
+ const body = yield response.text().catch(() => '');
66
+ throw new Error(`Jupiter swap-instructions error ${response.status}: ${body}`);
67
+ }
68
+ let res = yield response.json();
69
+ if (res.error) {
70
+ throw new Error(`Jupiter swap-instructions error: ${typeof res.error === 'string' ? res.error : JSON.stringify(res.error)}`);
71
+ }
55
72
  return res;
56
73
  });
57
74
  }
58
75
  function getJupTokenLedgerAndSwapInstructions(params) {
59
76
  return __awaiter(this, void 0, void 0, function* () {
60
- try {
61
- let quoteResponse = yield getJupQuote(params);
62
- let swapInstructions = yield getJupSwapInstructions(Object.assign(Object.assign({}, params), { quoteResponse }));
63
- return {
64
- tokenLedgerInstruction: processJupInstruction(swapInstructions.tokenLedgerInstruction),
65
- swapInstruction: processJupInstruction(swapInstructions.swapInstruction),
66
- addressLookupTableAddresses: swapInstructions.addressLookupTableAddresses.map((a) => new web3_js_1.PublicKey(a)),
67
- quoteResponse: quoteResponse,
68
- };
69
- }
70
- catch (e) {
71
- console.log("Error getting Jup Instructions:", params.basketMintOut.toBase58(), params.basketMintIn.toBase58(), params.basketAmountOut);
72
- return {
73
- tokenLedgerInstruction: undefined,
74
- swapInstruction: undefined,
75
- addressLookupTableAddresses: [],
76
- quoteResponse: undefined,
77
- };
78
- }
77
+ let quoteResponse = yield getJupQuote(params);
78
+ let swapInstructions = yield getJupSwapInstructions(Object.assign(Object.assign({}, params), { quoteResponse }));
79
+ return {
80
+ tokenLedgerInstruction: processJupInstruction(swapInstructions.tokenLedgerInstruction),
81
+ swapInstruction: processJupInstruction(swapInstructions.swapInstruction),
82
+ addressLookupTableAddresses: swapInstructions.addressLookupTableAddresses.map((a) => new web3_js_1.PublicKey(a)),
83
+ quoteResponse: quoteResponse,
84
+ };
79
85
  });
80
86
  }
@@ -24,7 +24,6 @@ export interface FormattedLookupTables {
24
24
  }[];
25
25
  }
26
26
  export interface FormattedOracleSettings extends OracleInput {
27
- quote: string;
28
27
  side: string;
29
28
  }
30
29
  export interface FormattedOracle {
@@ -1,7 +1,7 @@
1
1
  import BN from 'bn.js';
2
2
  import { PublicKey } from '@solana/web3.js';
3
3
  import { Bounty } from './bounty';
4
- import { FormattedOracleType } from '../oracle';
4
+ import { FormattedOracleType, FormattedQuote } from '../oracle';
5
5
  export type FormattedIntentStatus = "not_active" | "active" | "reverted" | "completed";
6
6
  export declare const INTENT_STATUS_STRINGS: Map<number, FormattedIntentStatus>;
7
7
  export type FormattedTaskType = "unknown" | "edit_creator" | "edit_manager_settings" | "edit_fee_settings" | "edit_schedule_settings" | "edit_automation_settings" | "edit_lp_settings" | "edit_metadata_settings" | "edit_deposits_settings" | "edit_force_rebalance_settings" | "edit_custom_rebalance_settings" | "edit_add_token_delay" | "edit_update_weights_delay" | "edit_make_direct_swap_delay" | "add_token" | "update_weights" | "make_direct_swap";
@@ -183,6 +183,7 @@ export interface OracleInput {
183
183
  token_decimals: number;
184
184
  twap_seconds_ago: number;
185
185
  twap_secondary_seconds_ago: number;
186
+ quote: FormattedQuote;
186
187
  }
187
188
  export interface AddOrEditTokenInput {
188
189
  token_mint: string;
@@ -4,6 +4,8 @@ export declare const MAX_ORACLES_PER_TOKEN = 4;
4
4
  export declare const MAX_ACCOUNTS_PER_ORACLE = 4;
5
5
  export type FormattedOracleType = "pyth" | "raydium_clmm" | "raydium_cpmm" | "switchboard" | "example";
6
6
  export declare const ORACLE_TYPES_STRINGS: Map<number, FormattedOracleType>;
7
+ export type FormattedQuote = "usdc" | "wsol" | "usd";
8
+ export declare const QUOTES_STRINGS: Map<number, FormattedQuote>;
7
9
  export interface OraclePriceOnChain {
8
10
  price: Fraction;
9
11
  conf: Fraction;
@@ -19,7 +21,8 @@ export declare enum OracleType {
19
21
  }
20
22
  export declare enum Quote {
21
23
  Usdc = 0,
22
- Wsol = 1
24
+ Wsol = 1,
25
+ Usd = 2
23
26
  }
24
27
  export declare enum Side {
25
28
  Base = 0,
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.PYTH_USDC_ORACLE_SETTINGS = exports.PYTH_WSOL_ORACLE_SETTINGS = exports.DEFAULT_ORACLE_SETTINGS = exports.OracleAggregatorLayout = exports.OracleDataLayout = exports.OracleSettingsLayout = exports.Side = exports.Quote = exports.OracleType = exports.OraclePriceLayout = exports.ORACLE_TYPES_STRINGS = exports.MAX_ACCOUNTS_PER_ORACLE = exports.MAX_ORACLES_PER_TOKEN = void 0;
6
+ exports.PYTH_USDC_ORACLE_SETTINGS = exports.PYTH_WSOL_ORACLE_SETTINGS = exports.DEFAULT_ORACLE_SETTINGS = exports.OracleAggregatorLayout = exports.OracleDataLayout = exports.OracleSettingsLayout = exports.Side = exports.Quote = exports.OracleType = exports.OraclePriceLayout = exports.QUOTES_STRINGS = exports.ORACLE_TYPES_STRINGS = exports.MAX_ACCOUNTS_PER_ORACLE = exports.MAX_ORACLES_PER_TOKEN = void 0;
7
7
  const bn_js_1 = __importDefault(require("bn.js"));
8
8
  const borsh_1 = require("@coral-xyz/borsh");
9
9
  const fraction_1 = require("./fraction");
@@ -17,6 +17,11 @@ exports.ORACLE_TYPES_STRINGS = new Map([
17
17
  [3, "switchboard"],
18
18
  [255, "example"],
19
19
  ]);
20
+ exports.QUOTES_STRINGS = new Map([
21
+ [0, "usdc"],
22
+ [1, "wsol"],
23
+ [2, "usd"],
24
+ ]);
20
25
  ;
21
26
  exports.OraclePriceLayout = (0, borsh_1.struct)([
22
27
  fraction_1.FractionLayout.replicate('price'),
@@ -36,6 +41,7 @@ var Quote;
36
41
  (function (Quote) {
37
42
  Quote[Quote["Usdc"] = 0] = "Usdc";
38
43
  Quote[Quote["Wsol"] = 1] = "Wsol";
44
+ Quote[Quote["Usd"] = 2] = "Usd";
39
45
  })(Quote || (exports.Quote = Quote = {}));
40
46
  ;
41
47
  var Side;
@@ -80,8 +86,8 @@ exports.DEFAULT_ORACLE_SETTINGS = {
80
86
  numRequiredAccounts: 1,
81
87
  weight: constants_1.HUNDRED_PERCENT_BPS,
82
88
  isRequired: 1,
83
- confThreshBps: 100, // TODO: 1% ??
84
- volatilityThreshBps: 50000,
89
+ confThreshBps: 200, // TODO: 1% ??
90
+ volatilityThreshBps: 200,
85
91
  maxSlippageBps: 1000,
86
92
  minLiquidity: new bn_js_1.default(0),
87
93
  stalenessThresh: new bn_js_1.default(120),
@@ -89,7 +95,7 @@ exports.DEFAULT_ORACLE_SETTINGS = {
89
95
  tokenDecimals: constants_1.WSOL_DECIMALS,
90
96
  twapSecondsAgo: new bn_js_1.default(0),
91
97
  twapSecondarySecondsAgo: new bn_js_1.default(0),
92
- quote: Quote.Wsol,
98
+ quote: Quote.Usd,
93
99
  side: Side.Base,
94
100
  };
95
101
  exports.PYTH_WSOL_ORACLE_SETTINGS = Object.assign(Object.assign({}, exports.DEFAULT_ORACLE_SETTINGS), { tokenDecimals: constants_1.WSOL_DECIMALS });
@@ -1,5 +1,6 @@
1
1
  import { AccountInfo, Connection, PublicKey } from '@solana/web3.js';
2
2
  import { Basket } from '../layouts/basket';
3
+ import { OraclePrice } from './oracles/oracle';
3
4
  export declare function computeTokenMintsHash(mints: string[]): number[];
4
5
  export declare function addFieldsToBasket(basket: Basket): Basket;
5
6
  export declare function addLutsToBaskets(connection: Connection, baskets: Basket[]): Promise<Basket[]>;
@@ -11,4 +12,6 @@ export interface BasketFilter {
11
12
  }
12
13
  export declare function fetchBaskets(connection: Connection, filter?: BasketFilter): Promise<Basket[]>;
13
14
  export declare function fetchBasketOracleAccountInfos(connection: Connection, basket: Basket): Promise<Map<string, AccountInfo<Buffer> | null>>;
15
+ export declare function loadBasketPriceFromOracleAccountInfosWithPythPriceOverrides(basket: Basket, oracleAccountInfos: Map<string, AccountInfo<Buffer> | null>, pythPriceOverrides?: Map<string, OraclePrice>): Basket;
16
+ export declare function loadBasketPriceWithPythPriceOverrides(basket: Basket, connection: Connection, pythPriceOverrides?: Map<string, OraclePrice>): Promise<Basket>;
14
17
  export declare function loadBasketPrice(basket: Basket, connection: Connection): Promise<Basket>;
@@ -19,18 +19,20 @@ exports.fetchBasket = fetchBasket;
19
19
  exports.fetchBasketsMultiple = fetchBasketsMultiple;
20
20
  exports.fetchBaskets = fetchBaskets;
21
21
  exports.fetchBasketOracleAccountInfos = fetchBasketOracleAccountInfos;
22
+ exports.loadBasketPriceFromOracleAccountInfosWithPythPriceOverrides = loadBasketPriceFromOracleAccountInfosWithPythPriceOverrides;
23
+ exports.loadBasketPriceWithPythPriceOverrides = loadBasketPriceWithPythPriceOverrides;
22
24
  exports.loadBasketPrice = loadBasketPrice;
23
- const decimal_js_1 = __importDefault(require("decimal.js"));
24
25
  const crypto_1 = require("crypto");
26
+ const decimal_js_1 = __importDefault(require("decimal.js"));
25
27
  const web3_js_1 = require("@solana/web3.js");
26
28
  const constants_1 = require("../constants");
27
29
  const basket_1 = require("../layouts/basket");
30
+ const fraction_1 = require("../layouts/fraction");
28
31
  const oracle_1 = require("../layouts/oracle");
29
32
  const txUtils_1 = require("../txUtils");
30
33
  const oracle_2 = require("./oracles/oracle");
31
34
  const pythOracle_1 = require("./oracles/pythOracle");
32
35
  const raydiumClmmOracle_1 = require("./oracles/raydiumClmmOracle");
33
- const fraction_1 = require("../layouts/fraction");
34
36
  // export async function computeTokenMintsHash(mints: string[]): Promise<Buffer> {
35
37
  // let hashBuffer = new Uint8Array(32)
36
38
  // for (const mint of mints) {
@@ -453,6 +455,35 @@ function fetchBasketOracleAccountInfos(connection, basket) {
453
455
  return baseInfos;
454
456
  });
455
457
  }
458
+ function loadBasketPriceFromOracleAccountInfosWithPythPriceOverrides(basket, oracleAccountInfos, pythPriceOverrides) {
459
+ var _a, _b;
460
+ const solPrice = (_a = pythPriceOverrides === null || pythPriceOverrides === void 0 ? void 0 : pythPriceOverrides.get(constants_1.PYTHNET_CUSTODY_PRICE_WSOL_ACCOUNT.toBase58())) !== null && _a !== void 0 ? _a : pythOracle_1.PythOracle.fetch(oracle_1.PYTH_WSOL_ORACLE_SETTINGS, //@ts-ignore
461
+ [oracleAccountInfos.get(constants_1.PYTHNET_CUSTODY_PRICE_WSOL_ACCOUNT.toBase58())]);
462
+ const usdcPrice = (_b = pythPriceOverrides === null || pythPriceOverrides === void 0 ? void 0 : pythPriceOverrides.get(constants_1.PYTHNET_CUSTODY_PRICE_USDC_ACCOUNT.toBase58())) !== null && _b !== void 0 ? _b : pythOracle_1.PythOracle.fetch(oracle_1.PYTH_USDC_ORACLE_SETTINGS, //@ts-ignore
463
+ [oracleAccountInfos.get(constants_1.PYTHNET_CUSTODY_PRICE_USDC_ACCOUNT.toBase58())]);
464
+ let totalValue = new decimal_js_1.default(0);
465
+ for (let i = 0; i < basket.numTokens; i++) {
466
+ const oraclePrice = oracle_2.PriceAggregator.fetch(basket.composition[i].oracleAggregator, //@ts-ignore
467
+ [basket.lutPubkeys[0], basket.lutPubkeys[1]], oracleAccountInfos, solPrice, usdcPrice, pythPriceOverrides);
468
+ let amount = new decimal_js_1.default(basket.composition[i].amount.toString());
469
+ const value = oraclePrice.price.mul(amount);
470
+ basket.composition[i].price = oraclePrice;
471
+ basket.composition[i].value = value;
472
+ totalValue = totalValue.add(value);
473
+ }
474
+ basket.tvl = totalValue;
475
+ let supplyOutstanding = new decimal_js_1.default(basket.supplyOutstanding.toString());
476
+ if (supplyOutstanding.gt(new decimal_js_1.default(0))) {
477
+ basket.price = totalValue.div(supplyOutstanding);
478
+ }
479
+ return basket;
480
+ }
481
+ function loadBasketPriceWithPythPriceOverrides(basket, connection, pythPriceOverrides) {
482
+ return __awaiter(this, void 0, void 0, function* () {
483
+ const oracleAccountInfos = yield fetchBasketOracleAccountInfos(connection, basket);
484
+ return loadBasketPriceFromOracleAccountInfosWithPythPriceOverrides(basket, oracleAccountInfos, pythPriceOverrides);
485
+ });
486
+ }
456
487
  function loadBasketPrice(basket, connection) {
457
488
  return __awaiter(this, void 0, void 0, function* () {
458
489
  let oracleAccountInfos = yield fetchBasketOracleAccountInfos(connection, basket);
@@ -176,7 +176,7 @@ function decodeTaskDataForType(intent) {
176
176
  conf_thresh_bps: oracleAggregator.confThreshBps,
177
177
  conf_multiplier: (0, fraction_1.fractionToDecimal)(oracleAggregator.confMultiplier).toNumber(),
178
178
  oracles: oracleAggregator.oracles.slice(0, oracleAggregator.numOracles).map(oracle => {
179
- var _a;
179
+ var _a, _b;
180
180
  return ({
181
181
  oracle_type: (_a = oracle_1.ORACLE_TYPES_STRINGS.get(oracle.oracleSettings.oracleType)) !== null && _a !== void 0 ? _a : "example",
182
182
  account_lut_id: oracle.accountsToLoadLutIds[0],
@@ -194,6 +194,7 @@ function decodeTaskDataForType(intent) {
194
194
  token_decimals: oracle.oracleSettings.tokenDecimals,
195
195
  twap_seconds_ago: parseInt(oracle.oracleSettings.twapSecondsAgo.toString()),
196
196
  twap_secondary_seconds_ago: parseInt(oracle.oracleSettings.twapSecondarySecondsAgo.toString()),
197
+ quote: (_b = oracle_1.QUOTES_STRINGS.get(oracle.oracleSettings.quote)) !== null && _b !== void 0 ? _b : "usd",
197
198
  });
198
199
  }),
199
200
  };
@@ -40,4 +40,4 @@ export declare function getSwapPairs(rebalanceIntent: RebalanceIntent, basket: B
40
40
  outAmount: number;
41
41
  value: number;
42
42
  }[];
43
- export declare function isRebalanceRequired(rebalanceIntent: RebalanceIntent, basket: Basket): boolean;
43
+ export declare function isRebalanceRequired(basket: Basket, connection: Connection): Promise<boolean>;