@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.
- package/dist/src/constants.d.ts +23 -0
- package/dist/src/constants.js +38 -0
- package/dist/src/index.d.ts +804 -0
- package/dist/src/index.js +2097 -0
- package/dist/src/instructions/automation/auction.d.ts +6 -0
- package/dist/src/instructions/automation/auction.js +40 -0
- package/dist/src/instructions/automation/claimBounty.d.ts +12 -0
- package/dist/src/instructions/automation/claimBounty.js +44 -0
- package/dist/src/instructions/automation/flashSwap.d.ts +21 -0
- package/dist/src/instructions/automation/flashSwap.js +74 -0
- package/dist/src/instructions/automation/priceUpdate.d.ts +19 -0
- package/dist/src/instructions/automation/priceUpdate.js +89 -0
- package/dist/src/instructions/automation/rebalanceIntent.d.ts +32 -0
- package/dist/src/instructions/automation/rebalanceIntent.js +117 -0
- package/dist/src/instructions/automation/rebalanceSwap.d.ts +11 -0
- package/dist/src/instructions/automation/rebalanceSwap.js +42 -0
- package/dist/src/instructions/management/addBounty.d.ts +7 -0
- package/dist/src/instructions/management/addBounty.js +41 -0
- package/dist/src/instructions/management/admin.d.ts +9 -0
- package/dist/src/instructions/management/admin.js +53 -0
- package/dist/src/instructions/management/claimFees.d.ts +15 -0
- package/dist/src/instructions/management/claimFees.js +95 -0
- package/dist/src/instructions/management/createBasket.d.ts +21 -0
- package/dist/src/instructions/management/createBasket.js +98 -0
- package/dist/src/instructions/management/edit.d.ts +51 -0
- package/dist/src/instructions/management/edit.js +477 -0
- package/dist/src/instructions/management/luts.d.ts +30 -0
- package/dist/src/instructions/management/luts.js +99 -0
- package/dist/src/instructions/pda.d.ts +25 -0
- package/dist/src/instructions/pda.js +128 -0
- package/dist/src/instructions/user/deposit.d.ts +20 -0
- package/dist/src/instructions/user/deposit.js +100 -0
- package/dist/src/instructions/user/withdraw.d.ts +8 -0
- package/dist/src/instructions/user/withdraw.js +36 -0
- package/dist/src/jup.d.ts +49 -0
- package/dist/src/jup.js +80 -0
- package/dist/src/keeperMonitor.d.ts +52 -0
- package/dist/src/keeperMonitor.js +624 -0
- package/dist/src/layouts/basket.d.ts +191 -0
- package/dist/src/layouts/basket.js +51 -0
- package/dist/src/layouts/config.d.ts +281 -0
- package/dist/src/layouts/config.js +237 -0
- package/dist/src/layouts/fraction.d.ts +20 -0
- package/dist/src/layouts/fraction.js +164 -0
- package/dist/src/layouts/intents/bounty.d.ts +18 -0
- package/dist/src/layouts/intents/bounty.js +19 -0
- package/dist/src/layouts/intents/intent.d.ts +209 -0
- package/dist/src/layouts/intents/intent.js +97 -0
- package/dist/src/layouts/intents/rebalanceIntent.d.ts +212 -0
- package/dist/src/layouts/intents/rebalanceIntent.js +94 -0
- package/dist/src/layouts/lookupTable.d.ts +7 -0
- package/dist/src/layouts/lookupTable.js +10 -0
- package/dist/src/layouts/oracle.d.ts +63 -0
- package/dist/src/layouts/oracle.js +96 -0
- package/dist/src/states/basket.d.ts +14 -0
- package/dist/src/states/basket.js +479 -0
- package/dist/src/states/config.d.ts +3 -0
- package/dist/src/states/config.js +71 -0
- package/dist/src/states/intents/intent.d.ts +10 -0
- package/dist/src/states/intents/intent.js +316 -0
- package/dist/src/states/intents/rebalanceIntent.d.ts +42 -0
- package/dist/src/states/intents/rebalanceIntent.js +680 -0
- package/dist/src/states/oracles/constants.d.ts +9 -0
- package/dist/src/states/oracles/constants.js +15 -0
- package/dist/src/states/oracles/oracle.d.ts +24 -0
- package/dist/src/states/oracles/oracle.js +168 -0
- package/dist/src/states/oracles/pythOracle.d.ts +132 -0
- package/dist/src/states/oracles/pythOracle.js +609 -0
- package/dist/src/states/oracles/raydiumClmmOracle.d.ts +184 -0
- package/dist/src/states/oracles/raydiumClmmOracle.js +843 -0
- package/dist/src/states/oracles/raydiumCpmmOracle.d.ts +120 -0
- package/dist/src/states/oracles/raydiumCpmmOracle.js +540 -0
- package/dist/src/states/oracles/switchboardOracle.d.ts +0 -0
- package/dist/src/states/oracles/switchboardOracle.js +1 -0
- package/dist/src/states/withdrawBasketFees.d.ts +10 -0
- package/dist/src/states/withdrawBasketFees.js +154 -0
- package/dist/src/txUtils.d.ts +65 -0
- package/dist/src/txUtils.js +306 -0
- package/dist/test.d.ts +1 -0
- package/dist/test.js +561 -0
- package/package.json +31 -0
- package/src/constants.ts +40 -0
- package/src/index.ts +2431 -0
- package/src/instructions/automation/auction.ts +55 -0
- package/src/instructions/automation/claimBounty.ts +69 -0
- package/src/instructions/automation/flashSwap.ts +104 -0
- package/src/instructions/automation/priceUpdate.ts +117 -0
- package/src/instructions/automation/rebalanceIntent.ts +181 -0
- package/src/instructions/management/addBounty.ts +55 -0
- package/src/instructions/management/admin.ts +72 -0
- package/src/instructions/management/claimFees.ts +129 -0
- package/src/instructions/management/createBasket.ts +138 -0
- package/src/instructions/management/edit.ts +602 -0
- package/src/instructions/management/luts.ts +157 -0
- package/src/instructions/pda.ts +151 -0
- package/src/instructions/user/deposit.ts +143 -0
- package/src/instructions/user/withdraw.ts +53 -0
- package/src/jup.ts +113 -0
- package/src/keeperMonitor.ts +585 -0
- package/src/layouts/basket.ts +233 -0
- package/src/layouts/config.ts +576 -0
- package/src/layouts/fraction.ts +164 -0
- package/src/layouts/intents/bounty.ts +35 -0
- package/src/layouts/intents/intent.ts +324 -0
- package/src/layouts/intents/rebalanceIntent.ts +306 -0
- package/src/layouts/lookupTable.ts +14 -0
- package/src/layouts/oracle.ts +157 -0
- package/src/states/basket.ts +527 -0
- package/src/states/config.ts +62 -0
- package/src/states/intents/intent.ts +311 -0
- package/src/states/intents/rebalanceIntent.ts +751 -0
- package/src/states/oracles/constants.ts +13 -0
- package/src/states/oracles/oracle.ts +212 -0
- package/src/states/oracles/pythOracle.ts +874 -0
- package/src/states/oracles/raydiumClmmOracle.ts +1193 -0
- package/src/states/oracles/raydiumCpmmOracle.ts +784 -0
- package/src/states/oracles/switchboardOracle.ts +0 -0
- package/src/states/withdrawBasketFees.ts +160 -0
- package/src/txUtils.ts +424 -0
- package/test.ts +609 -0
- 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
|
+
}
|