@symmetry-hq/temp-v3-sdk 0.0.39 → 0.0.40

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.
@@ -20,3 +20,4 @@ export declare const MAX_SUPPORTED_TOKENS_PER_BASKET: number;
20
20
  export declare const MAX_ORACLES_PER_TOKEN: number;
21
21
  export declare const MAX_EXTRA_DATA_PER_ORACLE: number;
22
22
  export declare const LUT_EXTEND_BATCH_SIZE = 20;
23
+ export declare const UPDATE_TOKEN_PRICES_MAX_ACCOUNTS = 50;
@@ -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.LUT_EXTEND_BATCH_SIZE = exports.MAX_EXTRA_DATA_PER_ORACLE = exports.MAX_ORACLES_PER_TOKEN = exports.MAX_SUPPORTED_TOKENS_PER_BASKET = exports.USDC_DECIMALS = exports.WSOL_DECIMALS = exports.HUNDRED_PERCENT_BPS = exports.X64 = exports.MAX_TRANSFER_TOKENS = exports.MAX_MANAGERS_PER_BASKET = exports.INTENT_TASK_DATA_SIZE = exports.PYTHNET_CUSTODY_PRICE_USDC_ACCOUNT = exports.PYTHNET_CUSTODY_PRICE_WSOL_ACCOUNT = exports.MINTS = exports.RENT_SYSVAR_ID = exports.ADDRESS_LOOKUP_TABLE_PROGRAM_ID = exports.METADATA_PROGRAM_ID = exports.BASKETS_V3_PROGRAM_ID = exports.PRIORITY_FEE = exports.COMPUTE_UNITS = void 0;
6
+ exports.UPDATE_TOKEN_PRICES_MAX_ACCOUNTS = exports.LUT_EXTEND_BATCH_SIZE = exports.MAX_EXTRA_DATA_PER_ORACLE = exports.MAX_ORACLES_PER_TOKEN = exports.MAX_SUPPORTED_TOKENS_PER_BASKET = exports.USDC_DECIMALS = exports.WSOL_DECIMALS = exports.HUNDRED_PERCENT_BPS = exports.X64 = exports.MAX_TRANSFER_TOKENS = exports.MAX_MANAGERS_PER_BASKET = exports.INTENT_TASK_DATA_SIZE = exports.PYTHNET_CUSTODY_PRICE_USDC_ACCOUNT = exports.PYTHNET_CUSTODY_PRICE_WSOL_ACCOUNT = exports.MINTS = exports.RENT_SYSVAR_ID = exports.ADDRESS_LOOKUP_TABLE_PROGRAM_ID = exports.METADATA_PROGRAM_ID = exports.BASKETS_V3_PROGRAM_ID = exports.PRIORITY_FEE = exports.COMPUTE_UNITS = void 0;
7
7
  const web3_js_1 = require("@solana/web3.js");
8
8
  const decimal_js_1 = __importDefault(require("decimal.js"));
9
9
  exports.COMPUTE_UNITS = 1000000;
@@ -35,3 +35,4 @@ exports.MAX_SUPPORTED_TOKENS_PER_BASKET = 100;
35
35
  exports.MAX_ORACLES_PER_TOKEN = 4;
36
36
  exports.MAX_EXTRA_DATA_PER_ORACLE = 4;
37
37
  exports.LUT_EXTEND_BATCH_SIZE = 20;
38
+ exports.UPDATE_TOKEN_PRICES_MAX_ACCOUNTS = 50;
@@ -131,6 +131,17 @@ export declare class SymmetryCore {
131
131
  basket: string;
132
132
  rebalance_intent: string;
133
133
  }): Promise<TxPayloadBatchSequence>;
134
+ /**
135
+ * Build update token prices transactions.
136
+ * For pyth oracle accounts, fetches feed IDs, builds vaa [create init encode], [write verify],
137
+ * [update feed], [close vaa] instructions. For all tokens, builds [update token prices] instructions.
138
+ * and returns TxPayloadBatchSequence ready for signAndSendTxPayloadBatchSequence.
139
+ * Batch layout:
140
+ * batch 0: [ [vaa1CreateInitEncodeIxs], [vaa2CreateInitEncodeIxs], ... ]
141
+ * batch 1: [ [vaa1WriteVerifyIxs], [vaa2WriteVerifyIxs], ... ]
142
+ * batch 2: [ [updateFeed1], [updateFeed2], ... ]
143
+ * batch 3: [ [updateTokenPrices], [...], [closeVaa1Ix, closeVaa2Ix, ...]]
144
+ */
134
145
  updateTokenPricesTx(params: {
135
146
  keeper: string;
136
147
  basket: string;
package/dist/src/index.js CHANGED
@@ -37,10 +37,12 @@ const fraction_1 = require("./layouts/fraction");
37
37
  const intent_1 = require("./layouts/intents/intent");
38
38
  Object.defineProperty(exports, "TaskType", { enumerable: true, get: function () { return intent_1.TaskType; } });
39
39
  const rebalanceIntent_2 = require("./layouts/intents/rebalanceIntent");
40
+ const oracle_1 = require("./layouts/oracle");
40
41
  const basket_1 = require("./states/basket");
41
42
  const config_1 = require("./states/config");
42
43
  const intent_2 = require("./states/intents/intent");
43
44
  const rebalanceIntent_3 = require("./states/intents/rebalanceIntent");
45
+ const pythOracle_1 = require("./states/oracles/pythOracle");
44
46
  const txUtils_1 = require("./txUtils");
45
47
  class SymmetryCore {
46
48
  constructor(params) {
@@ -860,30 +862,47 @@ class SymmetryCore {
860
862
  return txPayloadBatchSequence;
861
863
  });
862
864
  }
865
+ /**
866
+ * Build update token prices transactions.
867
+ * For pyth oracle accounts, fetches feed IDs, builds vaa [create init encode], [write verify],
868
+ * [update feed], [close vaa] instructions. For all tokens, builds [update token prices] instructions.
869
+ * and returns TxPayloadBatchSequence ready for signAndSendTxPayloadBatchSequence.
870
+ * Batch layout:
871
+ * batch 0: [ [vaa1CreateInitEncodeIxs], [vaa2CreateInitEncodeIxs], ... ]
872
+ * batch 1: [ [vaa1WriteVerifyIxs], [vaa2WriteVerifyIxs], ... ]
873
+ * batch 2: [ [updateFeed1], [updateFeed2], ... ]
874
+ * batch 3: [ [updateTokenPrices], [...], [closeVaa1Ix, closeVaa2Ix, ...]]
875
+ */
863
876
  updateTokenPricesTx(params) {
864
877
  return __awaiter(this, void 0, void 0, function* () {
865
878
  let keeper = new web3_js_1.PublicKey(params.keeper);
866
879
  let rebalanceIntent = new web3_js_1.PublicKey(params.rebalance_intent);
867
880
  let basketRebalanceIntent = (0, pda_1.getRebalanceIntentPda)(new web3_js_1.PublicKey(params.basket), new web3_js_1.PublicKey(params.basket));
868
881
  let basket = yield this.fetchBasket(params.basket);
869
- let ixs = [];
870
- let batchSize = 7;
871
- for (let batchStart = 0; batchStart < basket.numTokens; batchStart += batchSize) {
882
+ let pythPriceFeeds = [];
883
+ let updateTokenPricesIxs = [];
884
+ for (let startIndex = 0; startIndex < basket.numTokens; startIndex++) {
872
885
  let allKeys = [];
873
886
  let tokenIndices = [];
874
- for (let i = batchStart; i < basket.numTokens && i < batchStart + batchSize; i++) {
875
- tokenIndices.push(i);
876
- let agg = basket.composition[i].oracleAggregator;
887
+ for (let endIndex = startIndex; endIndex < basket.numTokens; endIndex++) {
888
+ let numAccounts = basket.composition[endIndex].oracleAggregator.oracles
889
+ .slice(0, basket.composition[endIndex].oracleAggregator.numOracles)
890
+ .reduce((acc, oracle) => acc + oracle.oracleSettings.numRequiredAccounts, 0);
891
+ if (allKeys.length + numAccounts > constants_1.UPDATE_TOKEN_PRICES_MAX_ACCOUNTS)
892
+ break;
893
+ if (tokenIndices.length == 20)
894
+ break;
895
+ startIndex = endIndex;
896
+ tokenIndices.push(endIndex);
897
+ let agg = basket.composition[endIndex].oracleAggregator;
877
898
  for (let i = 0; i < agg.numOracles; i++) {
878
- const oracleData = agg.oracles[i];
899
+ const oracleData = agg.oracles[endIndex];
879
900
  for (let j = 0; j < oracleData.oracleSettings.numRequiredAccounts; j++) {
880
901
  const lutId = oracleData.accountsToLoadLutIds[j];
881
902
  const lutIdx = oracleData.accountsToLoadLutIndices[j];
882
- if (lutId === 0 && lutIdx === 0)
883
- continue;
884
- if (!basket.lutPubkeys)
885
- continue;
886
903
  allKeys.push(basket.lutPubkeys[lutId].state.addresses[lutIdx]);
904
+ if (oracleData.oracleSettings.oracleType === oracle_1.OracleType.Pyth)
905
+ pythPriceFeeds.push(basket.lutPubkeys[lutId].state.addresses[lutIdx]);
887
906
  }
888
907
  }
889
908
  }
@@ -891,7 +910,7 @@ class SymmetryCore {
891
910
  tokenIndices.push(0);
892
911
  // TODO: in last instruction we should include performance fee accounts
893
912
  let performanceFees = basket.settings.fees.hostPerformanceFeeBps + basket.settings.fees.creatorPerformanceFeeBps + basket.settings.fees.managersPerformanceFeeBps;
894
- ixs.push((0, priceUpdate_1.updateTokenPricesIx)({
913
+ updateTokenPricesIxs.push((0, priceUpdate_1.updateTokenPricesIx)({
895
914
  keeper: keeper,
896
915
  basket: basket.ownAddress,
897
916
  rebalanceIntent: rebalanceIntent,
@@ -903,16 +922,67 @@ class SymmetryCore {
903
922
  basketMint: performanceFees > 0 ? basket.mint : undefined,
904
923
  }));
905
924
  }
906
- let txBatchData = { batches: [ixs.map(ix => ({
907
- payer: keeper,
908
- instructions: [
909
- ix,
910
- web3_js_1.ComputeBudgetProgram.setComputeUnitLimit({ units: constants_1.COMPUTE_UNITS }),
911
- web3_js_1.ComputeBudgetProgram.setComputeUnitPrice({ microLamports: this.sdkParams.priorityFee }),
912
- ],
913
- lookupTables: [basket.lookupTables.active[0], basket.lookupTables.active[1]],
914
- }))] };
925
+ let feedIds = yield (0, pythOracle_1.fetchFeedIdsFromAccounts)(this.sdkParams.connection, pythPriceFeeds);
926
+ const { vaaCreateInitEncodeIxs, vaaWriteVerifyIxs, updateFeedIxs, closeVaaIxs } = yield (0, pythOracle_1.buildPythPriceFeedUpdateIxs)(keeper, feedIds.feedIds);
927
+ let txBatchData = { batches: [
928
+ [
929
+ ...vaaCreateInitEncodeIxs.map(ixs => ({
930
+ payer: keeper,
931
+ instructions: [
932
+ ...ixs.ixs,
933
+ web3_js_1.ComputeBudgetProgram.setComputeUnitLimit({ units: constants_1.COMPUTE_UNITS }),
934
+ web3_js_1.ComputeBudgetProgram.setComputeUnitPrice({ microLamports: this.sdkParams.priorityFee }),
935
+ ],
936
+ lookupTables: [],
937
+ })),
938
+ ],
939
+ [
940
+ ...vaaWriteVerifyIxs.map(ixs => ({
941
+ payer: keeper,
942
+ instructions: [
943
+ ...ixs,
944
+ web3_js_1.ComputeBudgetProgram.setComputeUnitLimit({ units: constants_1.COMPUTE_UNITS }),
945
+ web3_js_1.ComputeBudgetProgram.setComputeUnitPrice({ microLamports: this.sdkParams.priorityFee }),
946
+ ],
947
+ lookupTables: [],
948
+ })),
949
+ ],
950
+ [
951
+ ...updateFeedIxs.map(ix => ({
952
+ payer: keeper,
953
+ instructions: [
954
+ ix,
955
+ web3_js_1.ComputeBudgetProgram.setComputeUnitLimit({ units: constants_1.COMPUTE_UNITS }),
956
+ web3_js_1.ComputeBudgetProgram.setComputeUnitPrice({ microLamports: this.sdkParams.priorityFee }),
957
+ ],
958
+ lookupTables: [],
959
+ })),
960
+ ],
961
+ [
962
+ ...updateTokenPricesIxs.map(ix => ({
963
+ payer: keeper,
964
+ instructions: [
965
+ ix,
966
+ web3_js_1.ComputeBudgetProgram.setComputeUnitLimit({ units: constants_1.COMPUTE_UNITS }),
967
+ web3_js_1.ComputeBudgetProgram.setComputeUnitPrice({ microLamports: this.sdkParams.priorityFee }),
968
+ ],
969
+ lookupTables: [basket.lookupTables.active[0], basket.lookupTables.active[1]],
970
+ })),
971
+ {
972
+ payer: keeper,
973
+ instructions: [
974
+ ...closeVaaIxs,
975
+ web3_js_1.ComputeBudgetProgram.setComputeUnitLimit({ units: constants_1.COMPUTE_UNITS }),
976
+ web3_js_1.ComputeBudgetProgram.setComputeUnitPrice({ microLamports: this.sdkParams.priorityFee }),
977
+ ],
978
+ lookupTables: [],
979
+ }
980
+ ],
981
+ ] };
915
982
  let versionedTxs = yield (0, txUtils_1.prepareVersionedTxs)(this.sdkParams.connection, txBatchData);
983
+ for (let [txId, vaaCreateInitEncodeIx] of vaaCreateInitEncodeIxs.entries()) {
984
+ versionedTxs.batches[0][txId].sign([vaaCreateInitEncodeIx.signer]);
985
+ }
916
986
  let txPayloadBatchSequence = (0, txUtils_1.prepareTxPayloadBatchSequence)(txBatchData, versionedTxs);
917
987
  return txPayloadBatchSequence;
918
988
  });
@@ -1,7 +1,8 @@
1
1
  import { BN } from '@coral-xyz/anchor';
2
2
  import { HermesClient } from '@pythnetwork/hermes-client';
3
- import { AccountInfo, Connection, Keypair, PublicKey, Signer, Transaction, TransactionInstruction, VersionedTransaction } from '@solana/web3.js';
3
+ import { AccountInfo, Connection, Keypair, PublicKey, TransactionInstruction } from '@solana/web3.js';
4
4
  import { OracleSettings } from '../../layouts/oracle';
5
+ import { TxBatchData } from '../../txUtils';
5
6
  import { OraclePrice } from './oracle';
6
7
  export type VerificationLevel = {
7
8
  kind: 'Partial';
@@ -49,22 +50,6 @@ export declare function parseAccumulatorUpdateData(data: Buffer): {
49
50
  proof: number[][];
50
51
  }[];
51
52
  };
52
- /**
53
- * Build instructions to update Pyth price feed accounts (full verification)
54
- */
55
- export declare function buildPythPriceFeedUpdateInstructions(connection: Connection, payer: PublicKey, priceFeedIds: string[], shardId?: number, hermesClient?: HermesClient): Promise<PythUpdateResult>;
56
- export declare const DEFAULT_COMPUTE_BUDGET_UNITS = 200000;
57
- /**
58
- * The maximum size of a Solana transaction, leaving some room for the compute budget instructions.
59
- */
60
- export declare const PACKET_DATA_SIZE_WITH_ROOM_FOR_COMPUTE_BUDGET: number;
61
- /**
62
- * The maximum number of transactions in a Jito bundle.
63
- */
64
- export declare const JITO_BUNDLE_SIZE = 5;
65
- export declare const DEFAULT_PRIORITY_FEE_CONFIG: {
66
- computeUnitPriceMicroLamports: number;
67
- };
68
53
  /**
69
54
  * Get the size of a transaction that would contain the provided array of instructions
70
55
  */
@@ -75,84 +60,44 @@ export declare function getSizeOfTransaction(instructions: TransactionInstructio
75
60
  }): number;
76
61
  /** Get the size of n in bytes when serialized as a CompressedU16 */
77
62
  export declare function getSizeOfCompressedU16(n: number): number;
63
+ export interface InstructionBatch {
64
+ instructions: TransactionInstruction[];
65
+ signers: Keypair[];
66
+ computeUnits: number;
67
+ }
78
68
  /**
79
- * This class batches instructions into transactions efficiently.
69
+ * Fetch Pyth price accounts from RPC and extract feed IDs
80
70
  */
81
- export declare class TransactionBuilder {
82
- private payer;
83
- private connection;
84
- private addressLookupTable?;
85
- private transactionInstructions;
86
- constructor(payer: PublicKey, connection: Connection, addressLookupTable?: {
87
- state: {
88
- addresses: PublicKey[];
89
- };
90
- } | undefined);
91
- addInstruction(args: {
92
- instruction: TransactionInstruction;
93
- signers: Signer[];
94
- computeUnits?: number;
95
- }): void;
96
- addInstructions(instructions: {
97
- instruction: TransactionInstruction;
98
- signers: Signer[];
99
- computeUnits?: number;
100
- }[]): void;
101
- buildVersionedTransactions(args: {
102
- computeUnitPriceMicroLamports?: number;
103
- tightComputeBudget?: boolean;
104
- jitoTipLamports?: number;
105
- }): Promise<{
106
- tx: VersionedTransaction;
107
- signers: Signer[];
108
- }[]>;
109
- buildLegacyTransactions(args: {
110
- computeUnitPriceMicroLamports?: number;
111
- tightComputeBudget?: boolean;
112
- jitoTipLamports?: number;
113
- }): {
114
- tx: Transaction;
115
- signers: Signer[];
116
- }[];
117
- static batchIntoLegacyTransactions(instructions: TransactionInstruction[], priorityFeeConfig: {
118
- computeUnitPriceMicroLamports?: number;
119
- tightComputeBudget?: boolean;
120
- jitoTipLamports?: number;
121
- }): Transaction[];
122
- static batchIntoVersionedTransactions(payer: PublicKey, connection: Connection, instructions: {
123
- instruction: TransactionInstruction;
124
- signers: Signer[];
125
- computeUnits?: number;
126
- }[], priorityFeeConfig: {
127
- computeUnitPriceMicroLamports?: number;
128
- tightComputeBudget?: boolean;
129
- jitoTipLamports?: number;
130
- }, addressLookupTable?: {
131
- state: {
132
- addresses: PublicKey[];
133
- };
134
- }): Promise<{
135
- tx: VersionedTransaction;
136
- signers: Signer[];
137
- }[]>;
138
- static addPriorityFee(transaction: Transaction, priorityFeeConfig: {
139
- computeUnitPriceMicroLamports?: number;
140
- tightComputeBudget?: boolean;
141
- jitoTipLamports?: number;
142
- }): void;
71
+ export declare function fetchFeedIdsFromAccounts(connection: Connection, priceAccounts: PublicKey[]): Promise<{
72
+ feedIds: string[];
73
+ feedIdToAccount: Map<string, PublicKey>;
74
+ }>;
75
+ export interface PythUpdateTxResult {
76
+ txBatchData: TxBatchData;
77
+ /** Keypairs that must sign their respective transactions before sending */
78
+ extraSigners: Map<number, Keypair[]>;
143
79
  }
144
- export declare const isVersionedTransaction: (tx: Transaction | VersionedTransaction) => tx is VersionedTransaction;
145
80
  /**
146
- * Send a set of transactions to the network (with retries), using a plain Signer for the payer
81
+ * Build Pyth price feed update as TxBatchData compatible with SDK txUtils.
82
+ *
83
+ * TxBatchData.batches layout:
84
+ * batch 0 (sequential): [createAccount + initEncodedVaa + writeVaa_part1]
85
+ * batch 1 (sequential): [writeVaa_part2 + verifyEncodedVaa]
86
+ * batch 2 (parallel): [updateFeed_0], [updateFeed_1], ... [updateFeed_N-2]
87
+ * batch 3 (sequential): [updateFeed_last + closeEncodedVaa]
88
+ *
89
+ * Transactions within each batch are sent in parallel by sendVersionedTxs.
90
+ * Batches are sent sequentially.
147
91
  */
148
- export declare function sendTransactions(transactions: {
149
- tx: Transaction | VersionedTransaction;
150
- signers?: Signer[];
151
- }[], connection: Connection, payer: Signer, maxRetries?: number): Promise<string[]>;
152
- export declare function buildPythPriceFeedUpdateTxs(connection: Connection, payer: PublicKey, priceFeedIds: string[], shardId?: number, computeUnitPriceMicroLamports?: number, hermesClient?: HermesClient): Promise<{
153
- tx: VersionedTransaction;
154
- signers: Signer[];
155
- }[]>;
92
+ export declare function buildPythPriceFeedUpdateIxs(payer: PublicKey, priceFeedIds: string[], defaultShardId?: number, hermesClient?: HermesClient): Promise<{
93
+ vaaCreateInitEncodeIxs: {
94
+ ixs: TransactionInstruction[];
95
+ signer: Keypair;
96
+ }[];
97
+ vaaWriteVerifyIxs: TransactionInstruction[][];
98
+ updateFeedIxs: TransactionInstruction[];
99
+ closeVaaIxs: TransactionInstruction[];
100
+ }>;
156
101
  export declare class PriceFeedMessage {
157
102
  feedId: Buffer;
158
103
  price: BN;
@@ -174,6 +119,14 @@ export declare class PriceFeedMessage {
174
119
  });
175
120
  static decode(buf: Buffer, offset?: number): [PriceFeedMessage, number];
176
121
  }
122
+ export declare class PythState {
123
+ writeAuthority: PublicKey;
124
+ verificationLevel: VerificationLevel;
125
+ priceMessage: PriceFeedMessage;
126
+ postedSlot: BN;
127
+ constructor(writeAuthority: PublicKey, verificationLevel: VerificationLevel, priceMessage: PriceFeedMessage, postedSlot: BN);
128
+ static decode(buf: Buffer, offset?: number): [PythState, number];
129
+ }
177
130
  export declare class PythOracle {
178
131
  static fetch(oracleParams: OracleSettings, accountInfos: AccountInfo<Buffer>[], solPrice?: OraclePrice, usdPrice?: OraclePrice): OraclePrice;
179
132
  }