@exponent-labs/exponent-sdk 0.1.6 → 0.1.8

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 (92) hide show
  1. package/build/EventDecoderV2.d.ts +31 -0
  2. package/build/EventDecoderV2.js +76 -0
  3. package/build/EventDecoderV2.js.map +1 -0
  4. package/build/addressLookupTableUtil.d.ts +17 -1
  5. package/build/addressLookupTableUtil.js +35 -1
  6. package/build/addressLookupTableUtil.js.map +1 -1
  7. package/build/clmm/events.d.ts +10 -0
  8. package/build/clmm/events.js +10 -0
  9. package/build/clmm/events.js.map +1 -0
  10. package/build/clmm/index.d.ts +1 -0
  11. package/build/clmm/index.js +18 -0
  12. package/build/clmm/index.js.map +1 -0
  13. package/build/events.d.ts +200 -9
  14. package/build/events.js +73 -24
  15. package/build/events.js.map +1 -1
  16. package/build/eventsV2.d.ts +7 -0
  17. package/build/eventsV2.js +10 -0
  18. package/build/eventsV2.js.map +1 -0
  19. package/build/flavors.d.ts +2 -0
  20. package/build/flavors.js +81 -27
  21. package/build/flavors.js.map +1 -1
  22. package/build/index.d.ts +6 -0
  23. package/build/index.js +14 -4
  24. package/build/index.js.map +1 -1
  25. package/build/lpPosition.js +4 -1
  26. package/build/lpPosition.js.map +1 -1
  27. package/build/market.d.ts +14 -2
  28. package/build/market.js +70 -29
  29. package/build/market.js.map +1 -1
  30. package/build/marketThree.d.ts +664 -0
  31. package/build/marketThree.js +1415 -0
  32. package/build/marketThree.js.map +1 -0
  33. package/build/marketThree.test.d.ts +1 -0
  34. package/build/marketThree.test.js +166 -0
  35. package/build/marketThree.test.js.map +1 -0
  36. package/build/orderbook/events.d.ts +7 -0
  37. package/build/orderbook/events.js +10 -0
  38. package/build/orderbook/events.js.map +1 -0
  39. package/build/orderbook/index.d.ts +4 -0
  40. package/build/orderbook/index.js +41 -0
  41. package/build/orderbook/index.js.map +1 -0
  42. package/build/orderbook/math.d.ts +26 -0
  43. package/build/orderbook/math.js +111 -0
  44. package/build/orderbook/math.js.map +1 -0
  45. package/build/orderbook/orderbook.d.ts +175 -0
  46. package/build/orderbook/orderbook.js +756 -0
  47. package/build/orderbook/orderbook.js.map +1 -0
  48. package/build/orderbook/types.d.ts +49 -0
  49. package/build/orderbook/types.js +27 -0
  50. package/build/orderbook/types.js.map +1 -0
  51. package/build/orderbook/utils.d.ts +18 -0
  52. package/build/orderbook/utils.js +74 -0
  53. package/build/orderbook/utils.js.map +1 -0
  54. package/build/router.d.ts +92 -0
  55. package/build/router.js +214 -0
  56. package/build/router.js.map +1 -0
  57. package/build/syPosition.js +6 -0
  58. package/build/syPosition.js.map +1 -1
  59. package/build/utils/index.d.ts +3 -2
  60. package/build/utils/index.js +22 -1
  61. package/build/utils/index.js.map +1 -1
  62. package/build/vault.d.ts +3 -1
  63. package/build/vault.js +98 -62
  64. package/build/vault.js.map +1 -1
  65. package/build/ytPosition.d.ts +2 -0
  66. package/build/ytPosition.js +18 -5
  67. package/build/ytPosition.js.map +1 -1
  68. package/package.json +28 -23
  69. package/src/EventDecoderV2.ts +96 -0
  70. package/src/addressLookupTableUtil.ts +42 -1
  71. package/src/clmm/events.ts +17 -0
  72. package/src/clmm/index.ts +1 -0
  73. package/src/events.ts +280 -27
  74. package/src/eventsV2.ts +13 -0
  75. package/src/flavors.ts +97 -27
  76. package/src/index.ts +6 -0
  77. package/src/lpPosition.ts +5 -2
  78. package/src/market.ts +100 -31
  79. package/src/marketThree.test.ts +208 -0
  80. package/src/marketThree.ts +2430 -0
  81. package/src/orderbook/events.ts +13 -0
  82. package/src/orderbook/index.ts +12 -0
  83. package/src/orderbook/math.ts +122 -0
  84. package/src/orderbook/orderbook.ts +1153 -0
  85. package/src/orderbook/types.ts +45 -0
  86. package/src/orderbook/utils.ts +74 -0
  87. package/src/router.ts +360 -0
  88. package/src/syPosition.ts +4 -0
  89. package/src/utils/index.ts +27 -2
  90. package/src/vault.ts +100 -62
  91. package/src/ytPosition.ts +28 -7
  92. package/tsconfig.json +4 -1
@@ -0,0 +1,45 @@
1
+ import { web3 } from "@coral-xyz/anchor"
2
+
3
+ export type OrderbookLoadOptions = {
4
+ syConfig?: {
5
+ skipWrap?: boolean
6
+ }
7
+ }
8
+
9
+ type EmptyObject = Record<never, never>
10
+ export type OfferTypeAnchor = { buyYt: EmptyObject; sellYt?: never } | { sellYt: EmptyObject; buyYt?: never }
11
+
12
+ export type OfferOptionsAnchor = { fillOrKill: { "0": boolean } }
13
+
14
+ export enum OfferType {
15
+ SellYT = 1,
16
+ BuyYT = 2,
17
+ }
18
+
19
+ export type Offer = {
20
+ type: OfferType
21
+ priceApy: number
22
+ amount: number
23
+ userEscrow: web3.PublicKey
24
+ expiryAt: number
25
+ createdAt: number
26
+ isVirtual: boolean
27
+ }
28
+
29
+ export enum OfferTradeDirection {
30
+ SY_TO_YT,
31
+ SY_TO_PT,
32
+ YT_TO_SY,
33
+ PT_TO_SY,
34
+ }
35
+
36
+ export enum QuoteDirection {
37
+ BASE_TO_YT,
38
+ BASE_TO_PT,
39
+ YT_TO_BASE,
40
+ PT_TO_BASE,
41
+ SY_TO_YT,
42
+ SY_TO_PT,
43
+ YT_TO_SY,
44
+ PT_TO_SY,
45
+ }
@@ -0,0 +1,74 @@
1
+ import { OfferType, OfferTradeDirection, OfferTypeAnchor, QuoteDirection } from "./types"
2
+
3
+ /**
4
+ * Get offer type by offer.orderTypeFlag value
5
+ */
6
+ export function getOfferType(orderTypeFlag: number): OfferType {
7
+ return orderTypeFlag === 1 ? OfferType.SellYT : OfferType.BuyYT
8
+ }
9
+
10
+ /**
11
+ * Get price in percents and cast it to implied rate
12
+ */
13
+ export function priceToImpliedRate(price: number): number {
14
+ return Math.log(1 + price / 100)
15
+ }
16
+
17
+ export function getOfferTypeFromTradeDirection(tradeDirection: OfferTradeDirection): {
18
+ offerType: OfferType
19
+ isVirtual: boolean
20
+ } {
21
+ const isVirtual = tradeDirection === OfferTradeDirection.PT_TO_SY || tradeDirection === OfferTradeDirection.SY_TO_PT
22
+
23
+ const offerType: OfferType = (() => {
24
+ if (tradeDirection === OfferTradeDirection.SY_TO_YT || tradeDirection === OfferTradeDirection.PT_TO_SY) {
25
+ return OfferType.BuyYT
26
+ } else {
27
+ return OfferType.SellYT
28
+ }
29
+ })()
30
+
31
+ return {
32
+ isVirtual,
33
+ offerType,
34
+ }
35
+ }
36
+
37
+ export function convertOfferTypeToAnchorType(offerType: OfferType): OfferTypeAnchor {
38
+ return offerType === OfferType.BuyYT ? { buyYt: {} } : { sellYt: {} }
39
+ }
40
+
41
+ export function convertOfferTypeFromAnchorType(offerTypeAnchor: OfferTypeAnchor): OfferType {
42
+ return offerTypeAnchor?.buyYt ? OfferType.BuyYT : OfferType.SellYT
43
+ }
44
+
45
+ export function getOfferDirectionFromQuoteDirection(direction: QuoteDirection): OfferTradeDirection {
46
+ switch (direction) {
47
+ case QuoteDirection.BASE_TO_YT:
48
+ return OfferTradeDirection.SY_TO_YT
49
+ case QuoteDirection.BASE_TO_PT:
50
+ return OfferTradeDirection.SY_TO_PT
51
+ case QuoteDirection.YT_TO_BASE:
52
+ return OfferTradeDirection.YT_TO_SY
53
+ case QuoteDirection.PT_TO_BASE:
54
+ return OfferTradeDirection.PT_TO_SY
55
+ case QuoteDirection.SY_TO_YT:
56
+ return OfferTradeDirection.SY_TO_YT
57
+ case QuoteDirection.SY_TO_PT:
58
+ return OfferTradeDirection.SY_TO_PT
59
+ case QuoteDirection.YT_TO_SY:
60
+ return OfferTradeDirection.YT_TO_SY
61
+ case QuoteDirection.PT_TO_SY:
62
+ return OfferTradeDirection.PT_TO_SY
63
+ default:
64
+ throw new Error(`Unable to determine offer direction from quote direction: ${direction}`)
65
+ }
66
+ }
67
+
68
+ export function isQuoteInputTokenBase(direction: QuoteDirection): boolean {
69
+ return direction === QuoteDirection.BASE_TO_YT || direction === QuoteDirection.BASE_TO_PT
70
+ }
71
+
72
+ export function isQuoteOutputTokenBase(direction: QuoteDirection): boolean {
73
+ return direction === QuoteDirection.YT_TO_BASE || direction === QuoteDirection.PT_TO_BASE
74
+ }
package/src/router.ts ADDED
@@ -0,0 +1,360 @@
1
+ import { web3 } from "@coral-xyz/anchor"
2
+
3
+ import { ExponentFetcher, MarketThree, Ticks } from "@exponent-labs/exponent-fetcher"
4
+ import {
5
+ QuoteDirection as ClmmQuoteDirection,
6
+ MarketThreeState,
7
+ getSwapQuote as getClmmSwapQuote,
8
+ } from "@exponent-labs/market-three-math"
9
+
10
+ import { Environment } from "./environment"
11
+ import { Market, MarketLoadOptions } from "./market"
12
+ import { Orderbook, OrderbookLoadOptions, QuoteDirection as OrderbookQuoteDirection } from "./orderbook"
13
+ import { Vault } from "./vault"
14
+
15
+ export class Router {
16
+ private legacyMarkets: Market[]
17
+ private orderbooks: Orderbook[]
18
+ private clmmsWithTicks: ClmmWithTicks[]
19
+ //? For possible future use inside refetch functionality
20
+ private vault: Vault | null
21
+ private connection: web3.Connection
22
+
23
+ /**
24
+ * Use the constructor if markets are already initialized in your app
25
+ */
26
+ constructor(
27
+ connection: web3.Connection,
28
+ markets: { legacyMarkets?: Market[]; orderbooks?: Orderbook[]; clmmsWithTicks?: ClmmWithTicks[] },
29
+ vault?: Vault,
30
+ ) {
31
+ this.connection = connection
32
+
33
+ this.legacyMarkets = markets.legacyMarkets ?? []
34
+ this.orderbooks = markets.orderbooks ?? []
35
+ this.clmmsWithTicks = markets.clmmsWithTicks ?? []
36
+
37
+ this.vault = vault ?? null
38
+ }
39
+
40
+ /**
41
+ * Use the load method if you don't have already loaded markets in your app
42
+ */
43
+ public static async load(
44
+ connection: web3.Connection,
45
+ args: {
46
+ vault?: Vault
47
+ env: Environment
48
+ legacyMarketsParams?: {
49
+ address: web3.PublicKey
50
+ options?: MarketLoadOptions
51
+ }[]
52
+ orderbookParams?: {
53
+ address: web3.PublicKey
54
+ options?: OrderbookLoadOptions
55
+ }[]
56
+ clmmParams?: {
57
+ marketThreeAddress: web3.PublicKey
58
+ }[]
59
+ },
60
+ ): Promise<Router> {
61
+ const { vault, legacyMarketsParams = [], orderbookParams = [], clmmParams = [], env } = args
62
+
63
+ const legacyMarketsPromises = this.fetchLegacyMarkets(connection, { env, vault, legacyMarketsParams })
64
+
65
+ const orderbooksPromises = this.fetchOrderbooks(connection, { env, vault, orderbookParams })
66
+
67
+ const clmmsWithTicksPromises = this.fetchClmmsWithTicks(
68
+ connection,
69
+ clmmParams.map(({ marketThreeAddress }) => marketThreeAddress),
70
+ )
71
+
72
+ const [legacyMarkets, orderbooks, clmmsWithTicks] = await Promise.all([
73
+ legacyMarketsPromises,
74
+ orderbooksPromises,
75
+ clmmsWithTicksPromises,
76
+ ])
77
+
78
+ return new Router(
79
+ connection,
80
+ { legacyMarkets: legacyMarkets, orderbooks: orderbooks, clmmsWithTicks: clmmsWithTicks },
81
+ args.vault,
82
+ )
83
+ }
84
+
85
+ /**
86
+ * Refreshes the states of all markets, orderbooks and CLMMs
87
+ */
88
+ public async refresh(): Promise<Router> {
89
+ const legacyMarkets = await Promise.all(this.legacyMarkets.map((market) => market.reload(this.connection)))
90
+
91
+ const orderbooks = await Promise.all(this.orderbooks.map((orderbook) => orderbook.reload(this.connection)))
92
+
93
+ const clmmsWithTicks = await Router.fetchClmmsWithTicks(
94
+ this.connection,
95
+ this.clmmsWithTicks.map((clmmWithTicks) => clmmWithTicks.marketThree.selfAddress),
96
+ )
97
+
98
+ return new Router(
99
+ this.connection,
100
+ { legacyMarkets: legacyMarkets, orderbooks: orderbooks, clmmsWithTicks: clmmsWithTicks },
101
+ this.vault,
102
+ )
103
+ }
104
+
105
+ public getQuote(params: { direction: RouterQuoteDirection; inAmount: number; syExchangeRate: number }): Quote | null {
106
+ //? Better to refetch market and orderbook states before every call or trigger reload method here
107
+ const { direction, inAmount, syExchangeRate } = params
108
+
109
+ const marketQuotes = this.legacyMarkets.map((market) => this.getLegacyMarketQuote({ market, direction, inAmount }))
110
+ const orderbookQuotes = this.orderbooks.map((orderbook) =>
111
+ this.getOrderbookQuote({ orderbook, direction, inAmount, syExchangeRate }),
112
+ )
113
+ const clmmQuotes = this.clmmsWithTicks.map((clmmWithTicks) =>
114
+ this.getClmmQuote({ clmmWithTicks, syExchangeRate, direction, inAmount }),
115
+ )
116
+
117
+ const bestQuote: Quote | null =
118
+ [...marketQuotes, ...orderbookQuotes, ...clmmQuotes]
119
+ .filter(({ outAmount }) => outAmount > 0)
120
+ .sort((a, b) => b.outAmount - a.outAmount)
121
+ .at(0) ?? null
122
+
123
+ return bestQuote
124
+ }
125
+
126
+ static async fetchLegacyMarkets(
127
+ connection: web3.Connection,
128
+ args: {
129
+ env: Environment
130
+ vault?: Vault
131
+ legacyMarketsParams: {
132
+ address: web3.PublicKey
133
+ options?: MarketLoadOptions
134
+ }[]
135
+ },
136
+ ): Promise<Market[]> {
137
+ return await Promise.all(
138
+ args.legacyMarketsParams.map((market) =>
139
+ Market.load(args.env, connection, market.address, args.vault, market.options),
140
+ ),
141
+ )
142
+ }
143
+
144
+ static async fetchOrderbooks(
145
+ connection: web3.Connection,
146
+ args: {
147
+ env: Environment
148
+ vault?: Vault
149
+ orderbookParams: {
150
+ address: web3.PublicKey
151
+ options?: OrderbookLoadOptions
152
+ }[]
153
+ },
154
+ ): Promise<Orderbook[]> {
155
+ return await Promise.all(
156
+ args.orderbookParams.map((orderbook) =>
157
+ Orderbook.load(args.env, connection, orderbook.address, orderbook.options, args.vault),
158
+ ),
159
+ )
160
+ }
161
+
162
+ static async fetchClmmsWithTicks(
163
+ connection: web3.Connection,
164
+ clmmAddresses: web3.PublicKey[],
165
+ ): Promise<{ marketThree: MarketThree; ticks: Ticks }[]> {
166
+ const fetchClmmWithTicks = async (marketThreeAddress: web3.PublicKey) => {
167
+ const xponFetcher = new ExponentFetcher({ connection })
168
+ const marketThree = await xponFetcher.fetchMarketThree(marketThreeAddress)
169
+ const ticks = await xponFetcher.fetchMarketThreeTicks(marketThree.ticks)
170
+
171
+ return { marketThree, ticks }
172
+ }
173
+
174
+ return await Promise.all(clmmAddresses.map((address) => fetchClmmWithTicks(address)))
175
+ }
176
+
177
+ private getLegacyMarketQuote(params: { market: Market; direction: RouterQuoteDirection; inAmount: number }): Quote {
178
+ const { direction, inAmount, market } = params
179
+
180
+ const marketCalculator = market.marketCalculator()
181
+
182
+ if (direction === RouterQuoteDirection.BASE_TO_YT) {
183
+ const { ytOut, feeInAsset } = marketCalculator.estimateYtOutForExactAssetIn(inAmount)
184
+ return {
185
+ outAmount: ytOut,
186
+ feesInOutToken: feeInAsset,
187
+ source: RouterTradeSource.MARKET,
188
+ sourceAddress: market.selfAddress,
189
+ }
190
+ }
191
+
192
+ if (direction === RouterQuoteDirection.BASE_TO_PT) {
193
+ const ptOut = marketCalculator.estimateNetPtForExactNetAsset(inAmount)
194
+ const { feeAsset, netTraderPt } = marketCalculator.calcTradePt(ptOut, false)
195
+ return {
196
+ outAmount: netTraderPt,
197
+ feesInOutToken: feeAsset,
198
+ source: RouterTradeSource.MARKET,
199
+ sourceAddress: market.selfAddress,
200
+ }
201
+ }
202
+
203
+ if (direction === RouterQuoteDirection.PT_TO_BASE) {
204
+ const { feeAsset, netTraderAsset } = marketCalculator.calcTradePt(inAmount * -1)
205
+ return {
206
+ outAmount: netTraderAsset,
207
+ feesInOutToken: feeAsset,
208
+ source: RouterTradeSource.MARKET,
209
+ sourceAddress: market.selfAddress,
210
+ }
211
+ }
212
+
213
+ if (direction === RouterQuoteDirection.YT_TO_BASE) {
214
+ const { feeInAsset, assetOut } = marketCalculator.simSellYt(inAmount)
215
+ return {
216
+ outAmount: assetOut,
217
+ feesInOutToken: feeInAsset,
218
+ source: RouterTradeSource.MARKET,
219
+ sourceAddress: market.selfAddress,
220
+ }
221
+ }
222
+
223
+ throw new Error(`Unknown quote direction: ${direction}`)
224
+ }
225
+
226
+ private getOrderbookQuote(params: {
227
+ orderbook: Orderbook
228
+ direction: RouterQuoteDirection
229
+ inAmount: number
230
+ syExchangeRate: number
231
+ }): Quote {
232
+ const { direction, inAmount, orderbook, syExchangeRate } = params
233
+
234
+ const unixNow = Math.round(Date.now() / 1000)
235
+ const { outAmount, takerFees } = orderbook.getQuote({
236
+ inAmount,
237
+ unixNow,
238
+ direction: castToOrderbookQuoteDirection(direction),
239
+ syExchangeRate,
240
+ })
241
+
242
+ return {
243
+ outAmount: outAmount,
244
+ feesInOutToken: takerFees,
245
+ source: RouterTradeSource.ORDERBOOK,
246
+ sourceAddress: orderbook.selfAddress,
247
+ }
248
+ }
249
+
250
+ private getClmmQuote(params: {
251
+ clmmWithTicks: ClmmWithTicks
252
+ syExchangeRate: number
253
+ direction: RouterQuoteDirection
254
+ inAmount: number
255
+ }): Quote {
256
+ const { clmmWithTicks, syExchangeRate, inAmount, direction } = params
257
+ const sourceAddress = clmmWithTicks.marketThree.selfAddress
258
+
259
+ const marketThreeState: MarketThreeState = {
260
+ financials: clmmWithTicks.marketThree.financials,
261
+ configurationOptions: clmmWithTicks.marketThree.configurationOptions,
262
+ ticks: clmmWithTicks.ticks,
263
+ currentSyExchangeRate: syExchangeRate,
264
+ }
265
+
266
+ if (direction === RouterQuoteDirection.BASE_TO_PT) {
267
+ const syInAmount = inAmount / syExchangeRate
268
+
269
+ const { amountOut, lpFee, protocolFee } = getClmmSwapQuote(
270
+ marketThreeState,
271
+ syInAmount,
272
+ ClmmQuoteDirection.SyToPt,
273
+ )
274
+ return {
275
+ outAmount: amountOut,
276
+ feesInOutToken: lpFee + protocolFee,
277
+ source: RouterTradeSource.CLMM,
278
+ sourceAddress,
279
+ }
280
+ }
281
+
282
+ if (direction === RouterQuoteDirection.PT_TO_BASE) {
283
+ const { amountOut, lpFee, protocolFee } = getClmmSwapQuote(marketThreeState, inAmount, ClmmQuoteDirection.PtToSy)
284
+
285
+ const baseOutAmount = amountOut * syExchangeRate
286
+
287
+ return {
288
+ outAmount: baseOutAmount,
289
+ feesInOutToken: lpFee + protocolFee,
290
+ source: RouterTradeSource.CLMM,
291
+ sourceAddress,
292
+ }
293
+ }
294
+
295
+ if (direction === RouterQuoteDirection.BASE_TO_YT) {
296
+ const syInAmount = inAmount / syExchangeRate
297
+ const { amountOut, lpFee, protocolFee } = getClmmSwapQuote(
298
+ marketThreeState,
299
+ syInAmount,
300
+ ClmmQuoteDirection.SyToYt,
301
+ )
302
+
303
+ return {
304
+ outAmount: amountOut,
305
+ feesInOutToken: lpFee + protocolFee,
306
+ source: RouterTradeSource.CLMM,
307
+ sourceAddress,
308
+ }
309
+ }
310
+
311
+ if (direction === RouterQuoteDirection.YT_TO_BASE) {
312
+ const { amountOut, lpFee, protocolFee } = getClmmSwapQuote(marketThreeState, inAmount, ClmmQuoteDirection.YtToSy)
313
+ const baseOutAmount = amountOut * syExchangeRate
314
+ return {
315
+ outAmount: baseOutAmount,
316
+ feesInOutToken: lpFee + protocolFee,
317
+ source: RouterTradeSource.CLMM,
318
+ sourceAddress,
319
+ }
320
+ }
321
+
322
+ throw new Error(`Unknown quote direction: ${direction}`)
323
+ }
324
+ }
325
+
326
+ export type ClmmWithTicks = {
327
+ marketThree: MarketThree
328
+ ticks: Ticks
329
+ }
330
+
331
+ export type Quote = {
332
+ outAmount: number
333
+ feesInOutToken: number
334
+ source: RouterTradeSource
335
+ sourceAddress: web3.PublicKey
336
+ }
337
+
338
+ /**
339
+ * As orderbook supports more trade directions than market, we need to cast it for type safety
340
+ */
341
+ function castToOrderbookQuoteDirection(direction: RouterQuoteDirection): OrderbookQuoteDirection {
342
+ if (direction === RouterQuoteDirection.BASE_TO_YT) return OrderbookQuoteDirection.BASE_TO_YT
343
+ if (direction === RouterQuoteDirection.BASE_TO_PT) return OrderbookQuoteDirection.BASE_TO_PT
344
+ if (direction === RouterQuoteDirection.YT_TO_BASE) return OrderbookQuoteDirection.YT_TO_BASE
345
+ if (direction === RouterQuoteDirection.PT_TO_BASE) return OrderbookQuoteDirection.PT_TO_BASE
346
+ throw new Error("Unknown quote direction")
347
+ }
348
+
349
+ export enum RouterTradeSource {
350
+ MARKET = "MARKET",
351
+ ORDERBOOK = "ORDERBOOK",
352
+ CLMM = "CLMM",
353
+ }
354
+
355
+ export enum RouterQuoteDirection {
356
+ BASE_TO_YT,
357
+ BASE_TO_PT,
358
+ YT_TO_BASE,
359
+ PT_TO_BASE,
360
+ }
package/src/syPosition.ts CHANGED
@@ -168,6 +168,10 @@ async function makeSyPositionGeneric(
168
168
  interfaceIndex = 11 // InterfaceType.KaminoVault
169
169
  } else if ("solstice" in interfaceType) {
170
170
  interfaceIndex = 12 // InterfaceType.Solstice
171
+ } else if ("reflect" in interfaceType) {
172
+ interfaceIndex = 13 // InterfaceType.Reflect
173
+ } else if ("ore" in interfaceType) {
174
+ interfaceIndex = 14 // InterfaceType.Ore
171
175
  } else {
172
176
  throw new Error("Unsupported interface type")
173
177
  }
@@ -1,8 +1,8 @@
1
- import { web3 } from "@coral-xyz/anchor"
1
+ import { Program as AnchorProgram, AnchorProvider, Idl, web3 } from "@coral-xyz/anchor"
2
2
 
3
3
  import { EXPONENT_ADMIN_PROGRAM_ID, ExponentAdminPda } from "@exponent-labs/exponent-admin-pda"
4
4
 
5
- export { InstructionAccounts } from "./ix"
5
+ export type { InstructionAccounts } from "./ix"
6
6
 
7
7
  export function uniqueRemainingAccounts(xs: web3.AccountMeta[]): web3.AccountMeta[] {
8
8
  const seen: Record<string, web3.AccountMeta> = {}
@@ -32,3 +32,28 @@ export function getExponentAdminStatePda() {
32
32
  const exponentAdminPda = new ExponentAdminPda(EXPONENT_ADMIN_PROGRAM_ID)
33
33
  return exponentAdminPda.exponentAdmin()
34
34
  }
35
+
36
+ // Browser-compatible mock wallet for creating anchor programs
37
+ class MockWallet {
38
+ constructor(readonly payer: web3.Keypair) {}
39
+
40
+ async signTransaction<T extends web3.Transaction | web3.VersionedTransaction>(tx: T): Promise<T> {
41
+ return tx
42
+ }
43
+
44
+ async signAllTransactions<T extends web3.Transaction | web3.VersionedTransaction>(txs: T[]): Promise<T[]> {
45
+ return txs
46
+ }
47
+
48
+ get publicKey(): web3.PublicKey {
49
+ return this.payer.publicKey
50
+ }
51
+ }
52
+
53
+ export function createAnchorProgram<IDL extends Idl = Idl>(idl: IDL) {
54
+ const mockProvider = new AnchorProvider(
55
+ new web3.Connection(web3.clusterApiUrl("devnet")),
56
+ new MockWallet(web3.Keypair.generate()) as any,
57
+ )
58
+ return new AnchorProgram<IDL>(idl, mockProvider)
59
+ }