@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,13 @@
1
+ import BN from "bn.js";
2
+
3
+
4
+ export const U8_MAX = new BN(0xff);
5
+ export const U16_MAX = new BN(0xffff);
6
+ export const U32_MAX = new BN(0xffffffff);
7
+ export const U64_MAX = new BN(1).shln(64).sub(new BN(1));
8
+ export const U128_MAX = new BN(1).shln(128).sub(new BN(1));
9
+
10
+
11
+ export const HERMES_PUBLIC_ENDPOINT = "https://hermes.pyth.network";
12
+ export const SOLANA_DEVNET_ENDPOINT = "https://api.devnet.solana.com";
13
+ export const SOLANA_MAINNET_ENDPOINT = "https://api.mainnet-beta.solana.com";
@@ -0,0 +1,212 @@
1
+ import Decimal from 'decimal.js';
2
+
3
+ import BN from 'bn.js';
4
+ import { AccountInfo, AddressLookupTableAccount, PublicKey } from '@solana/web3.js';
5
+
6
+ import { HUNDRED_PERCENT_BPS } from '../../constants';
7
+ import { Fraction, fractionToDecimal } from '../../layouts/fraction';
8
+ import {
9
+ MAX_ACCOUNTS_PER_ORACLE, OracleAggregator, OracleData, OracleSettings, OracleType
10
+ } from '../../layouts/oracle';
11
+ import { U32_MAX } from './constants';
12
+ import { PythOracle } from './pythOracle';
13
+ import {
14
+ getNextTickArrayStartIndex, getPdaTickArrayAddress, getTickArrayStartIndexByTick, PoolState,
15
+ RaydiumCLMMOracle
16
+ } from './raydiumClmmOracle';
17
+ import { RaydiumCPMMOracle } from './raydiumCpmmOracle';
18
+
19
+ export class OraclePrice {
20
+ price: Decimal;
21
+ conf: Decimal;
22
+ updateTime: number;
23
+ validated?: boolean;
24
+
25
+ constructor(price: Decimal, conf: Decimal, updateTime: number, validated?: boolean){
26
+ this.price = price;
27
+ this.conf = conf;
28
+ this.updateTime = updateTime;
29
+ let zero_Decimal = new Decimal(0);
30
+ if(this.price.lt(zero_Decimal)) throw new Error("price should be more than 0");
31
+ if(this.conf.lt(zero_Decimal)) throw new Error("confidence can't be negative");
32
+ if(this.updateTime < 0) throw new Error("update time should be more than 0");
33
+ this.validated = validated;
34
+ }
35
+
36
+ getMid(): Decimal {
37
+ return this.price;
38
+ }
39
+ getLow(): Decimal {
40
+ return this.price.sub(this.conf);
41
+ }
42
+ getHigh(): Decimal {
43
+ return this.price.add(this.conf);
44
+ }
45
+ }
46
+
47
+
48
+ export class PriceAggregator{
49
+ numOracles: number;
50
+ oracles: OracleData[];
51
+ minConfBps: number; // u16
52
+ // maximum confidence ratio allowed (conf / price)
53
+ confThreshBps: number; // u16
54
+ // minimum number of oracle results required for valid price
55
+ minOraclesThresh: number; // u8
56
+ // factor to expand confidence bands (≥ 1.0)
57
+ confMultiplier: Fraction;
58
+
59
+ constructor(numOracles: number, oracles: OracleData[], minConfBps: number,
60
+ confThreshBps: number, minOraclesThresh: number, confMultiplier: Fraction){
61
+ this.numOracles = numOracles;
62
+ this.oracles = oracles;
63
+ this.minConfBps = minConfBps;
64
+ this.confThreshBps = confThreshBps;
65
+ this.minOraclesThresh = minOraclesThresh;
66
+ this.confMultiplier = confMultiplier;
67
+
68
+ if(!(this.oracles.length > 0))
69
+ throw new Error(`At least one oracle is required`);
70
+ if(!(0 <= this.minConfBps && this.minConfBps < 10_000))
71
+ throw new Error(`Minimum confidence must be between 0 and 10000`);
72
+ if(!(0 <= this.confThreshBps && this.confThreshBps < 10_000))
73
+ throw new Error(`Confidence threshold must be between 0 and 10000`);
74
+ if(!(0 <= this.minOraclesThresh && this.minOraclesThresh <= U32_MAX.toNumber()))
75
+ throw new Error(`Minimum number of oracles must be between 0 and ${U32_MAX}`);
76
+ }
77
+
78
+ static fetch(
79
+ oracleAggregator: OracleAggregator,
80
+ lutAccounts: AddressLookupTableAccount[],
81
+ accountInfoMap: Map<string, AccountInfo<Buffer> | null>,
82
+ solPrice: OraclePrice,
83
+ usdPrice: OraclePrice,
84
+ ): OraclePrice {
85
+ let validated: boolean = true;
86
+ const agg = oracleAggregator;
87
+
88
+ const oracleResults: OraclePrice[] = [];
89
+
90
+ for(let i = 0; i < agg.numOracles; i++) {
91
+ const oracleData = agg.oracles[i];
92
+ const settings = oracleData.oracleSettings;
93
+
94
+ let loadedAccounts: AccountInfo<Buffer>[] = [];
95
+ for (let j = 0; j < settings.numRequiredAccounts; j++) {
96
+ const lutId = oracleData.accountsToLoadLutIds[j];
97
+ const lutIdx = oracleData.accountsToLoadLutIndices[j];
98
+ const pubkey = lutAccounts[lutId].state.addresses[lutIdx];
99
+ const account = accountInfoMap.get(pubkey.toBase58());
100
+ // @ts-ignore
101
+ loadedAccounts.push(account);
102
+ }
103
+
104
+ if (settings.oracleType === OracleType.RaydiumClmm) {
105
+ // ensure tick arrays are appended in order: prev, current, next
106
+ const poolPubkey = lutAccounts[oracleData.accountsToLoadLutIds[0]].state.addresses[oracleData.accountsToLoadLutIndices[0]];
107
+ const poolAi = accountInfoMap.get(poolPubkey.toBase58());
108
+ if (poolAi) {
109
+ const [poolState] = PoolState.decode(poolAi.data, 8);
110
+ const currStart = getTickArrayStartIndexByTick(poolState.tickCurrent, poolState.tickSpacing);
111
+ const prevStart = getNextTickArrayStartIndex(currStart, poolState.tickSpacing, true);
112
+ const nextStart = getNextTickArrayStartIndex(currStart, poolState.tickSpacing, false);
113
+ const poolId = poolPubkey;
114
+ [prevStart, currStart, nextStart].forEach(start => {
115
+ const pk = getPdaTickArrayAddress(poolId, start);
116
+ const ai = accountInfoMap.get(pk.toBase58());
117
+ if (ai) loadedAccounts.push(ai);
118
+ });
119
+ }
120
+ }
121
+
122
+ let result = (() => {
123
+ switch (settings.oracleType) {
124
+ case OracleType.Pyth:
125
+ return PythOracle.fetch(settings, loadedAccounts, solPrice, usdPrice);
126
+ case OracleType.RaydiumClmm:
127
+ return RaydiumCLMMOracle.fetch(settings, loadedAccounts, solPrice, usdPrice);
128
+ case OracleType.RaydiumCpmm:
129
+ return RaydiumCPMMOracle.fetch(settings, loadedAccounts, solPrice, usdPrice);
130
+ default:
131
+ return new OraclePrice(new Decimal(0), new Decimal(0), 0);
132
+ }
133
+ })();
134
+
135
+ // if oracle is required and price is 0, return 0 price, else skip oraclce
136
+ if (result.getMid().eq(new Decimal(0))) {
137
+ if(settings.isRequired)
138
+ validated = false;
139
+ continue;
140
+ }
141
+ if (!result.validated) {
142
+ if(settings.isRequired)
143
+ validated = false;
144
+ }
145
+
146
+ oracleResults.push(result);
147
+ }
148
+
149
+ // check this
150
+ if(oracleResults.length < agg.minOraclesThresh)
151
+ validated = false;
152
+
153
+ let prices: { price: Decimal, weight: Decimal }[] = [];
154
+
155
+ for (let i = 0; i < oracleResults.length; i++) {
156
+ const pr = oracleResults[i];
157
+ const weight = new Decimal(agg.oracles[i].oracleSettings.weight);
158
+ prices.push({ price: pr.getMid(), weight: weight });
159
+ prices.push({ price: pr.getLow(), weight: weight });
160
+ prices.push({ price: pr.getHigh(), weight: weight });
161
+ }
162
+
163
+ const medianPrice = weightedPercentile(prices, 50);
164
+ const p25Price = weightedPercentile(prices, 25);
165
+ const p75Price = weightedPercentile(prices, 75);
166
+
167
+ let first: Decimal = medianPrice.sub(p25Price);
168
+ let second: Decimal = p75Price.sub(medianPrice);
169
+ let conf = first.gte(second) ? first : second;
170
+ // confidence should be strictly less than median price
171
+ conf = conf.lt(medianPrice) ? conf : medianPrice;
172
+ conf = conf.mul(fractionToDecimal(agg.confMultiplier));
173
+
174
+ if (conf.div(medianPrice).mul(new Decimal(HUNDRED_PERCENT_BPS)).lt(new Decimal(agg.minConfBps)))
175
+ conf = medianPrice.mul(new Decimal(agg.minConfBps)).div(new Decimal(HUNDRED_PERCENT_BPS));
176
+ if (conf.div(medianPrice).mul(new Decimal(HUNDRED_PERCENT_BPS)).gt(new Decimal(agg.confThreshBps)))
177
+ return new OraclePrice(new Decimal(0), new Decimal(0), 0);
178
+
179
+ const oldest = Math.min(...oracleResults.map(p => p.updateTime));
180
+ return new OraclePrice(medianPrice, conf, oldest, validated);
181
+ }
182
+ }
183
+
184
+ function weightedPercentile(prices: { price: Decimal, weight: Decimal }[], percentile: number): Decimal {
185
+ if (percentile < 0 || percentile > 100) {
186
+ throw new Error("Percentile must be between 0 and 100");
187
+ }
188
+
189
+ // Sort by price ascending
190
+ prices.sort((a, b) => a.price.sub(b.price).toNumber());
191
+
192
+ // Edge cases
193
+ if (percentile === 0) return prices[0].price;
194
+ if (percentile === 100) return prices[prices.length - 1].price;
195
+
196
+ // Compute total weight
197
+ const totalWeight = prices.reduce((sum, x) => sum.add(x.weight), new Decimal(0));
198
+
199
+ // Threshold = percentile% of total weight
200
+ const thresh = totalWeight.mul(new Decimal(percentile)).div(new Decimal(100));
201
+
202
+ // Cumulative sum
203
+ let cum = new Decimal(0);
204
+ for (const { price, weight } of prices) {
205
+ cum = cum.add(weight);
206
+ if (cum.gte(thresh))
207
+ return price; // nearest-rank percentile
208
+ }
209
+
210
+ // fallback (should not happen, but safe)
211
+ return prices[prices.length - 1].price;
212
+ }