@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,120 @@
1
+ import Decimal from 'decimal.js';
2
+ import BN from 'bn.js';
3
+ import { AccountInfo, PublicKey } from '@solana/web3.js';
4
+ import { OracleSettings, Side } from '../../layouts/oracle';
5
+ import { OraclePrice } from './oracle';
6
+ declare class Observation {
7
+ timestamp: BN;
8
+ cumT0Price: BN;
9
+ cumT1Price: BN;
10
+ constructor(params: {
11
+ timestamp: BN;
12
+ cumT0Price: BN;
13
+ cumT1Price: BN;
14
+ });
15
+ static decode(data: Buffer, offset?: number): [Observation, number];
16
+ sub(other: Observation): Observation;
17
+ add(other: Observation): Observation;
18
+ getWeightedObservation(time: BN): Observation;
19
+ adjustToTimestamp(targetTimestamp: BN, observationPrev: Observation): Observation;
20
+ getTwap(side: Side): BN;
21
+ }
22
+ declare class VaultState {
23
+ mint: PublicKey;
24
+ owner: PublicKey;
25
+ amount: string;
26
+ constructor(params: {
27
+ mint: PublicKey;
28
+ owner: PublicKey;
29
+ amount: string;
30
+ });
31
+ static decode(data: Buffer, offset?: number): [VaultState, number];
32
+ }
33
+ declare class PoolState {
34
+ ammConfig: PublicKey;
35
+ poolCreator: PublicKey;
36
+ token0Vault: PublicKey;
37
+ token1Vault: PublicKey;
38
+ lpMint: PublicKey;
39
+ token0Mint: PublicKey;
40
+ token1Mint: PublicKey;
41
+ token0Program: PublicKey;
42
+ token1Program: PublicKey;
43
+ observationKey: PublicKey;
44
+ authBump: number;
45
+ status: number;
46
+ lpMintDecimals: number;
47
+ mint0Decimals: number;
48
+ mint1Decimals: number;
49
+ lpSupply: BN;
50
+ protocolFeesToken0: BN;
51
+ protocolFeesToken1: BN;
52
+ fundFeesToken0: BN;
53
+ fundFeesToken1: BN;
54
+ openTime: BN;
55
+ recentEpoch: BN;
56
+ creatorFeeOn: number;
57
+ enableCreatorFee: boolean;
58
+ padding1: number[];
59
+ creatorFeesToken0: BN;
60
+ creatorFeesToken1: BN;
61
+ padding: BN[];
62
+ constructor(params: {
63
+ ammConfig: PublicKey;
64
+ poolCreator: PublicKey;
65
+ token0Vault: PublicKey;
66
+ token1Vault: PublicKey;
67
+ lpMint: PublicKey;
68
+ token0Mint: PublicKey;
69
+ token1Mint: PublicKey;
70
+ token0Program: PublicKey;
71
+ token1Program: PublicKey;
72
+ observationKey: PublicKey;
73
+ authBump: number;
74
+ status: number;
75
+ lpMintDecimals: number;
76
+ mint0Decimals: number;
77
+ mint1Decimals: number;
78
+ lpSupply: BN;
79
+ protocolFeesToken0: BN;
80
+ protocolFeesToken1: BN;
81
+ fundFeesToken0: BN;
82
+ fundFeesToken1: BN;
83
+ openTime: BN;
84
+ recentEpoch: BN;
85
+ creatorFeeOn: number;
86
+ enableCreatorFee: boolean;
87
+ padding1: number[];
88
+ creatorFeesToken0: BN;
89
+ creatorFeesToken1: BN;
90
+ padding: BN[];
91
+ });
92
+ static decode(data: Buffer, offset?: number): [PoolState, number];
93
+ }
94
+ export declare class RaydiumCPMMOracle {
95
+ static deriveObservationKey(poolId: PublicKey): [PublicKey, number];
96
+ static getObservationAtIndex(observations: Observation[], index: number): Observation;
97
+ static getObservationAtTimestamp(timestamp: BN, observations: Observation[], startIndex: number): Observation;
98
+ static getDeltaObservations(currentTime: BN, observations: Observation[], observationIndex: number, primarySeconds: BN, secondarySeconds: BN): Observation[];
99
+ static getDecimals(side: Side, mint0Decimals: number, mint1Decimals: number): number;
100
+ /**
101
+ * Calculate spot price from pool reserves after subtracting all fees.
102
+ * Returns: { netBase, netQuote, spotPrice } where spotPrice is in USD per base token.
103
+ */
104
+ static getSpotPriceWithReserves(poolState: PoolState, vault0State: VaultState, vault1State: VaultState, side: Side, quotePrice: OraclePrice): {
105
+ netBase: Decimal;
106
+ netQuote: Decimal;
107
+ spotPrice: Decimal;
108
+ };
109
+ static getTwapPrimary(currentTime: BN, observations: Observation[], observationIndex: number, side: Side, primarySeconds: BN, secondarySeconds: BN, mint0Decimals: number, mint1Decimals: number): Decimal;
110
+ static getTwapSecondary(currentTime: BN, observations: Observation[], observationIndex: number, side: Side, primarySeconds: BN, secondarySeconds: BN, mint0Decimals: number, mint1Decimals: number): Decimal;
111
+ /**
112
+ * Calculate max price impact for minLiquidity trade in both directions (buy and sell).
113
+ * Uses constant-product AMM formulas:
114
+ * - BUY: delta_base_out = netBase * delta_q / (netQuote + delta_q)
115
+ * - SELL: delta_quote_out = netQuote * delta_base / (netBase + delta_base)
116
+ */
117
+ static calculateMaxPriceImpactForMinLiquidity(oracleParams: OracleSettings, netBase: Decimal, netQuote: Decimal, spotPriceUsd: Decimal, quotePrice: OraclePrice): Decimal;
118
+ static fetch(oracleParams: OracleSettings, accountInfos: AccountInfo<Buffer>[], solPrice: OraclePrice, usdPrice: OraclePrice): OraclePrice;
119
+ }
120
+ export {};
@@ -0,0 +1,540 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.RaydiumCPMMOracle = void 0;
7
+ const decimal_js_1 = __importDefault(require("decimal.js"));
8
+ const bn_js_1 = __importDefault(require("bn.js"));
9
+ const web3_js_1 = require("@solana/web3.js");
10
+ const oracle_1 = require("../../layouts/oracle");
11
+ const oracle_2 = require("./oracle");
12
+ const CPMM_PROGRAM_ID = new web3_js_1.PublicKey("CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C");
13
+ const DEV_CPMM_PROGRAM_ID = new web3_js_1.PublicKey("DRaycpLY18LhpbydsBWbVJtxpNv9oXPgjRSfpF2bWpYb");
14
+ class Observation {
15
+ constructor(params) {
16
+ this.timestamp = params.timestamp;
17
+ this.cumT0Price = params.cumT0Price;
18
+ this.cumT1Price = params.cumT1Price;
19
+ }
20
+ static decode(data, offset = 0) {
21
+ const timestamp = new bn_js_1.default(data.subarray(offset, offset + 8), "le");
22
+ const cumT0Price = new bn_js_1.default(data.subarray(offset + 8, offset + 24), 'le');
23
+ const cumT1Price = new bn_js_1.default(data.subarray(offset + 24, offset + 40), 'le');
24
+ return [
25
+ new Observation({
26
+ timestamp,
27
+ cumT0Price,
28
+ cumT1Price
29
+ }),
30
+ offset + 40
31
+ ];
32
+ }
33
+ sub(other) {
34
+ if (!(other instanceof Observation)) {
35
+ throw new TypeError("Subtraction is only supported between Observation instances");
36
+ }
37
+ return new Observation({
38
+ timestamp: this.timestamp.sub(other.timestamp),
39
+ cumT0Price: this.cumT0Price.sub(other.cumT0Price),
40
+ cumT1Price: this.cumT1Price.sub(other.cumT1Price),
41
+ });
42
+ }
43
+ add(other) {
44
+ if (!(other instanceof Observation)) {
45
+ throw new TypeError("Addition is only supported between Observation instances");
46
+ }
47
+ return new Observation({
48
+ timestamp: this.timestamp.add(other.timestamp),
49
+ cumT0Price: this.cumT0Price.add(other.cumT0Price),
50
+ cumT1Price: this.cumT1Price.add(other.cumT1Price),
51
+ });
52
+ }
53
+ getWeightedObservation(time) {
54
+ const cumT0Price = this.cumT0Price.mul(time).div(this.timestamp);
55
+ const cumT1Price = this.cumT1Price.mul(time).div(this.timestamp);
56
+ return new Observation({
57
+ timestamp: time,
58
+ cumT0Price,
59
+ cumT1Price
60
+ });
61
+ }
62
+ adjustToTimestamp(targetTimestamp, observationPrev) {
63
+ // delta = self.sub(prevPbservation)
64
+ const delta = this.sub(observationPrev);
65
+ // weightedDelta = delta.getWeightedObservation(targetTimestamp - self.blockTimestamp)
66
+ const timeForWeighted = targetTimestamp.sub(this.timestamp);
67
+ const weightedDelta = delta.getWeightedObservation(timeForWeighted);
68
+ // return self.add(weightedDelta)
69
+ return this.add(weightedDelta);
70
+ }
71
+ getTwap(side) {
72
+ let cumPrice = new bn_js_1.default(0);
73
+ if (side === oracle_1.Side.Base)
74
+ cumPrice = this.cumT0Price;
75
+ else
76
+ cumPrice = this.cumT1Price;
77
+ return cumPrice.div(this.timestamp);
78
+ }
79
+ }
80
+ class VaultState {
81
+ constructor(params) {
82
+ this.mint = params.mint;
83
+ this.owner = params.owner;
84
+ this.amount = params.amount;
85
+ }
86
+ static decode(data, offset = 0) {
87
+ // mint (32)
88
+ const mint = new web3_js_1.PublicKey(data.slice(offset, offset + 32));
89
+ offset += 32;
90
+ // owner (32)
91
+ const owner = new web3_js_1.PublicKey(data.slice(offset, offset + 32));
92
+ offset += 32;
93
+ // amount u64 (8)
94
+ const amount = (new bn_js_1.default(data.subarray(offset, offset + 8), 'le')).toString();
95
+ offset += 8;
96
+ return [
97
+ new VaultState({ mint, owner, amount }),
98
+ offset
99
+ ];
100
+ }
101
+ }
102
+ class ObservationState {
103
+ constructor(params) {
104
+ this.initialized = params.initialized;
105
+ this.observationIndex = params.observationIndex;
106
+ this.poolId = params.poolId;
107
+ this.observations = params.observations;
108
+ this.padding = params.padding;
109
+ }
110
+ static decode(data, offset = 8) {
111
+ let cursor = offset;
112
+ const initialized = data.readUInt8(cursor) !== 0;
113
+ cursor += 1;
114
+ const observationIndex = data.readUInt16LE(cursor);
115
+ cursor += 2;
116
+ const poolId = new web3_js_1.PublicKey(data.subarray(cursor, cursor + 32));
117
+ cursor += 32;
118
+ const observations = [];
119
+ for (let i = 0; i < 100; i++) {
120
+ let obs;
121
+ [obs, cursor] = Observation.decode(data, cursor);
122
+ observations.push(obs);
123
+ }
124
+ const padding = [];
125
+ for (let i = 0; i < 4; i++) {
126
+ padding.push(new bn_js_1.default(data.subarray(cursor, cursor + 8), "le"));
127
+ cursor += 8;
128
+ }
129
+ return [
130
+ new ObservationState({
131
+ initialized,
132
+ observationIndex,
133
+ poolId,
134
+ observations,
135
+ padding
136
+ }),
137
+ cursor
138
+ ];
139
+ }
140
+ }
141
+ class PoolState {
142
+ constructor(params) {
143
+ this.ammConfig = params.ammConfig;
144
+ this.poolCreator = params.poolCreator;
145
+ this.token0Vault = params.token0Vault;
146
+ this.token1Vault = params.token1Vault;
147
+ this.lpMint = params.lpMint;
148
+ this.token0Mint = params.token0Mint;
149
+ this.token1Mint = params.token1Mint;
150
+ this.token0Program = params.token0Program;
151
+ this.token1Program = params.token1Program;
152
+ this.observationKey = params.observationKey;
153
+ this.authBump = params.authBump; // u8
154
+ this.status = params.status; // u8
155
+ this.lpMintDecimals = params.lpMintDecimals; // u8
156
+ this.mint0Decimals = params.mint0Decimals; // u8
157
+ this.mint1Decimals = params.mint1Decimals; // u8
158
+ this.lpSupply = params.lpSupply; // u64
159
+ this.protocolFeesToken0 = params.protocolFeesToken0; // u64
160
+ this.protocolFeesToken1 = params.protocolFeesToken1; // u64
161
+ this.fundFeesToken0 = params.fundFeesToken0; // u64
162
+ this.fundFeesToken1 = params.fundFeesToken1; // u64
163
+ this.openTime = params.openTime; // u64
164
+ this.recentEpoch = params.recentEpoch; // u64
165
+ this.creatorFeeOn = params.creatorFeeOn; //u8
166
+ this.enableCreatorFee = params.enableCreatorFee;
167
+ this.padding1 = params.padding1; // [u8; 6]
168
+ this.creatorFeesToken0 = params.creatorFeesToken0; // u64
169
+ this.creatorFeesToken1 = params.creatorFeesToken1; // u64
170
+ this.padding = params.padding; // [u64; 28]
171
+ }
172
+ static decode(data, offset = 8) {
173
+ let cursor = offset;
174
+ const ammConfig = new web3_js_1.PublicKey(data.subarray(cursor, cursor + 32));
175
+ cursor += 32;
176
+ const poolCreator = new web3_js_1.PublicKey(data.subarray(cursor, cursor + 32));
177
+ cursor += 32;
178
+ const token0Vault = new web3_js_1.PublicKey(data.subarray(cursor, cursor + 32));
179
+ cursor += 32;
180
+ const token1Vault = new web3_js_1.PublicKey(data.subarray(cursor, cursor + 32));
181
+ cursor += 32;
182
+ const lpMint = new web3_js_1.PublicKey(data.subarray(cursor, cursor + 32));
183
+ cursor += 32;
184
+ const token0Mint = new web3_js_1.PublicKey(data.subarray(cursor, cursor + 32));
185
+ cursor += 32;
186
+ const token1Mint = new web3_js_1.PublicKey(data.subarray(cursor, cursor + 32));
187
+ cursor += 32;
188
+ const token0Program = new web3_js_1.PublicKey(data.subarray(cursor, cursor + 32));
189
+ cursor += 32;
190
+ const token1Program = new web3_js_1.PublicKey(data.subarray(cursor, cursor + 32));
191
+ cursor += 32;
192
+ const observationKey = new web3_js_1.PublicKey(data.subarray(cursor, cursor + 32));
193
+ cursor += 32;
194
+ const authBump = data.readUInt8(cursor);
195
+ cursor += 1;
196
+ const status = data.readUInt8(cursor);
197
+ cursor += 1;
198
+ const lpMintDecimals = data.readUInt8(cursor);
199
+ cursor += 1;
200
+ const mint0Decimals = data.readUInt8(cursor);
201
+ cursor += 1;
202
+ const mint1Decimals = data.readUInt8(cursor);
203
+ cursor += 1;
204
+ const lpSupply = new bn_js_1.default(data.subarray(cursor, cursor + 8), "le");
205
+ cursor += 8;
206
+ const protocolFeesToken0 = new bn_js_1.default(data.subarray(cursor, cursor + 8), "le");
207
+ cursor += 8;
208
+ const protocolFeesToken1 = new bn_js_1.default(data.subarray(cursor, cursor + 8), "le");
209
+ cursor += 8;
210
+ const fundFeesToken0 = new bn_js_1.default(data.subarray(cursor, cursor + 8), "le");
211
+ cursor += 8;
212
+ const fundFeesToken1 = new bn_js_1.default(data.subarray(cursor, cursor + 8), "le");
213
+ cursor += 8;
214
+ const openTime = new bn_js_1.default(data.subarray(cursor, cursor + 8), "le");
215
+ cursor += 8;
216
+ const recentEpoch = new bn_js_1.default(data.subarray(cursor, cursor + 8), "le");
217
+ cursor += 8;
218
+ const creatorFeeOn = data.readUInt8(cursor);
219
+ cursor += 1;
220
+ const enableCreatorFee = !!data.readUInt8(cursor);
221
+ cursor += 1;
222
+ const padding1 = [];
223
+ for (let i = 0; i < 6; i++) {
224
+ padding1.push(data.readUInt8(cursor));
225
+ cursor += 1;
226
+ }
227
+ const creatorFeesToken0 = new bn_js_1.default(data.subarray(cursor, cursor + 8), "le");
228
+ cursor += 8;
229
+ const creatorFeesToken1 = new bn_js_1.default(data.subarray(cursor, cursor + 8), "le");
230
+ cursor += 8;
231
+ const padding = [];
232
+ for (let i = 0; i < 28; i++) {
233
+ padding.push(new bn_js_1.default(data.subarray(cursor, cursor + 8), "le"));
234
+ cursor += 8;
235
+ }
236
+ return [
237
+ new PoolState({
238
+ ammConfig,
239
+ poolCreator,
240
+ token0Vault,
241
+ token1Vault,
242
+ lpMint,
243
+ token0Mint,
244
+ token1Mint,
245
+ token0Program,
246
+ token1Program,
247
+ observationKey,
248
+ authBump,
249
+ status,
250
+ lpMintDecimals,
251
+ mint0Decimals,
252
+ mint1Decimals,
253
+ lpSupply,
254
+ protocolFeesToken0,
255
+ protocolFeesToken1,
256
+ fundFeesToken0,
257
+ fundFeesToken1,
258
+ openTime,
259
+ recentEpoch,
260
+ creatorFeeOn,
261
+ enableCreatorFee,
262
+ padding1,
263
+ creatorFeesToken0,
264
+ creatorFeesToken1,
265
+ padding,
266
+ }),
267
+ cursor,
268
+ ];
269
+ }
270
+ }
271
+ class RaydiumCPMMOracle {
272
+ // poolId: PublicKey;
273
+ // poolState: PoolState;
274
+ // observationState: ObservationState;
275
+ // vault0: VaultState;
276
+ // vault1: VaultState;
277
+ // constructor(
278
+ // oracleParams: OracleSettings,
279
+ // cpmmParams: {
280
+ // poolId: PublicKey;
281
+ // poolState: PoolState;
282
+ // observationState: ObservationState,
283
+ // vault0: VaultState,
284
+ // vault1: VaultState,
285
+ // }){
286
+ // super(
287
+ // oracleParams
288
+ // );
289
+ // this.poolId = cpmmParams.poolId;
290
+ // this.poolState = cpmmParams.poolState;
291
+ // this.observationState = cpmmParams.observationState;
292
+ // this.vault0 = cpmmParams.vault0;
293
+ // this.vault1 = cpmmParams.vault1;
294
+ // }
295
+ static deriveObservationKey(poolId) {
296
+ const seeds = [
297
+ Buffer.from("observation"),
298
+ poolId.toBuffer(),
299
+ ];
300
+ return web3_js_1.PublicKey.findProgramAddressSync(seeds, CPMM_PROGRAM_ID);
301
+ }
302
+ ;
303
+ static getObservationAtIndex(observations, index) {
304
+ return observations[index];
305
+ }
306
+ static getObservationAtTimestamp(timestamp, observations, startIndex) {
307
+ let observationCurrent = this.getObservationAtIndex(observations, startIndex);
308
+ let index = startIndex;
309
+ // Loop backwards until we find the observation <= timestamp
310
+ while (observationCurrent.timestamp.gt(timestamp)) {
311
+ index = (index - 1 + 100) % 100;
312
+ observationCurrent = this.getObservationAtIndex(observations, index);
313
+ if (index === startIndex) {
314
+ throw Error("Observations do not go back far enough in time");
315
+ }
316
+ }
317
+ // Previous index for interpolation
318
+ const prevIndex = (index - 1 + 100) % 100;
319
+ const observationPrev = this.getObservationAtIndex(observations, prevIndex);
320
+ // Adjust current observation to the target timestamp
321
+ const result = observationCurrent.adjustToTimestamp(timestamp, observationPrev);
322
+ return result;
323
+ }
324
+ static getDeltaObservations(currentTime, observations, observationIndex, primarySeconds, secondarySeconds) {
325
+ const obsIndex = observationIndex;
326
+ const observationCurrent = this.getObservationAtTimestamp(currentTime, observations, obsIndex);
327
+ const observationPrimary = this.getObservationAtTimestamp(currentTime.sub(primarySeconds), observations, obsIndex);
328
+ const deltaPrimary = observationCurrent.sub(observationPrimary);
329
+ const observationSecondary = this.getObservationAtTimestamp(currentTime.sub(secondarySeconds), observations, obsIndex);
330
+ const deltaSecondary = observationCurrent.sub(observationSecondary);
331
+ return [deltaPrimary, deltaSecondary];
332
+ }
333
+ ;
334
+ static getDecimals(side, mint0Decimals, mint1Decimals) {
335
+ let dec;
336
+ if (side === oracle_1.Side.Base)
337
+ dec = mint0Decimals - mint1Decimals;
338
+ else
339
+ dec = mint1Decimals - mint0Decimals;
340
+ return dec;
341
+ }
342
+ // static getSpotPrice(
343
+ // baseAmount: BN, quoteAmount: BN, protocolFeesToken0: BN, protocolFeesToken1: BN,
344
+ // fundFeesToken0: BN, fundFeesToken1: BN, mint0Decimals: number, mint1Decimals: number, side: Side
345
+ // ): Decimal {
346
+ // let decimals = this.getDecimals(side, mint0Decimals, mint1Decimals);
347
+ // let fees0 = protocolFeesToken0.add(fundFeesToken0);
348
+ // let fees1 = protocolFeesToken1.add(fundFeesToken1);
349
+ // if(side === Side.Base) {
350
+ // baseAmount = baseAmount.sub(fees0);
351
+ // quoteAmount = quoteAmount.sub(fees1);
352
+ // }
353
+ // else {
354
+ // baseAmount = baseAmount.sub(fees1);
355
+ // quoteAmount = quoteAmount.sub(fees0);
356
+ // }
357
+ // let price_scaled = new Decimal(baseAmount.toString()).div(quoteAmount.toString());
358
+ // return price_scaled.div(10 ** decimals);
359
+ // }
360
+ /**
361
+ * Calculate spot price from pool reserves after subtracting all fees.
362
+ * Returns: { netBase, netQuote, spotPrice } where spotPrice is in USD per base token.
363
+ */
364
+ static getSpotPriceWithReserves(poolState, vault0State, vault1State, side, quotePrice) {
365
+ // Total fees per token (protocol + fund + creator)
366
+ let fees0 = new decimal_js_1.default(poolState.protocolFeesToken0.toString())
367
+ .add(new decimal_js_1.default(poolState.fundFeesToken0.toString()))
368
+ .add(new decimal_js_1.default(poolState.creatorFeesToken0.toString()));
369
+ let fees1 = new decimal_js_1.default(poolState.protocolFeesToken1.toString())
370
+ .add(new decimal_js_1.default(poolState.fundFeesToken1.toString()))
371
+ .add(new decimal_js_1.default(poolState.creatorFeesToken1.toString()));
372
+ // Swap fees if side is Quote
373
+ if (side === oracle_1.Side.Quote) {
374
+ [fees0, fees1] = [fees1, fees0];
375
+ }
376
+ // Get vault balances
377
+ const baseBalance = new decimal_js_1.default(vault0State.amount);
378
+ const quoteBalance = new decimal_js_1.default(vault1State.amount);
379
+ // Net reserves after subtracting fees
380
+ const netBase = baseBalance.sub(fees0);
381
+ const netQuote = quoteBalance.sub(fees1);
382
+ // Guard against zero or negative reserves
383
+ if (netBase.lte(0) || netQuote.lte(0)) {
384
+ return { netBase: new decimal_js_1.default(0), netQuote: new decimal_js_1.default(0), spotPrice: new decimal_js_1.default(0) };
385
+ }
386
+ // Relative price = netQuote / netBase (quote tokens per 1 base token)
387
+ // Example: 10,000 USDC / 100 SOL = 100 USDC per SOL
388
+ const relativePrice = netQuote.div(netBase);
389
+ // Convert to USD: spotPrice = relativePrice * quotePrice.price
390
+ // If quote is USDC and quotePrice.price ≈ 1, spotPrice ≈ relativePrice
391
+ // If quote is WSOL and quotePrice.price = $150, spotPrice = relativePrice * 150
392
+ const spotPrice = relativePrice.mul(quotePrice.price);
393
+ return { netBase, netQuote, spotPrice };
394
+ }
395
+ static getTwapPrimary(currentTime, observations, observationIndex, side, primarySeconds, secondarySeconds, mint0Decimals, mint1Decimals) {
396
+ let observation = this.getDeltaObservations(currentTime, observations, observationIndex, primarySeconds, secondarySeconds)[0];
397
+ // TODO: use constant for 2**32 number is not safe
398
+ let twap_scaled = new decimal_js_1.default(observation.getTwap(side).toString()).div(2 ** 32);
399
+ let twap = new decimal_js_1.default(twap_scaled.toString()).div(10 ** this.getDecimals(side, mint0Decimals, mint1Decimals));
400
+ return twap;
401
+ }
402
+ static getTwapSecondary(currentTime, observations, observationIndex, side, primarySeconds, secondarySeconds, mint0Decimals, mint1Decimals) {
403
+ let observation = this.getDeltaObservations(currentTime, observations, observationIndex, primarySeconds, secondarySeconds)[1];
404
+ // TODO: use constant for 2**32 number is not safe
405
+ let twap_scaled = new decimal_js_1.default(observation.getTwap(side).toString()).div(2 ** 32);
406
+ let twap = new decimal_js_1.default(twap_scaled.toString()).div(10 ** this.getDecimals(side, mint0Decimals, mint1Decimals));
407
+ return twap;
408
+ }
409
+ /**
410
+ * Calculate max price impact for minLiquidity trade in both directions (buy and sell).
411
+ * Uses constant-product AMM formulas:
412
+ * - BUY: delta_base_out = netBase * delta_q / (netQuote + delta_q)
413
+ * - SELL: delta_quote_out = netQuote * delta_base / (netBase + delta_base)
414
+ */
415
+ static calculateMaxPriceImpactForMinLiquidity(oracleParams, netBase, netQuote, spotPriceUsd, quotePrice) {
416
+ const minLiquidityUsd = new decimal_js_1.default(oracleParams.minLiquidity.toString());
417
+ if (spotPriceUsd.lte(0)) {
418
+ return new decimal_js_1.default(10000); // 100% impact - invalid
419
+ }
420
+ // Convert minLiquidity USD to quote tokens
421
+ // delta_q_tokens = minLiquidityUsd / quotePrice.price
422
+ const deltaQTokens = minLiquidityUsd.div(quotePrice.price);
423
+ // Require pool has at least that many quote tokens
424
+ if (netQuote.lt(deltaQTokens)) {
425
+ // Not enough liquidity - return max impact (will fail validation)
426
+ return new decimal_js_1.default(10000); // 100% impact
427
+ }
428
+ // === BUY simulation (user spends delta_q quote to receive base) ===
429
+ // delta_base_buy = netBase * delta_q / (netQuote + delta_q)
430
+ const denomBuy = netQuote.add(deltaQTokens);
431
+ const deltaBaseBuy = netBase.mul(deltaQTokens).div(denomBuy);
432
+ let impactBuy = new decimal_js_1.default(0);
433
+ if (deltaBaseBuy.gt(0)) {
434
+ // quote spent in USD = delta_q * quotePrice
435
+ const quoteUsd = deltaQTokens.mul(quotePrice.price);
436
+ // execution price in USD per base = quoteUsd / deltaBaseBuy
437
+ const execPriceBuy = quoteUsd.div(deltaBaseBuy);
438
+ // impact = |execPrice - spotPrice| / spotPrice
439
+ const diffBuy = execPriceBuy.sub(spotPriceUsd).abs();
440
+ impactBuy = diffBuy.div(spotPriceUsd);
441
+ }
442
+ // === SELL simulation (user sells base roughly equivalent to minLiquidity USD) ===
443
+ // Approximate base amount to sell: delta_base_sell = delta_q * netBase / netQuote
444
+ let deltaBaseSell = new decimal_js_1.default(0);
445
+ if (netQuote.gt(0)) {
446
+ deltaBaseSell = deltaQTokens.mul(netBase).div(netQuote);
447
+ }
448
+ let impactSell = new decimal_js_1.default(0);
449
+ if (deltaBaseSell.gt(0)) {
450
+ // delta_quote_out = netQuote * delta_base_sell / (netBase + delta_base_sell)
451
+ const denomSell = netBase.add(deltaBaseSell);
452
+ const deltaQuoteOut = netQuote.mul(deltaBaseSell).div(denomSell);
453
+ // quote out in USD
454
+ const quoteOutUsd = deltaQuoteOut.mul(quotePrice.price);
455
+ // execution price in USD per base = quoteOutUsd / deltaBaseSell
456
+ const execPriceSell = quoteOutUsd.div(deltaBaseSell);
457
+ // impact = |execPrice - spotPrice| / spotPrice
458
+ const diffSell = execPriceSell.sub(spotPriceUsd).abs();
459
+ impactSell = diffSell.div(spotPriceUsd);
460
+ }
461
+ // Take max impact of both sides and convert to bps
462
+ const maxImpact = decimal_js_1.default.max(impactBuy, impactSell);
463
+ return maxImpact.mul(new decimal_js_1.default(10000)); // Convert to bps
464
+ }
465
+ static fetch(oracleParams, accountInfos, solPrice, usdPrice) {
466
+ const poolStateInfo = accountInfos[0];
467
+ const vault0Info = accountInfos[1];
468
+ const vault1Info = accountInfos[2];
469
+ const observationStateInfo = accountInfos[3];
470
+ const [decodedPoolState, _] = PoolState.decode(poolStateInfo.data, 8);
471
+ const [decodedVault0State, __] = VaultState.decode(vault0Info.data, 0);
472
+ const [decodedVault1State, ___] = VaultState.decode(vault1Info.data, 0);
473
+ const [decodedObservationState, ____] = ObservationState.decode(observationStateInfo.data, 8);
474
+ const currentTime = new bn_js_1.default(Math.floor(Date.now() / 1000));
475
+ // Determine quote oracle
476
+ const quotePrice = oracleParams.quote === oracle_1.Quote.Usdc ? usdPrice : solPrice;
477
+ // Get spot price with reserves
478
+ const { netBase, netQuote, spotPrice } = this.getSpotPriceWithReserves(decodedPoolState, decodedVault0State, decodedVault1State, oracleParams.side, quotePrice);
479
+ // Get TWAP prices
480
+ let primaryPrice = RaydiumCPMMOracle.getTwapPrimary(currentTime, decodedObservationState.observations, decodedObservationState.observationIndex, oracleParams.side, oracleParams.twapSecondsAgo, oracleParams.twapSecondarySecondsAgo, decodedPoolState.mint0Decimals, decodedPoolState.mint1Decimals);
481
+ let secondaryPrice = RaydiumCPMMOracle.getTwapSecondary(currentTime, decodedObservationState.observations, decodedObservationState.observationIndex, oracleParams.side, oracleParams.twapSecondsAgo, oracleParams.twapSecondarySecondsAgo, decodedPoolState.mint0Decimals, decodedPoolState.mint1Decimals);
482
+ // Convert TWAP prices to USD
483
+ const primaryPriceUsd = primaryPrice.mul(quotePrice.price);
484
+ const secondaryPriceUsd = secondaryPrice.mul(quotePrice.price);
485
+ // Validate primary TWAP is not zero
486
+ if (primaryPriceUsd.eq(0)) {
487
+ return new oracle_2.OraclePrice(new decimal_js_1.default(0), new decimal_js_1.default(0), 0);
488
+ }
489
+ // === Min liquidity and price impact validation ===
490
+ if (oracleParams.minLiquidity.gt(new bn_js_1.default(0))) {
491
+ const impactBps = this.calculateMaxPriceImpactForMinLiquidity(oracleParams, netBase, netQuote, spotPrice, quotePrice);
492
+ if (oracleParams.maxSlippageBps > 0) {
493
+ if (impactBps.gt(new decimal_js_1.default(oracleParams.maxSlippageBps))) {
494
+ return new oracle_2.OraclePrice(new decimal_js_1.default(0), new decimal_js_1.default(0), 0);
495
+ }
496
+ }
497
+ }
498
+ // === Confidence calculation ===
499
+ const maxPrice = decimal_js_1.default.max(primaryPriceUsd, secondaryPriceUsd, spotPrice);
500
+ const minPrice = decimal_js_1.default.min(primaryPriceUsd, secondaryPriceUsd, spotPrice);
501
+ let confidence = maxPrice.gt(minPrice) ? maxPrice.sub(minPrice) : new decimal_js_1.default(0);
502
+ // Get last update timestamp from latest observation
503
+ const lastUpdateTimestamp = decodedObservationState.observations[decodedObservationState.observationIndex].timestamp;
504
+ // === Inflate confidence by staleness ===
505
+ // confidence = confidence * (1 + delta_t * stalenessConfRateBps / 10_000)
506
+ const deltaSecondsBN = currentTime.sub(lastUpdateTimestamp);
507
+ const deltaSeconds = new decimal_js_1.default(deltaSecondsBN.toString());
508
+ if (oracleParams.stalenessConfRateBps > 0 && deltaSeconds.gt(0)) {
509
+ const stalenessRate = new decimal_js_1.default(oracleParams.stalenessConfRateBps).div(new decimal_js_1.default(10000));
510
+ const inflateFactor = new decimal_js_1.default(1).add(deltaSeconds.mul(stalenessRate));
511
+ confidence = confidence.mul(inflateFactor);
512
+ }
513
+ // === Validate confidence threshold ===
514
+ // confidence / primaryPrice * 10_000 < confThreshBps
515
+ const confRatioBps = confidence.div(primaryPriceUsd).mul(new decimal_js_1.default(10000));
516
+ if (confRatioBps.gt(new decimal_js_1.default(oracleParams.confThreshBps))) {
517
+ return new oracle_2.OraclePrice(new decimal_js_1.default(0), new decimal_js_1.default(0), 0);
518
+ }
519
+ // === Validate staleness threshold ===
520
+ if (oracleParams.stalenessThresh.gt(new bn_js_1.default(0))) {
521
+ if (currentTime.sub(lastUpdateTimestamp).gt(oracleParams.stalenessThresh)) {
522
+ return new oracle_2.OraclePrice(new decimal_js_1.default(0), new decimal_js_1.default(0), 0);
523
+ }
524
+ }
525
+ // === Validate volatility threshold ===
526
+ // (maxPrice - minPrice) / minPrice * 10_000 <= volatilityThreshBps
527
+ if (!minPrice.eq(0)) {
528
+ const volRatioBps = maxPrice.sub(minPrice).div(minPrice).mul(new decimal_js_1.default(10000));
529
+ if (volRatioBps.gt(new decimal_js_1.default(oracleParams.volatilityThreshBps))) {
530
+ return new oracle_2.OraclePrice(new decimal_js_1.default(0), new decimal_js_1.default(0), 0);
531
+ }
532
+ }
533
+ else {
534
+ // minPrice == 0 is invalid
535
+ return new oracle_2.OraclePrice(new decimal_js_1.default(0), new decimal_js_1.default(0), 0);
536
+ }
537
+ return new oracle_2.OraclePrice(primaryPriceUsd, confidence, currentTime.toNumber());
538
+ }
539
+ }
540
+ exports.RaydiumCPMMOracle = RaydiumCPMMOracle;
File without changes
@@ -0,0 +1 @@
1
+ "use strict";
@@ -0,0 +1,10 @@
1
+ import { Connection, PublicKey } from '@solana/web3.js';
2
+ import { WithdrawBasketFees } from '../layouts/basket';
3
+ export declare function addFieldsToWithdrawBasketFees(withdrawBasketFees: WithdrawBasketFees): WithdrawBasketFees;
4
+ export declare function fetchWithdrawBasketFees(connection: Connection, withdrawBasketFeesAddress: PublicKey): Promise<WithdrawBasketFees>;
5
+ export declare function fetchWithdrawBasketFeesMultiple(connection: Connection, withdrawBasketFeesAddresses: PublicKey[]): Promise<Map<string, WithdrawBasketFees>>;
6
+ export interface WithdrawBasketFeesFilter {
7
+ type: "basket" | "manager" | "creator" | "host" | "symmetry";
8
+ pubkey: string;
9
+ }
10
+ export declare function fetchWithdrawBasketFeesList(connection: Connection, filter?: WithdrawBasketFeesFilter): Promise<WithdrawBasketFees[]>;