@kamino-finance/kliquidity-sdk 8.3.1 → 8.4.0
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/Kamino.d.ts +16 -14
- package/dist/Kamino.d.ts.map +1 -1
- package/dist/Kamino.js +114 -125
- package/dist/Kamino.js.map +1 -1
- package/dist/constants/numericalValues.d.ts +3 -0
- package/dist/constants/numericalValues.d.ts.map +1 -1
- package/dist/constants/numericalValues.js +4 -1
- package/dist/constants/numericalValues.js.map +1 -1
- package/dist/rebalance_methods/autodriftRebalance.d.ts.map +1 -1
- package/dist/rebalance_methods/autodriftRebalance.js +10 -10
- package/dist/rebalance_methods/autodriftRebalance.js.map +1 -1
- package/dist/rebalance_methods/driftRebalance.d.ts.map +1 -1
- package/dist/rebalance_methods/driftRebalance.js +10 -10
- package/dist/rebalance_methods/driftRebalance.js.map +1 -1
- package/dist/rebalance_methods/expanderRebalance.d.ts.map +1 -1
- package/dist/rebalance_methods/expanderRebalance.js +3 -4
- package/dist/rebalance_methods/expanderRebalance.js.map +1 -1
- package/dist/rebalance_methods/pricePercentageRebalance.d.ts.map +1 -1
- package/dist/rebalance_methods/pricePercentageRebalance.js +5 -6
- package/dist/rebalance_methods/pricePercentageRebalance.js.map +1 -1
- package/dist/rebalance_methods/pricePercentageWithResetRebalance.d.ts.map +1 -1
- package/dist/rebalance_methods/pricePercentageWithResetRebalance.js +5 -6
- package/dist/rebalance_methods/pricePercentageWithResetRebalance.js.map +1 -1
- package/dist/rebalance_methods/takeProfitRebalance.d.ts.map +1 -1
- package/dist/rebalance_methods/takeProfitRebalance.js +5 -5
- package/dist/rebalance_methods/takeProfitRebalance.js.map +1 -1
- package/dist/services/JupService.d.ts.map +1 -1
- package/dist/services/MeteoraService.d.ts.map +1 -1
- package/dist/services/MeteoraService.js +4 -1
- package/dist/services/MeteoraService.js.map +1 -1
- package/dist/services/OrcaService.d.ts +7 -11
- package/dist/services/OrcaService.d.ts.map +1 -1
- package/dist/services/OrcaService.js +133 -101
- package/dist/services/OrcaService.js.map +1 -1
- package/dist/services/OrcaWhirlpoolsResponse.d.ts +63 -92
- package/dist/services/OrcaWhirlpoolsResponse.d.ts.map +1 -1
- package/dist/services/RaydiumService.d.ts.map +1 -1
- package/dist/services/RaydiumService.js +7 -1
- package/dist/services/RaydiumService.js.map +1 -1
- package/dist/utils/farms.d.ts +1 -0
- package/dist/utils/farms.d.ts.map +1 -0
- package/dist/utils/farms.js +2 -0
- package/dist/utils/farms.js.map +1 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +1 -0
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/lookupTable.d.ts.map +1 -1
- package/dist/utils/lookupTable.js +1 -1
- package/dist/utils/lookupTable.js.map +1 -1
- package/dist/utils/orca.d.ts +37 -1
- package/dist/utils/orca.d.ts.map +1 -1
- package/dist/utils/orca.js +242 -0
- package/dist/utils/orca.js.map +1 -1
- package/dist/utils/tokenUtils.d.ts +5 -5
- package/dist/utils/tokenUtils.d.ts.map +1 -1
- package/dist/utils/tokenUtils.js +11 -7
- package/dist/utils/tokenUtils.js.map +1 -1
- package/dist/utils/transactions.d.ts.map +1 -1
- package/dist/utils/types.d.ts +5 -0
- package/dist/utils/types.d.ts.map +1 -1
- package/dist/utils/types.js.map +1 -1
- package/dist/utils/utils.d.ts +0 -1
- package/dist/utils/utils.d.ts.map +1 -1
- package/dist/utils/utils.js +3 -4
- package/dist/utils/utils.js.map +1 -1
- package/dist/utils/whirlpools.d.ts +12 -1
- package/dist/utils/whirlpools.d.ts.map +1 -1
- package/dist/utils/whirlpools.js +30 -29
- package/dist/utils/whirlpools.js.map +1 -1
- package/package.json +10 -9
- package/src/Kamino.ts +271 -215
- package/src/constants/numericalValues.ts +5 -0
- package/src/rebalance_methods/autodriftRebalance.ts +30 -22
- package/src/rebalance_methods/driftRebalance.ts +30 -22
- package/src/rebalance_methods/expanderRebalance.ts +7 -4
- package/src/rebalance_methods/pricePercentageRebalance.ts +13 -6
- package/src/rebalance_methods/pricePercentageWithResetRebalance.ts +13 -6
- package/src/rebalance_methods/takeProfitRebalance.ts +13 -5
- package/src/services/MeteoraService.ts +5 -2
- package/src/services/OrcaService.ts +163 -126
- package/src/services/OrcaWhirlpoolsResponse.ts +69 -101
- package/src/services/RaydiumService.ts +8 -2
- package/src/utils/farms.ts +0 -0
- package/src/utils/index.ts +1 -0
- package/src/utils/lookupTable.ts +2 -2
- package/src/utils/orca.ts +377 -1
- package/src/utils/tokenUtils.ts +5 -5
- package/src/utils/types.ts +7 -0
- package/src/utils/utils.ts +2 -4
- package/src/utils/whirlpools.ts +50 -31
package/src/Kamino.ts
CHANGED
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
AccountRole,
|
|
5
5
|
address,
|
|
6
6
|
Address,
|
|
7
|
+
Base58EncodedBytes,
|
|
7
8
|
fetchEncodedAccounts,
|
|
8
9
|
generateKeyPairSigner,
|
|
9
10
|
getAddressEncoder,
|
|
@@ -30,21 +31,15 @@ import {
|
|
|
30
31
|
InitializeTickArrayAccounts,
|
|
31
32
|
InitializeTickArrayArgs,
|
|
32
33
|
} from './@codegen/whirlpools/instructions';
|
|
33
|
-
import { Position, TickArray, Whirlpool } from './@codegen/whirlpools/accounts';
|
|
34
|
+
import { Position as OrcaPosition, TickArray, Whirlpool } from './@codegen/whirlpools/accounts';
|
|
34
35
|
import {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
priceToTickIndex,
|
|
43
|
-
sqrtPriceX64ToPrice,
|
|
44
|
-
tickIndexToPrice,
|
|
45
|
-
} from '@orca-so/whirlpool-sdk';
|
|
46
|
-
import { OrcaDAL } from '@orca-so/whirlpool-sdk/dist/dal/orca-dal';
|
|
47
|
-
import { OrcaPosition } from '@orca-so/whirlpool-sdk/dist/position/orca-position';
|
|
36
|
+
sqrtPriceToPrice as orcaSqrtPriceToPrice,
|
|
37
|
+
getTickArrayStartTickIndex as orcaGetTickArrayStartTickIndex,
|
|
38
|
+
priceToTickIndex as orcaPriceToTickIndex,
|
|
39
|
+
IncreaseLiquidityQuote,
|
|
40
|
+
sqrtPriceToPrice,
|
|
41
|
+
tickIndexToPrice as orcaTickIndexToPrice,
|
|
42
|
+
} from '@orca-so/whirlpools-core';
|
|
48
43
|
import {
|
|
49
44
|
getEmptyShareData,
|
|
50
45
|
Holdings,
|
|
@@ -119,7 +114,9 @@ import {
|
|
|
119
114
|
WithdrawAllAndCloseIxns,
|
|
120
115
|
WithdrawShares,
|
|
121
116
|
ZERO,
|
|
122
|
-
|
|
117
|
+
getNearestValidTickIndexFromTickIndex as orcaGetNearestValidTickIndexFromTickIndex,
|
|
118
|
+
getIncreaseLiquidityQuote,
|
|
119
|
+
defaultSlippagePercentageBPS,
|
|
123
120
|
} from './utils';
|
|
124
121
|
import {
|
|
125
122
|
checkExpectedVaultsBalances,
|
|
@@ -165,7 +162,7 @@ import {
|
|
|
165
162
|
import BN from 'bn.js';
|
|
166
163
|
import StrategyWithAddress from './models/StrategyWithAddress';
|
|
167
164
|
import { Rebalancing, Uninitialized } from './@codegen/kliquidity/types/StrategyStatus';
|
|
168
|
-
import { FRONTEND_KAMINO_STRATEGY_URL, METADATA_PROGRAM_ID, U64_MAX } from './constants';
|
|
165
|
+
import { FRONTEND_KAMINO_STRATEGY_URL, METADATA_PROGRAM_ID, U64_MAX, ZERO_BN } from './constants';
|
|
169
166
|
import {
|
|
170
167
|
CollateralInfo,
|
|
171
168
|
ExecutiveWithdrawActionKind,
|
|
@@ -177,12 +174,7 @@ import {
|
|
|
177
174
|
} from './@codegen/kliquidity/types';
|
|
178
175
|
import { AmmConfig, PersonalPositionState, PoolState } from './@codegen/raydium/accounts';
|
|
179
176
|
|
|
180
|
-
import { OrcaService, RaydiumService, Whirlpool as
|
|
181
|
-
import {
|
|
182
|
-
getAddLiquidityQuote,
|
|
183
|
-
InternalAddLiquidityQuote,
|
|
184
|
-
InternalAddLiquidityQuoteParam,
|
|
185
|
-
} from '@orca-so/whirlpool-sdk/dist/position/quotes/add-liquidity';
|
|
177
|
+
import { OrcaService, RaydiumService, Whirlpool as WhirlpoolAPIResponse, WhirlpoolAprApy } from './services';
|
|
186
178
|
import { Pool } from './services/RaydiumPoolsResponse';
|
|
187
179
|
import {
|
|
188
180
|
UpdateCollectFeesFee,
|
|
@@ -327,10 +319,10 @@ import {
|
|
|
327
319
|
import {
|
|
328
320
|
getPdaProtocolPositionAddress,
|
|
329
321
|
i32ToBytes,
|
|
330
|
-
LiquidityMath,
|
|
331
|
-
SqrtPriceMath,
|
|
332
|
-
TickMath,
|
|
333
|
-
TickUtils,
|
|
322
|
+
LiquidityMath as RaydiumLiquidityMath,
|
|
323
|
+
SqrtPriceMath as RaydiumSqrtPriceMath,
|
|
324
|
+
TickMath as RaydiumTickMath,
|
|
325
|
+
TickUtils as RaydiumTickUtils,
|
|
334
326
|
} from '@raydium-io/raydium-sdk-v2/lib';
|
|
335
327
|
import {
|
|
336
328
|
ASSOCIATED_TOKEN_PROGRAM_ADDRESS,
|
|
@@ -355,6 +347,7 @@ import { fetchMultipleLookupTableAccounts } from './utils/lookupTable';
|
|
|
355
347
|
import type { AccountInfoBase, AccountInfoWithJsonData, AccountInfoWithPubkey } from '@solana/rpc-types';
|
|
356
348
|
import { Connection } from '@solana/web3.js';
|
|
357
349
|
import { toLegacyPublicKey } from './utils/compat';
|
|
350
|
+
import { IncreaseLiquidityQuoteParam } from '@orca-so/whirlpools';
|
|
358
351
|
|
|
359
352
|
const addressEncoder = getAddressEncoder();
|
|
360
353
|
|
|
@@ -408,7 +401,7 @@ export class Kamino {
|
|
|
408
401
|
}
|
|
409
402
|
|
|
410
403
|
this._scope = new Scope(cluster, rpc);
|
|
411
|
-
this._orcaService = new OrcaService(rpc, legacyConnection,
|
|
404
|
+
this._orcaService = new OrcaService(rpc, legacyConnection, whirlpoolProgramId);
|
|
412
405
|
this._raydiumService = new RaydiumService(rpc, legacyConnection, raydiumProgramId);
|
|
413
406
|
this._meteoraService = new MeteoraService(rpc, meteoraProgramId);
|
|
414
407
|
|
|
@@ -419,6 +412,8 @@ export class Kamino {
|
|
|
419
412
|
|
|
420
413
|
getConnection = () => this._rpc;
|
|
421
414
|
|
|
415
|
+
getLegacyConnection = () => this._legacyConnection;
|
|
416
|
+
|
|
422
417
|
getProgramID = () => this._kliquidityProgramId;
|
|
423
418
|
|
|
424
419
|
setGlobalConfig = (globalConfig: Address) => {
|
|
@@ -962,7 +957,7 @@ export class Kamino {
|
|
|
962
957
|
if (pools.length === 0) {
|
|
963
958
|
throw new Error(`No pool found for ${poolTokenA.toString()} and ${poolTokenB.toString()}`);
|
|
964
959
|
}
|
|
965
|
-
return pools[0].price;
|
|
960
|
+
return Number(pools[0].price);
|
|
966
961
|
} else if (dex === 'RAYDIUM') {
|
|
967
962
|
const pools = await this.getRaydiumPoolsForTokens(poolTokenA, poolTokenB);
|
|
968
963
|
if (pools.length === 0) {
|
|
@@ -1033,7 +1028,7 @@ export class Kamino {
|
|
|
1033
1028
|
let pool: Address = DEFAULT_PUBLIC_KEY;
|
|
1034
1029
|
const orcaPools = await this.getOrcaPoolsForTokens(poolTokenA, poolTokenB);
|
|
1035
1030
|
orcaPools.forEach((element) => {
|
|
1036
|
-
if (element.
|
|
1031
|
+
if (element.feeRate * FullBPS === feeBPS.toNumber()) {
|
|
1037
1032
|
pool = address(element.address);
|
|
1038
1033
|
}
|
|
1039
1034
|
});
|
|
@@ -1080,22 +1075,24 @@ export class Kamino {
|
|
|
1080
1075
|
if (dex === 'ORCA') {
|
|
1081
1076
|
const pools = await this.getOrcaPoolsForTokens(tokenMintA, tokenMintB);
|
|
1082
1077
|
const genericPoolInfos: GenericPoolInfo[] = await Promise.all(
|
|
1083
|
-
pools.map(async (pool:
|
|
1078
|
+
pools.map(async (pool: WhirlpoolAPIResponse) => {
|
|
1084
1079
|
const positionsCount = new Decimal(await this.getPositionsCountForPool(dex, address(pool.address)));
|
|
1085
1080
|
// read price from pool
|
|
1086
|
-
const poolData = await this._orcaService.
|
|
1081
|
+
const poolData = await this._orcaService.getOrcaWhirlpool(address(pool.address));
|
|
1087
1082
|
if (!poolData) {
|
|
1088
1083
|
throw new Error(`Pool ${pool.address} not found`);
|
|
1089
1084
|
}
|
|
1090
1085
|
const poolInfo: GenericPoolInfo = {
|
|
1091
1086
|
dex,
|
|
1092
1087
|
address: address(pool.address),
|
|
1093
|
-
price:
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1088
|
+
price: new Decimal(
|
|
1089
|
+
orcaSqrtPriceToPrice(BigInt(poolData.sqrtPrice), pool.tokenA.decimals, pool.tokenB.decimals)
|
|
1090
|
+
),
|
|
1091
|
+
tokenMintA: address(pool.tokenMintA),
|
|
1092
|
+
tokenMintB: address(pool.tokenMintB),
|
|
1093
|
+
tvl: pool.tvlUsdc ? new Decimal(pool.tvlUsdc) : undefined,
|
|
1094
|
+
feeRate: new Decimal(pool.feeRate).mul(FullBPS),
|
|
1095
|
+
volumeOnLast7d: pool.stats['7d'] ? new Decimal(pool.stats['7d'].volume) : undefined,
|
|
1099
1096
|
tickSpacing: new Decimal(pool.tickSpacing),
|
|
1100
1097
|
positions: positionsCount,
|
|
1101
1098
|
};
|
|
@@ -1157,15 +1154,15 @@ export class Kamino {
|
|
|
1157
1154
|
}
|
|
1158
1155
|
}
|
|
1159
1156
|
|
|
1160
|
-
getOrcaPoolsForTokens = async (poolTokenA: Address, poolTokenB: Address): Promise<
|
|
1161
|
-
const pools:
|
|
1157
|
+
getOrcaPoolsForTokens = async (poolTokenA: Address, poolTokenB: Address): Promise<WhirlpoolAPIResponse[]> => {
|
|
1158
|
+
const pools: WhirlpoolAPIResponse[] = [];
|
|
1162
1159
|
const poolTokenAString = poolTokenA.toString();
|
|
1163
1160
|
const poolTokenBString = poolTokenB.toString();
|
|
1164
1161
|
const whirlpools = await this._orcaService.getOrcaWhirlpools();
|
|
1165
|
-
whirlpools.
|
|
1162
|
+
whirlpools.forEach((element) => {
|
|
1166
1163
|
if (
|
|
1167
|
-
(element.
|
|
1168
|
-
(element.
|
|
1164
|
+
(element.tokenMintA === poolTokenAString && element.tokenMintB === poolTokenBString) ||
|
|
1165
|
+
(element.tokenMintA === poolTokenBString && element.tokenMintB === poolTokenAString)
|
|
1169
1166
|
)
|
|
1170
1167
|
pools.push(element);
|
|
1171
1168
|
});
|
|
@@ -1244,7 +1241,7 @@ export class Kamino {
|
|
|
1244
1241
|
filters.push({
|
|
1245
1242
|
memcmp: {
|
|
1246
1243
|
offset: 0n,
|
|
1247
|
-
bytes: bs58.encode(WhirlpoolStrategy.discriminator),
|
|
1244
|
+
bytes: bs58.encode(WhirlpoolStrategy.discriminator) as Base58EncodedBytes,
|
|
1248
1245
|
encoding: 'base58',
|
|
1249
1246
|
},
|
|
1250
1247
|
});
|
|
@@ -1253,7 +1250,7 @@ export class Kamino {
|
|
|
1253
1250
|
filters.push({
|
|
1254
1251
|
memcmp: {
|
|
1255
1252
|
offset: 8n,
|
|
1256
|
-
bytes: strategyFilters.owner,
|
|
1253
|
+
bytes: strategyFilters.owner.toString() as Base58EncodedBytes,
|
|
1257
1254
|
encoding: 'base58',
|
|
1258
1255
|
},
|
|
1259
1256
|
});
|
|
@@ -1263,7 +1260,7 @@ export class Kamino {
|
|
|
1263
1260
|
filters.push({
|
|
1264
1261
|
memcmp: {
|
|
1265
1262
|
offset: 1625n,
|
|
1266
|
-
bytes: strategyCreationStatusToBase58(strategyFilters.strategyCreationStatus),
|
|
1263
|
+
bytes: strategyCreationStatusToBase58(strategyFilters.strategyCreationStatus) as Base58EncodedBytes,
|
|
1267
1264
|
encoding: 'base58',
|
|
1268
1265
|
},
|
|
1269
1266
|
});
|
|
@@ -1272,7 +1269,7 @@ export class Kamino {
|
|
|
1272
1269
|
filters.push({
|
|
1273
1270
|
memcmp: {
|
|
1274
1271
|
offset: 1120n,
|
|
1275
|
-
bytes: strategyTypeToBase58(strategyFilters.strategyType).toString(),
|
|
1272
|
+
bytes: strategyTypeToBase58(strategyFilters.strategyType).toString() as Base58EncodedBytes,
|
|
1276
1273
|
encoding: 'base58',
|
|
1277
1274
|
},
|
|
1278
1275
|
});
|
|
@@ -1283,7 +1280,7 @@ export class Kamino {
|
|
|
1283
1280
|
filters.push({
|
|
1284
1281
|
memcmp: {
|
|
1285
1282
|
offset: 1664n,
|
|
1286
|
-
bytes: value,
|
|
1283
|
+
bytes: value as Base58EncodedBytes,
|
|
1287
1284
|
encoding: 'base58',
|
|
1288
1285
|
},
|
|
1289
1286
|
});
|
|
@@ -1323,13 +1320,13 @@ export class Kamino {
|
|
|
1323
1320
|
{
|
|
1324
1321
|
memcmp: {
|
|
1325
1322
|
offset: 0n,
|
|
1326
|
-
bytes: bs58.encode(WhirlpoolStrategy.discriminator),
|
|
1323
|
+
bytes: bs58.encode(WhirlpoolStrategy.discriminator) as Base58EncodedBytes,
|
|
1327
1324
|
encoding: 'base58',
|
|
1328
1325
|
},
|
|
1329
1326
|
},
|
|
1330
1327
|
{
|
|
1331
1328
|
memcmp: {
|
|
1332
|
-
bytes: kTokenMint,
|
|
1329
|
+
bytes: kTokenMint.toString() as Base58EncodedBytes,
|
|
1333
1330
|
offset: 720n,
|
|
1334
1331
|
encoding: 'base58',
|
|
1335
1332
|
},
|
|
@@ -1484,7 +1481,7 @@ export class Kamino {
|
|
|
1484
1481
|
);
|
|
1485
1482
|
|
|
1486
1483
|
fetchBalances.push(
|
|
1487
|
-
...this.getBalance<Whirlpool,
|
|
1484
|
+
...this.getBalance<Whirlpool, OrcaPosition>(
|
|
1488
1485
|
orcaStrategies,
|
|
1489
1486
|
orcaPools,
|
|
1490
1487
|
orcaPositions,
|
|
@@ -1602,18 +1599,18 @@ export class Kamino {
|
|
|
1602
1599
|
const decimalsA = strategy.tokenAMintDecimals.toNumber();
|
|
1603
1600
|
const decimalsB = strategy.tokenBMintDecimals.toNumber();
|
|
1604
1601
|
|
|
1605
|
-
const poolPrice =
|
|
1602
|
+
const poolPrice = RaydiumSqrtPriceMath.sqrtPriceX64ToPrice(pool.sqrtPriceX64, decimalsA, decimalsB);
|
|
1606
1603
|
const twapPrice =
|
|
1607
1604
|
strategyPrices.aTwapPrice !== null && strategyPrices.bTwapPrice !== null
|
|
1608
1605
|
? strategyPrices.aTwapPrice.div(strategyPrices.bTwapPrice)
|
|
1609
1606
|
: null;
|
|
1610
|
-
const upperPrice =
|
|
1611
|
-
|
|
1607
|
+
const upperPrice = RaydiumSqrtPriceMath.sqrtPriceX64ToPrice(
|
|
1608
|
+
RaydiumSqrtPriceMath.getSqrtPriceX64FromTick(position.tickUpperIndex),
|
|
1612
1609
|
decimalsA,
|
|
1613
1610
|
decimalsB
|
|
1614
1611
|
);
|
|
1615
|
-
const lowerPrice =
|
|
1616
|
-
|
|
1612
|
+
const lowerPrice = RaydiumSqrtPriceMath.sqrtPriceX64ToPrice(
|
|
1613
|
+
RaydiumSqrtPriceMath.getSqrtPriceX64FromTick(position.tickLowerIndex),
|
|
1617
1614
|
decimalsA,
|
|
1618
1615
|
decimalsB
|
|
1619
1616
|
);
|
|
@@ -1726,10 +1723,10 @@ export class Kamino {
|
|
|
1726
1723
|
position: PersonalPositionState,
|
|
1727
1724
|
mode: 'DEPOSIT' | 'WITHDRAW' = 'WITHDRAW'
|
|
1728
1725
|
): TokenHoldings => {
|
|
1729
|
-
const lowerSqrtPriceX64 =
|
|
1730
|
-
const upperSqrtPriceX64 =
|
|
1726
|
+
const lowerSqrtPriceX64 = RaydiumSqrtPriceMath.getSqrtPriceX64FromTick(position.tickLowerIndex);
|
|
1727
|
+
const upperSqrtPriceX64 = RaydiumSqrtPriceMath.getSqrtPriceX64FromTick(position.tickUpperIndex);
|
|
1731
1728
|
|
|
1732
|
-
const { amountA, amountB } =
|
|
1729
|
+
const { amountA, amountB } = RaydiumLiquidityMath.getAmountsFromLiquidity(
|
|
1733
1730
|
pool.sqrtPriceX64,
|
|
1734
1731
|
new BN(lowerSqrtPriceX64),
|
|
1735
1732
|
new BN(upperSqrtPriceX64),
|
|
@@ -1790,7 +1787,7 @@ export class Kamino {
|
|
|
1790
1787
|
private getOrcaBalances = async (
|
|
1791
1788
|
strategy: WhirlpoolStrategy,
|
|
1792
1789
|
pool: Whirlpool,
|
|
1793
|
-
position:
|
|
1790
|
+
position: OrcaPosition,
|
|
1794
1791
|
collateralInfos: CollateralInfo[],
|
|
1795
1792
|
prices?: OraclePrices,
|
|
1796
1793
|
disabledTokensPrices?: Map<Address, Decimal>,
|
|
@@ -1814,13 +1811,13 @@ export class Kamino {
|
|
|
1814
1811
|
const decimalsA = strategy.tokenAMintDecimals.toNumber();
|
|
1815
1812
|
const decimalsB = strategy.tokenBMintDecimals.toNumber();
|
|
1816
1813
|
|
|
1817
|
-
const poolPrice =
|
|
1814
|
+
const poolPrice = new Decimal(orcaSqrtPriceToPrice(BigInt(pool.sqrtPrice.toString()), decimalsA, decimalsB));
|
|
1818
1815
|
const twapPrice =
|
|
1819
1816
|
strategyPrices.aTwapPrice !== null && strategyPrices.bTwapPrice !== null
|
|
1820
1817
|
? strategyPrices.aTwapPrice.div(strategyPrices.bTwapPrice)
|
|
1821
1818
|
: null;
|
|
1822
|
-
const upperPrice =
|
|
1823
|
-
const lowerPrice =
|
|
1819
|
+
const upperPrice = new Decimal(orcaTickIndexToPrice(position.tickUpperIndex, decimalsA, decimalsB));
|
|
1820
|
+
const lowerPrice = new Decimal(orcaTickIndexToPrice(position.tickLowerIndex, decimalsA, decimalsB));
|
|
1824
1821
|
let lowerResetPrice: Decimal | null = null;
|
|
1825
1822
|
let upperResetPrice: Decimal | null = null;
|
|
1826
1823
|
const dex = numberToDex(strategy.strategyDex.toNumber());
|
|
@@ -1856,14 +1853,14 @@ export class Kamino {
|
|
|
1856
1853
|
private getOrcaTokensBalances = (
|
|
1857
1854
|
strategy: WhirlpoolStrategy,
|
|
1858
1855
|
pool: Whirlpool,
|
|
1859
|
-
position:
|
|
1856
|
+
position: OrcaPosition,
|
|
1860
1857
|
mode: 'DEPOSIT' | 'WITHDRAW' = 'WITHDRAW'
|
|
1861
1858
|
): TokenHoldings => {
|
|
1862
1859
|
const quote = getRemoveLiquidityQuote(
|
|
1863
1860
|
{
|
|
1864
1861
|
positionAddress: strategy.position,
|
|
1865
1862
|
liquidity: position.liquidity,
|
|
1866
|
-
slippageTolerance:
|
|
1863
|
+
slippageTolerance: { numerator: ZERO_BN, denominator: new BN(1000) },
|
|
1867
1864
|
sqrtPrice: pool.sqrtPrice,
|
|
1868
1865
|
tickLowerIndex: position.tickLowerIndex,
|
|
1869
1866
|
tickUpperIndex: position.tickUpperIndex,
|
|
@@ -1975,7 +1972,7 @@ export class Kamino {
|
|
|
1975
1972
|
throw Error(`Could not fetch Orca whirlpool position state with pubkey ${strategy.position.toString()}`);
|
|
1976
1973
|
}
|
|
1977
1974
|
const whirlpool = Whirlpool.decode(Buffer.from(whirlpoolAcc.data[0], 'base64'));
|
|
1978
|
-
const position =
|
|
1975
|
+
const position = OrcaPosition.decode(Buffer.from(positionAcc.data[0], 'base64'));
|
|
1979
1976
|
return this.getOrcaTokensBalances(strategy, whirlpool, position, mode);
|
|
1980
1977
|
} else if (strategy.strategyDex.toNumber() === dexToNumber('RAYDIUM')) {
|
|
1981
1978
|
const [poolStateAcc, positionAcc] = (
|
|
@@ -2049,7 +2046,7 @@ export class Kamino {
|
|
|
2049
2046
|
throw Error(`Could not fetch Orca whirlpool position state with pubkey ${strategy.position.toString()}`);
|
|
2050
2047
|
}
|
|
2051
2048
|
const whirlpool = Whirlpool.decode(Buffer.from(whirlpoolAcc.data[0], 'base64'));
|
|
2052
|
-
const position =
|
|
2049
|
+
const position = OrcaPosition.decode(Buffer.from(positionAcc.data[0], 'base64'));
|
|
2053
2050
|
|
|
2054
2051
|
return this.getOrcaBalances(
|
|
2055
2052
|
strategy,
|
|
@@ -2328,7 +2325,10 @@ export class Kamino {
|
|
|
2328
2325
|
//datasize:165 filter selects all token accounts, memcmp filter selects based on the mint address withing each token account
|
|
2329
2326
|
return this._rpc
|
|
2330
2327
|
.getProgramAccounts(TOKEN_PROGRAM_ADDRESS, {
|
|
2331
|
-
filters: [
|
|
2328
|
+
filters: [
|
|
2329
|
+
{ dataSize: 165n },
|
|
2330
|
+
{ memcmp: { offset: 0n, bytes: shareMint.toString() as Base58EncodedBytes, encoding: 'base58' } },
|
|
2331
|
+
],
|
|
2332
2332
|
encoding: 'jsonParsed',
|
|
2333
2333
|
})
|
|
2334
2334
|
.send();
|
|
@@ -2343,7 +2343,10 @@ export class Kamino {
|
|
|
2343
2343
|
//how to get all token accounts for specific wallet: https://spl.solana.com/token#finding-all-token-accounts-for-a-wallet
|
|
2344
2344
|
return this._rpc
|
|
2345
2345
|
.getProgramAccounts(TOKEN_PROGRAM_ADDRESS, {
|
|
2346
|
-
filters: [
|
|
2346
|
+
filters: [
|
|
2347
|
+
{ dataSize: 165n },
|
|
2348
|
+
{ memcmp: { offset: 32n, bytes: wallet.toString() as Base58EncodedBytes, encoding: 'base58' } },
|
|
2349
|
+
],
|
|
2347
2350
|
encoding: 'jsonParsed',
|
|
2348
2351
|
})
|
|
2349
2352
|
.send();
|
|
@@ -2437,12 +2440,12 @@ export class Kamino {
|
|
|
2437
2440
|
if (positionPk === DEFAULT_PUBLIC_KEY) {
|
|
2438
2441
|
return { lowerPrice: ZERO, upperPrice: ZERO };
|
|
2439
2442
|
}
|
|
2440
|
-
const position = await
|
|
2443
|
+
const position = await OrcaPosition.fetch(this._rpc, positionPk, this._orcaService.getWhirlpoolProgramId());
|
|
2441
2444
|
if (!position) {
|
|
2442
2445
|
return { lowerPrice: ZERO, upperPrice: ZERO };
|
|
2443
2446
|
}
|
|
2444
|
-
const lowerPrice =
|
|
2445
|
-
const upperPrice =
|
|
2447
|
+
const lowerPrice = new Decimal(orcaTickIndexToPrice(position.tickLowerIndex, decimalsA, decimalsB));
|
|
2448
|
+
const upperPrice = new Decimal(orcaTickIndexToPrice(position.tickUpperIndex, decimalsA, decimalsB));
|
|
2446
2449
|
|
|
2447
2450
|
const positionRange: PositionRange = { lowerPrice, upperPrice };
|
|
2448
2451
|
|
|
@@ -2465,14 +2468,14 @@ export class Kamino {
|
|
|
2465
2468
|
if (!position) {
|
|
2466
2469
|
return { lowerPrice: ZERO, upperPrice: ZERO };
|
|
2467
2470
|
}
|
|
2468
|
-
const lowerPrice = sqrtPriceX64ToPrice(
|
|
2469
|
-
|
|
2471
|
+
const lowerPrice = RaydiumSqrtPriceMath.sqrtPriceX64ToPrice(
|
|
2472
|
+
RaydiumSqrtPriceMath.getSqrtPriceX64FromTick(position.tickLowerIndex),
|
|
2470
2473
|
decimalsA,
|
|
2471
2474
|
decimalsB
|
|
2472
2475
|
);
|
|
2473
2476
|
|
|
2474
|
-
const upperPrice = sqrtPriceX64ToPrice(
|
|
2475
|
-
|
|
2477
|
+
const upperPrice = RaydiumSqrtPriceMath.sqrtPriceX64ToPrice(
|
|
2478
|
+
RaydiumSqrtPriceMath.getSqrtPriceX64FromTick(position.tickUpperIndex),
|
|
2476
2479
|
decimalsA,
|
|
2477
2480
|
decimalsB
|
|
2478
2481
|
);
|
|
@@ -2554,17 +2557,21 @@ export class Kamino {
|
|
|
2554
2557
|
return whirlpoolMap;
|
|
2555
2558
|
};
|
|
2556
2559
|
|
|
2560
|
+
getAllWhirlpoolsFromAPI = async (tokens: Address[] = []): Promise<WhirlpoolAPIResponse[]> => {
|
|
2561
|
+
return await this._orcaService.getOrcaWhirlpools(tokens);
|
|
2562
|
+
};
|
|
2563
|
+
|
|
2557
2564
|
/**
|
|
2558
2565
|
* Get a list of Orca positions from public keys
|
|
2559
2566
|
* @param positions
|
|
2560
2567
|
*/
|
|
2561
|
-
getOrcaPositions = async (positions: Address[]): Promise<(
|
|
2568
|
+
getOrcaPositions = async (positions: Address[]): Promise<(OrcaPosition | null)[]> => {
|
|
2562
2569
|
const nonDefaults = positions.filter((value) => value !== DEFAULT_PUBLIC_KEY);
|
|
2563
2570
|
const fetched = await batchFetch(nonDefaults, (chunk) =>
|
|
2564
|
-
|
|
2571
|
+
OrcaPosition.fetchMultiple(this._rpc, chunk, this._orcaService.getWhirlpoolProgramId())
|
|
2565
2572
|
);
|
|
2566
|
-
const fetchedMap: Record<string,
|
|
2567
|
-
(map: Record<Address,
|
|
2573
|
+
const fetchedMap: Record<string, OrcaPosition | null> = fetched.reduce(
|
|
2574
|
+
(map: Record<Address, OrcaPosition | null>, position, i) => {
|
|
2568
2575
|
map[nonDefaults[i]] = position;
|
|
2569
2576
|
return map;
|
|
2570
2577
|
},
|
|
@@ -4501,8 +4508,8 @@ export class Kamino {
|
|
|
4501
4508
|
tickLowerIndex: number,
|
|
4502
4509
|
tickUpperIndex: number
|
|
4503
4510
|
): Promise<LowerAndUpperTickPubkeys> => {
|
|
4504
|
-
const startTickIndex =
|
|
4505
|
-
const endTickIndex =
|
|
4511
|
+
const startTickIndex = orcaGetTickArrayStartTickIndex(tickLowerIndex, whirlpoolState.tickSpacing);
|
|
4512
|
+
const endTickIndex = orcaGetTickArrayStartTickIndex(tickUpperIndex, whirlpoolState.tickSpacing);
|
|
4506
4513
|
|
|
4507
4514
|
const [lowerTickPubkey, lowerTickBump] = await getProgramDerivedAddress({
|
|
4508
4515
|
seeds: [Buffer.from('tick_array'), addressEncoder.encode(whirlpool), Buffer.from(startTickIndex.toString())],
|
|
@@ -4526,8 +4533,8 @@ export class Kamino {
|
|
|
4526
4533
|
tickLowerIndex: number,
|
|
4527
4534
|
tickUpperIndex: number
|
|
4528
4535
|
): Promise<LowerAndUpperTickPubkeys> => {
|
|
4529
|
-
const startTickIndex =
|
|
4530
|
-
const endTickIndex =
|
|
4536
|
+
const startTickIndex = RaydiumTickUtils.getTickArrayStartIndexByTick(tickLowerIndex, poolState.tickSpacing);
|
|
4537
|
+
const endTickIndex = RaydiumTickUtils.getTickArrayStartIndexByTick(tickUpperIndex, poolState.tickSpacing);
|
|
4531
4538
|
|
|
4532
4539
|
const [lowerTickPubkey, lowerTickBump] = await getProgramDerivedAddress({
|
|
4533
4540
|
seeds: [Buffer.from('tick_array'), addressEncoder.encode(pool), i32ToBytes(startTickIndex)],
|
|
@@ -4767,12 +4774,12 @@ export class Kamino {
|
|
|
4767
4774
|
const decimalsA = await getMintDecimals(this._rpc, whirlpool.tokenMintA);
|
|
4768
4775
|
const decimalsB = await getMintDecimals(this._rpc, whirlpool.tokenMintB);
|
|
4769
4776
|
|
|
4770
|
-
const tickLowerIndex =
|
|
4771
|
-
|
|
4777
|
+
const tickLowerIndex = orcaGetTickArrayStartTickIndex(
|
|
4778
|
+
orcaPriceToTickIndex(priceLower.toNumber(), decimalsA, decimalsB),
|
|
4772
4779
|
whirlpool.tickSpacing
|
|
4773
4780
|
);
|
|
4774
|
-
const tickUpperIndex =
|
|
4775
|
-
|
|
4781
|
+
const tickUpperIndex = orcaGetTickArrayStartTickIndex(
|
|
4782
|
+
orcaPriceToTickIndex(priceUpper.toNumber(), decimalsA, decimalsB),
|
|
4776
4783
|
whirlpool.tickSpacing
|
|
4777
4784
|
);
|
|
4778
4785
|
|
|
@@ -4898,15 +4905,15 @@ export class Kamino {
|
|
|
4898
4905
|
const decimalsA = await getMintDecimals(this._rpc, poolState.tokenMint0);
|
|
4899
4906
|
const decimalsB = await getMintDecimals(this._rpc, poolState.tokenMint1);
|
|
4900
4907
|
|
|
4901
|
-
const tickLowerIndex =
|
|
4902
|
-
|
|
4908
|
+
const tickLowerIndex = RaydiumTickMath.getTickWithPriceAndTickspacing(
|
|
4909
|
+
RaydiumTickMath.roundPriceWithTickspacing(priceLower, poolState.tickSpacing, decimalsA, decimalsB),
|
|
4903
4910
|
poolState.tickSpacing,
|
|
4904
4911
|
decimalsA,
|
|
4905
4912
|
decimalsB
|
|
4906
4913
|
);
|
|
4907
4914
|
|
|
4908
|
-
const tickUpperIndex =
|
|
4909
|
-
|
|
4915
|
+
const tickUpperIndex = RaydiumTickMath.getTickWithPriceAndTickspacing(
|
|
4916
|
+
RaydiumTickMath.roundPriceWithTickspacing(priceUpper, poolState.tickSpacing, decimalsA, decimalsB),
|
|
4910
4917
|
poolState.tickSpacing,
|
|
4911
4918
|
decimalsA,
|
|
4912
4919
|
decimalsB
|
|
@@ -5461,7 +5468,7 @@ export class Kamino {
|
|
|
5461
5468
|
const { whirlpool: whilrpoolState } = await this.getWhirlpoolStateIfNotFetched(pool);
|
|
5462
5469
|
if (rebalanceTypeKind.kind === RebalanceType.Drift.kind) {
|
|
5463
5470
|
processedRebalanceParams[0] = new Decimal(
|
|
5464
|
-
|
|
5471
|
+
orcaGetNearestValidTickIndexFromTickIndex(rebalanceParams[0].toNumber(), whilrpoolState.tickSpacing)
|
|
5465
5472
|
);
|
|
5466
5473
|
}
|
|
5467
5474
|
}
|
|
@@ -5830,7 +5837,7 @@ export class Kamino {
|
|
|
5830
5837
|
return getPositionRangeFromExpanderParams(price, rebalanceParams[0], rebalanceParams[1]);
|
|
5831
5838
|
|
|
5832
5839
|
case RebalanceType.Autodrift.kind:
|
|
5833
|
-
const currentTickIndex =
|
|
5840
|
+
const currentTickIndex = orcaPriceToTickIndex(price.toNumber(), tokenADecimals, tokenBDecimals);
|
|
5834
5841
|
const startMidTick = new Decimal(currentTickIndex);
|
|
5835
5842
|
return getPositionRangeFromAutodriftParams(
|
|
5836
5843
|
dex,
|
|
@@ -5852,12 +5859,22 @@ export class Kamino {
|
|
|
5852
5859
|
const pool = strategyWithAddress.strategy.pool;
|
|
5853
5860
|
const dex = numberToDex(strategyWithAddress.strategy.strategyDex.toNumber());
|
|
5854
5861
|
|
|
5855
|
-
return this.getCurrentPriceFromPool(
|
|
5862
|
+
return this.getCurrentPriceFromPool(
|
|
5863
|
+
dex,
|
|
5864
|
+
pool,
|
|
5865
|
+
strategyWithAddress.strategy.tokenAMintDecimals.toNumber(),
|
|
5866
|
+
strategyWithAddress.strategy.tokenBMintDecimals.toNumber()
|
|
5867
|
+
);
|
|
5856
5868
|
}
|
|
5857
5869
|
|
|
5858
|
-
async getCurrentPriceFromPool(
|
|
5870
|
+
async getCurrentPriceFromPool(
|
|
5871
|
+
dex: Dex,
|
|
5872
|
+
pool: Address,
|
|
5873
|
+
tokenADecimals?: number,
|
|
5874
|
+
tokenBDecimals?: number
|
|
5875
|
+
): Promise<Decimal> {
|
|
5859
5876
|
if (dex === 'ORCA') {
|
|
5860
|
-
return this.getOrcaPoolPrice(pool);
|
|
5877
|
+
return this.getOrcaPoolPrice(pool, tokenADecimals, tokenBDecimals);
|
|
5861
5878
|
} else if (dex === 'RAYDIUM') {
|
|
5862
5879
|
return this.getRaydiumPoolPrice(pool);
|
|
5863
5880
|
} else if (dex === 'METEORA') {
|
|
@@ -6234,9 +6251,9 @@ export class Kamino {
|
|
|
6234
6251
|
/**
|
|
6235
6252
|
* Read the pool price for a specific dex and pool
|
|
6236
6253
|
*/
|
|
6237
|
-
async getPoolPrice(dex: Dex, pool: Address): Promise<Decimal> {
|
|
6254
|
+
async getPoolPrice(dex: Dex, pool: Address, tokenADecimals: number, tokenBDecimals: number): Promise<Decimal> {
|
|
6238
6255
|
if (dex === 'ORCA') {
|
|
6239
|
-
return this.getOrcaPoolPrice(pool);
|
|
6256
|
+
return this.getOrcaPoolPrice(pool, tokenADecimals, tokenBDecimals);
|
|
6240
6257
|
} else if (dex === 'RAYDIUM') {
|
|
6241
6258
|
return this.getRaydiumPoolPrice(pool);
|
|
6242
6259
|
} else if (dex === 'METEORA') {
|
|
@@ -6246,12 +6263,25 @@ export class Kamino {
|
|
|
6246
6263
|
}
|
|
6247
6264
|
}
|
|
6248
6265
|
|
|
6249
|
-
async getOrcaPoolPrice(pool: Address): Promise<Decimal> {
|
|
6250
|
-
|
|
6251
|
-
if (
|
|
6252
|
-
|
|
6266
|
+
async getOrcaPoolPrice(pool: Address, tokenADecimals?: number, tokenBDecimals?: number): Promise<Decimal> {
|
|
6267
|
+
// if the decimals are provided read from API, otherwise use RPC
|
|
6268
|
+
if (tokenADecimals && tokenBDecimals) {
|
|
6269
|
+
const whirlpool = await Whirlpool.fetch(this._rpc, pool, this._orcaService.getWhirlpoolProgramId());
|
|
6270
|
+
if (!whirlpool) {
|
|
6271
|
+
throw Error(`Could not fetch Whirlpool data for ${pool.toString()}`);
|
|
6272
|
+
}
|
|
6273
|
+
|
|
6274
|
+
return new Decimal(sqrtPriceToPrice(BigInt(whirlpool.sqrtPrice.toString()), tokenADecimals, tokenBDecimals));
|
|
6275
|
+
} else {
|
|
6276
|
+
const whirlpool = await this._orcaService.getOrcaWhirlpool(pool);
|
|
6277
|
+
if (!whirlpool) {
|
|
6278
|
+
throw Error(`Could not fetch Whirlpool data for ${pool.toString()}`);
|
|
6279
|
+
}
|
|
6280
|
+
|
|
6281
|
+
return new Decimal(
|
|
6282
|
+
sqrtPriceToPrice(BigInt(whirlpool.sqrtPrice.toString()), whirlpool.tokenA.decimals, whirlpool.tokenB.decimals)
|
|
6283
|
+
);
|
|
6253
6284
|
}
|
|
6254
|
-
return poolData.price;
|
|
6255
6285
|
}
|
|
6256
6286
|
|
|
6257
6287
|
async getRaydiumPoolPrice(pool: Address): Promise<Decimal> {
|
|
@@ -6260,7 +6290,7 @@ export class Kamino {
|
|
|
6260
6290
|
throw new Error(`Raydium poolState ${pool.toString()} is not found`);
|
|
6261
6291
|
}
|
|
6262
6292
|
|
|
6263
|
-
const price =
|
|
6293
|
+
const price = RaydiumSqrtPriceMath.sqrtPriceX64ToPrice(
|
|
6264
6294
|
poolState.sqrtPriceX64,
|
|
6265
6295
|
poolState.mintDecimals0,
|
|
6266
6296
|
poolState.mintDecimals1
|
|
@@ -6329,7 +6359,9 @@ export class Kamino {
|
|
|
6329
6359
|
) {
|
|
6330
6360
|
return await this._rpc
|
|
6331
6361
|
.getProgramAccounts(ADDRESS_LOOKUP_TABLE_PROGRAM_ADDRESS, {
|
|
6332
|
-
filters: [
|
|
6362
|
+
filters: [
|
|
6363
|
+
{ memcmp: { offset: 22n, bytes: LUT_OWNER_KEY.toString() as Base58EncodedBytes, encoding: 'base58' } },
|
|
6364
|
+
],
|
|
6333
6365
|
dataSlice: { length: 0, offset: 0 },
|
|
6334
6366
|
})
|
|
6335
6367
|
.send()
|
|
@@ -6692,7 +6724,7 @@ export class Kamino {
|
|
|
6692
6724
|
*/
|
|
6693
6725
|
getStrategyAprApy = async (
|
|
6694
6726
|
strategy: Address | StrategyWithAddress,
|
|
6695
|
-
orcaPools?:
|
|
6727
|
+
orcaPools?: WhirlpoolAPIResponse[],
|
|
6696
6728
|
raydiumPools?: Pool[]
|
|
6697
6729
|
): Promise<WhirlpoolAprApy> => {
|
|
6698
6730
|
const { strategy: strategyState } = await this.getStrategyStateIfNotFetched(strategy);
|
|
@@ -6717,7 +6749,7 @@ export class Kamino {
|
|
|
6717
6749
|
if (isOrca) {
|
|
6718
6750
|
const prices = await this.getAllPrices();
|
|
6719
6751
|
const collateralInfos = await this.getCollateralInfos();
|
|
6720
|
-
return this._orcaService.getStrategyWhirlpoolPoolAprApy(strategyState, collateralInfos, prices
|
|
6752
|
+
return this._orcaService.getStrategyWhirlpoolPoolAprApy(strategyState, collateralInfos, prices);
|
|
6721
6753
|
}
|
|
6722
6754
|
if (isRaydium) {
|
|
6723
6755
|
return this._raydiumService.getStrategyWhirlpoolPoolAprApy(strategyState, raydiumPools);
|
|
@@ -6951,10 +6983,10 @@ export class Kamino {
|
|
|
6951
6983
|
const decimalsA = poolState.mintDecimals0;
|
|
6952
6984
|
const decimalsB = poolState.mintDecimals1;
|
|
6953
6985
|
|
|
6954
|
-
const { amountA, amountB } =
|
|
6986
|
+
const { amountA, amountB } = RaydiumLiquidityMath.getAmountsFromLiquidity(
|
|
6955
6987
|
poolState.sqrtPriceX64,
|
|
6956
|
-
|
|
6957
|
-
|
|
6988
|
+
RaydiumSqrtPriceMath.priceToSqrtPriceX64(lowerPrice, decimalsA, decimalsB),
|
|
6989
|
+
RaydiumSqrtPriceMath.priceToSqrtPriceX64(upperPrice, decimalsA, decimalsB),
|
|
6958
6990
|
new BN(100_000_000),
|
|
6959
6991
|
true
|
|
6960
6992
|
);
|
|
@@ -6972,31 +7004,31 @@ export class Kamino {
|
|
|
6972
7004
|
const decimalsA = await getMintDecimals(this._rpc, tokenMintA);
|
|
6973
7005
|
const decimalsB = await getMintDecimals(this._rpc, tokenMintB);
|
|
6974
7006
|
|
|
6975
|
-
const tickLowerIndex =
|
|
6976
|
-
|
|
7007
|
+
const tickLowerIndex = orcaGetNearestValidTickIndexFromTickIndex(
|
|
7008
|
+
orcaPriceToTickIndex(lowerPrice.toNumber(), decimalsA, decimalsB),
|
|
6977
7009
|
whirlpoolState.tickSpacing
|
|
6978
7010
|
);
|
|
6979
|
-
const tickUpperIndex =
|
|
6980
|
-
|
|
7011
|
+
const tickUpperIndex = orcaGetNearestValidTickIndexFromTickIndex(
|
|
7012
|
+
orcaPriceToTickIndex(upperPrice.toNumber(), decimalsA, decimalsB),
|
|
6981
7013
|
whirlpoolState.tickSpacing
|
|
6982
7014
|
);
|
|
6983
7015
|
|
|
6984
|
-
const
|
|
6985
|
-
|
|
6986
|
-
tokenMintB: toLegacyPublicKey(tokenMintB),
|
|
6987
|
-
tickCurrentIndex: whirlpoolState.tickCurrentIndex,
|
|
6988
|
-
sqrtPrice: whirlpoolState.sqrtPrice,
|
|
6989
|
-
inputTokenMint: toLegacyPublicKey(tokenMintA),
|
|
6990
|
-
inputTokenAmount: new BN(collToLamportsDecimal(tokenAAmountToDeposit, decimalsA).toString()),
|
|
6991
|
-
tickLowerIndex,
|
|
6992
|
-
tickUpperIndex,
|
|
6993
|
-
slippageTolerance: defaultSlippagePercentage,
|
|
7016
|
+
const param: IncreaseLiquidityQuoteParam = {
|
|
7017
|
+
tokenA: BigInt(collToLamportsDecimal(tokenAAmountToDeposit, decimalsA).toString()),
|
|
6994
7018
|
};
|
|
6995
7019
|
|
|
6996
|
-
const addLiqResult:
|
|
7020
|
+
const addLiqResult: IncreaseLiquidityQuote = getIncreaseLiquidityQuote(
|
|
7021
|
+
param,
|
|
7022
|
+
whirlpoolState,
|
|
7023
|
+
tickLowerIndex,
|
|
7024
|
+
tickUpperIndex,
|
|
7025
|
+
defaultSlippagePercentageBPS,
|
|
7026
|
+
undefined,
|
|
7027
|
+
undefined
|
|
7028
|
+
);
|
|
6997
7029
|
return [
|
|
6998
|
-
lamportsToNumberDecimal(addLiqResult.
|
|
6999
|
-
lamportsToNumberDecimal(addLiqResult.
|
|
7030
|
+
lamportsToNumberDecimal(new Decimal(addLiqResult.tokenEstA.toString()), decimalsA),
|
|
7031
|
+
lamportsToNumberDecimal(new Decimal(addLiqResult.tokenEstB.toString()), decimalsB),
|
|
7000
7032
|
];
|
|
7001
7033
|
} else if (dex === 'METEORA') {
|
|
7002
7034
|
const poolState = await LbPair.fetch(this._rpc, pool, this._meteoraService.getMeteoraProgramId());
|
|
@@ -7118,9 +7150,7 @@ export class Kamino {
|
|
|
7118
7150
|
}
|
|
7119
7151
|
|
|
7120
7152
|
return this.calculateAmountsOrca({
|
|
7121
|
-
|
|
7122
|
-
tokenAMint: strategyState.tokenAMint,
|
|
7123
|
-
tokenBMint: strategyState.tokenBMint,
|
|
7153
|
+
whirlpoolState: whirlpool,
|
|
7124
7154
|
positionAddress: strategyState.position,
|
|
7125
7155
|
tokenAAmount,
|
|
7126
7156
|
tokenBAmount,
|
|
@@ -7135,16 +7165,12 @@ export class Kamino {
|
|
|
7135
7165
|
};
|
|
7136
7166
|
|
|
7137
7167
|
calculateAmountsOrca = async ({
|
|
7138
|
-
|
|
7139
|
-
tokenAMint,
|
|
7140
|
-
tokenBMint,
|
|
7168
|
+
whirlpoolState,
|
|
7141
7169
|
positionAddress,
|
|
7142
7170
|
tokenAAmount,
|
|
7143
7171
|
tokenBAmount,
|
|
7144
7172
|
}: {
|
|
7145
|
-
|
|
7146
|
-
tokenAMint: Address;
|
|
7147
|
-
tokenBMint: Address;
|
|
7173
|
+
whirlpoolState: Whirlpool;
|
|
7148
7174
|
positionAddress: Address;
|
|
7149
7175
|
tokenAAmount?: Decimal;
|
|
7150
7176
|
tokenBAmount?: Decimal;
|
|
@@ -7152,47 +7178,61 @@ export class Kamino {
|
|
|
7152
7178
|
if (!tokenAAmount && !tokenBAmount) {
|
|
7153
7179
|
return [new Decimal(0), new Decimal(0)];
|
|
7154
7180
|
}
|
|
7181
|
+
|
|
7155
7182
|
// Given A in ATA, calc how much A and B
|
|
7156
|
-
const
|
|
7157
|
-
const
|
|
7158
|
-
|
|
7183
|
+
const defaultSlippagePercentageBPS = 10;
|
|
7184
|
+
const positionState = await OrcaPosition.fetch(
|
|
7185
|
+
this._rpc,
|
|
7186
|
+
positionAddress,
|
|
7187
|
+
this._orcaService.getWhirlpoolProgramId()
|
|
7188
|
+
);
|
|
7189
|
+
if (!positionState) {
|
|
7190
|
+
throw new Error(`Unable to get Orca position for pubkey ${positionAddress}`);
|
|
7191
|
+
}
|
|
7159
7192
|
|
|
7160
|
-
|
|
7161
|
-
const primaryTokenMint = tokenAAmount ? tokenAMint : tokenBMint;
|
|
7162
|
-
const secondaryTokenAmount = tokenAAmount ? tokenBAmount : tokenAAmount;
|
|
7163
|
-
const secondaryTokenMint = tokenAAmount ? tokenBMint : tokenAMint;
|
|
7193
|
+
let computedAmounts: [Decimal, Decimal] = [new Decimal(0), new Decimal(0)];
|
|
7164
7194
|
|
|
7165
|
-
|
|
7166
|
-
|
|
7167
|
-
|
|
7168
|
-
|
|
7169
|
-
|
|
7170
|
-
|
|
7171
|
-
|
|
7172
|
-
|
|
7173
|
-
|
|
7195
|
+
if (tokenAAmount) {
|
|
7196
|
+
const tokenAForQuote = BigInt(tokenAAmount.toString());
|
|
7197
|
+
const params: IncreaseLiquidityQuoteParam = {
|
|
7198
|
+
tokenA: tokenAForQuote,
|
|
7199
|
+
};
|
|
7200
|
+
const estimatedGivenA: IncreaseLiquidityQuote = getIncreaseLiquidityQuote(
|
|
7201
|
+
params,
|
|
7202
|
+
whirlpoolState,
|
|
7203
|
+
positionState.tickLowerIndex,
|
|
7204
|
+
positionState.tickUpperIndex,
|
|
7205
|
+
defaultSlippagePercentageBPS,
|
|
7206
|
+
undefined, // todo: use new Wirlpool state and read transfer fees
|
|
7207
|
+
undefined
|
|
7208
|
+
);
|
|
7209
|
+
computedAmounts = [
|
|
7210
|
+
new Decimal(estimatedGivenA.tokenEstA.toString()),
|
|
7211
|
+
new Decimal(estimatedGivenA.tokenEstB.toString()),
|
|
7212
|
+
];
|
|
7213
|
+
}
|
|
7174
7214
|
|
|
7175
|
-
if (
|
|
7176
|
-
|
|
7177
|
-
|
|
7178
|
-
|
|
7179
|
-
params = {
|
|
7180
|
-
positionAddress,
|
|
7181
|
-
tokenMint: secondaryTokenMint,
|
|
7182
|
-
tokenAmount: new BN(secondaryTokenAmount.toString()),
|
|
7183
|
-
refresh: true,
|
|
7184
|
-
slippageTolerance: defaultSlippagePercentage,
|
|
7215
|
+
if (tokenBAmount && computedAmounts[1] > tokenBAmount) {
|
|
7216
|
+
const tokenBForQuote = BigInt(tokenBAmount.toString());
|
|
7217
|
+
const params: IncreaseLiquidityQuoteParam = {
|
|
7218
|
+
tokenB: tokenBForQuote,
|
|
7185
7219
|
};
|
|
7186
|
-
const
|
|
7187
|
-
|
|
7188
|
-
|
|
7189
|
-
|
|
7220
|
+
const estimatedGivenB: IncreaseLiquidityQuote = getIncreaseLiquidityQuote(
|
|
7221
|
+
params,
|
|
7222
|
+
whirlpoolState,
|
|
7223
|
+
positionState.tickLowerIndex,
|
|
7224
|
+
positionState.tickUpperIndex,
|
|
7225
|
+
defaultSlippagePercentageBPS,
|
|
7226
|
+
undefined, // todo: use new Wirlpool state and read transfer fees
|
|
7227
|
+
undefined
|
|
7228
|
+
);
|
|
7229
|
+
computedAmounts = [
|
|
7230
|
+
new Decimal(estimatedGivenB.tokenEstA.toString()),
|
|
7231
|
+
new Decimal(estimatedGivenB.tokenEstB.toString()),
|
|
7190
7232
|
];
|
|
7191
7233
|
}
|
|
7192
|
-
|
|
7193
|
-
|
|
7194
|
-
new Decimal(estimatedGivenPrimary.estTokenB.toString()),
|
|
7195
|
-
];
|
|
7234
|
+
|
|
7235
|
+
return computedAmounts;
|
|
7196
7236
|
};
|
|
7197
7237
|
|
|
7198
7238
|
calculateAmountsRaydium = async ({
|
|
@@ -7224,18 +7264,18 @@ export class Kamino {
|
|
|
7224
7264
|
}
|
|
7225
7265
|
|
|
7226
7266
|
if (tokenAAmount && tokenBAmount && tokenAAmount.gt(0) && tokenBAmount.gt(0)) {
|
|
7227
|
-
const liquidity =
|
|
7267
|
+
const liquidity = RaydiumLiquidityMath.getLiquidityFromTokenAmounts(
|
|
7228
7268
|
poolState.sqrtPriceX64,
|
|
7229
|
-
|
|
7230
|
-
|
|
7269
|
+
RaydiumSqrtPriceMath.getSqrtPriceX64FromTick(position.tickLowerIndex),
|
|
7270
|
+
RaydiumSqrtPriceMath.getSqrtPriceX64FromTick(position.tickUpperIndex),
|
|
7231
7271
|
new BN(tokenAAmount.toString()),
|
|
7232
7272
|
new BN(tokenBAmount.toString())
|
|
7233
7273
|
);
|
|
7234
7274
|
|
|
7235
|
-
const { amountA, amountB } =
|
|
7275
|
+
const { amountA, amountB } = RaydiumLiquidityMath.getAmountsFromLiquidity(
|
|
7236
7276
|
poolState.sqrtPriceX64,
|
|
7237
|
-
|
|
7238
|
-
|
|
7277
|
+
RaydiumSqrtPriceMath.getSqrtPriceX64FromTick(position.tickLowerIndex),
|
|
7278
|
+
RaydiumSqrtPriceMath.getSqrtPriceX64FromTick(position.tickUpperIndex),
|
|
7239
7279
|
liquidity,
|
|
7240
7280
|
true
|
|
7241
7281
|
);
|
|
@@ -7245,10 +7285,10 @@ export class Kamino {
|
|
|
7245
7285
|
const primaryTokenAmount = tokenAAmount || tokenBAmount;
|
|
7246
7286
|
const secondaryTokenAmount = tokenAAmount ? tokenBAmount : tokenAAmount;
|
|
7247
7287
|
|
|
7248
|
-
const { amountA, amountB } =
|
|
7288
|
+
const { amountA, amountB } = RaydiumLiquidityMath.getAmountsFromLiquidity(
|
|
7249
7289
|
poolState.sqrtPriceX64,
|
|
7250
|
-
|
|
7251
|
-
|
|
7290
|
+
RaydiumSqrtPriceMath.getSqrtPriceX64FromTick(position.tickLowerIndex),
|
|
7291
|
+
RaydiumSqrtPriceMath.getSqrtPriceX64FromTick(position.tickUpperIndex),
|
|
7252
7292
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
7253
7293
|
new BN(primaryTokenAmount!.plus(secondaryTokenAmount || 0)!.toString()), // safe to use ! here because we check in the beginning that at least one of the amounts are not undefined;
|
|
7254
7294
|
true
|
|
@@ -7447,26 +7487,30 @@ export class Kamino {
|
|
|
7447
7487
|
throw Error(`Could not fetch whirlpool state with pubkey ${strategyState.pool.toString()}`);
|
|
7448
7488
|
}
|
|
7449
7489
|
|
|
7450
|
-
const position = await
|
|
7490
|
+
const position = await OrcaPosition.fetch(
|
|
7491
|
+
this._rpc,
|
|
7492
|
+
strategyState.position,
|
|
7493
|
+
this._orcaService.getWhirlpoolProgramId()
|
|
7494
|
+
);
|
|
7451
7495
|
if (!position) {
|
|
7452
7496
|
throw new Error(`Whirlpool position ${strategyState.position} does not exist`);
|
|
7453
7497
|
}
|
|
7454
7498
|
|
|
7455
|
-
const params:
|
|
7456
|
-
|
|
7457
|
-
tokenMintB: toLegacyPublicKey(strategyState.tokenBMint),
|
|
7458
|
-
tickCurrentIndex: whirlpool.tickCurrentIndex,
|
|
7459
|
-
sqrtPrice: whirlpool.sqrtPrice,
|
|
7460
|
-
inputTokenMint: toLegacyPublicKey(strategyState.tokenAMint),
|
|
7461
|
-
inputTokenAmount: amountA,
|
|
7462
|
-
tickLowerIndex: position.tickLowerIndex,
|
|
7463
|
-
tickUpperIndex: position.tickUpperIndex,
|
|
7464
|
-
slippageTolerance: defaultSlippagePercentage,
|
|
7499
|
+
const params: IncreaseLiquidityQuoteParam = {
|
|
7500
|
+
tokenA: BigInt(amountA.toString()),
|
|
7465
7501
|
};
|
|
7466
7502
|
|
|
7467
|
-
const quote:
|
|
7503
|
+
const quote: IncreaseLiquidityQuote = getIncreaseLiquidityQuote(
|
|
7504
|
+
params,
|
|
7505
|
+
whirlpool,
|
|
7506
|
+
position.tickLowerIndex,
|
|
7507
|
+
position.tickUpperIndex,
|
|
7508
|
+
defaultSlippagePercentageBPS,
|
|
7509
|
+
undefined,
|
|
7510
|
+
undefined
|
|
7511
|
+
);
|
|
7468
7512
|
|
|
7469
|
-
return { amountSlippageA: quote.
|
|
7513
|
+
return { amountSlippageA: new BN(quote.tokenEstA.toString()), amountSlippageB: new BN(quote.tokenEstB.toString()) };
|
|
7470
7514
|
}
|
|
7471
7515
|
|
|
7472
7516
|
private async getDepositRatioFromAMeteora(
|
|
@@ -7517,26 +7561,30 @@ export class Kamino {
|
|
|
7517
7561
|
throw Error(`Could not fetch whirlpool state with pubkey ${strategyState.pool.toString()}`);
|
|
7518
7562
|
}
|
|
7519
7563
|
|
|
7520
|
-
const position = await
|
|
7564
|
+
const position = await OrcaPosition.fetch(
|
|
7565
|
+
this._rpc,
|
|
7566
|
+
strategyState.position,
|
|
7567
|
+
this._orcaService.getWhirlpoolProgramId()
|
|
7568
|
+
);
|
|
7521
7569
|
if (!position) {
|
|
7522
7570
|
throw new Error(`Whirlpool position ${strategyState.position} does not exist`);
|
|
7523
7571
|
}
|
|
7524
7572
|
|
|
7525
|
-
const
|
|
7526
|
-
|
|
7527
|
-
tokenMintB: toLegacyPublicKey(strategyState.tokenBMint),
|
|
7528
|
-
tickCurrentIndex: whirlpool.tickCurrentIndex,
|
|
7529
|
-
sqrtPrice: whirlpool.sqrtPrice,
|
|
7530
|
-
inputTokenMint: toLegacyPublicKey(strategyState.tokenBMint),
|
|
7531
|
-
inputTokenAmount: amountB,
|
|
7532
|
-
tickLowerIndex: position.tickLowerIndex,
|
|
7533
|
-
tickUpperIndex: position.tickUpperIndex,
|
|
7534
|
-
slippageTolerance: defaultSlippagePercentage,
|
|
7573
|
+
const param: IncreaseLiquidityQuoteParam = {
|
|
7574
|
+
tokenB: BigInt(amountB.toString()),
|
|
7535
7575
|
};
|
|
7536
7576
|
|
|
7537
|
-
const quote:
|
|
7577
|
+
const quote: IncreaseLiquidityQuote = getIncreaseLiquidityQuote(
|
|
7578
|
+
param,
|
|
7579
|
+
whirlpool,
|
|
7580
|
+
position.tickLowerIndex,
|
|
7581
|
+
position.tickUpperIndex,
|
|
7582
|
+
defaultSlippagePercentageBPS,
|
|
7583
|
+
undefined,
|
|
7584
|
+
undefined
|
|
7585
|
+
);
|
|
7538
7586
|
|
|
7539
|
-
return { amountSlippageA: quote.
|
|
7587
|
+
return { amountSlippageA: new BN(quote.tokenEstA.toString()), amountSlippageB: new BN(quote.tokenEstB.toString()) };
|
|
7540
7588
|
};
|
|
7541
7589
|
|
|
7542
7590
|
private getDepositRatioFromARaydium = async (
|
|
@@ -7559,11 +7607,16 @@ export class Kamino {
|
|
|
7559
7607
|
throw new Error(`Raydium pool ${strategyState.pool.toString()} could not be found.`);
|
|
7560
7608
|
}
|
|
7561
7609
|
|
|
7562
|
-
const lowerSqrtPriceX64 =
|
|
7563
|
-
const upperSqrtPriceX64 =
|
|
7610
|
+
const lowerSqrtPriceX64 = RaydiumSqrtPriceMath.getSqrtPriceX64FromTick(positionState.tickLowerIndex);
|
|
7611
|
+
const upperSqrtPriceX64 = RaydiumSqrtPriceMath.getSqrtPriceX64FromTick(positionState.tickUpperIndex);
|
|
7564
7612
|
|
|
7565
|
-
const liqudity =
|
|
7566
|
-
|
|
7613
|
+
const liqudity = RaydiumLiquidityMath.getLiquidityFromTokenAmountA(
|
|
7614
|
+
lowerSqrtPriceX64,
|
|
7615
|
+
upperSqrtPriceX64,
|
|
7616
|
+
amountA,
|
|
7617
|
+
false
|
|
7618
|
+
);
|
|
7619
|
+
const amountsSlippage = RaydiumLiquidityMath.getAmountsFromLiquidityWithSlippage(
|
|
7567
7620
|
poolState.sqrtPriceX64,
|
|
7568
7621
|
lowerSqrtPriceX64,
|
|
7569
7622
|
upperSqrtPriceX64,
|
|
@@ -7596,11 +7649,11 @@ export class Kamino {
|
|
|
7596
7649
|
throw new Error(`Raydium pool ${strategyState.pool.toString()} could not be found.`);
|
|
7597
7650
|
}
|
|
7598
7651
|
|
|
7599
|
-
const lowerSqrtPriceX64 =
|
|
7600
|
-
const upperSqrtPriceX64 =
|
|
7652
|
+
const lowerSqrtPriceX64 = RaydiumSqrtPriceMath.getSqrtPriceX64FromTick(positionState.tickLowerIndex);
|
|
7653
|
+
const upperSqrtPriceX64 = RaydiumSqrtPriceMath.getSqrtPriceX64FromTick(positionState.tickUpperIndex);
|
|
7601
7654
|
|
|
7602
|
-
const liqudity =
|
|
7603
|
-
const amountsSlippage =
|
|
7655
|
+
const liqudity = RaydiumLiquidityMath.getLiquidityFromTokenAmountB(lowerSqrtPriceX64, upperSqrtPriceX64, amountB);
|
|
7656
|
+
const amountsSlippage = RaydiumLiquidityMath.getAmountsFromLiquidityWithSlippage(
|
|
7604
7657
|
poolState.sqrtPriceX64,
|
|
7605
7658
|
lowerSqrtPriceX64,
|
|
7606
7659
|
upperSqrtPriceX64,
|
|
@@ -7869,8 +7922,11 @@ export class Kamino {
|
|
|
7869
7922
|
|
|
7870
7923
|
const decimalsA = await getMintDecimals(this._rpc, whilrpoolState.tokenMintA);
|
|
7871
7924
|
const decimalsB = await getMintDecimals(this._rpc, whilrpoolState.tokenMintB);
|
|
7872
|
-
const tickIndex =
|
|
7873
|
-
|
|
7925
|
+
const tickIndex = orcaGetTickArrayStartTickIndex(
|
|
7926
|
+
orcaPriceToTickIndex(price.toNumber(), decimalsA, decimalsB),
|
|
7927
|
+
whilrpoolState.tickSpacing
|
|
7928
|
+
);
|
|
7929
|
+
const startTickIndex = orcaGetTickArrayStartTickIndex(tickIndex, whilrpoolState.tickSpacing);
|
|
7874
7930
|
|
|
7875
7931
|
const [startTickIndexPk, _startTickIndexBump] = await getTickArray(
|
|
7876
7932
|
this._orcaService.getWhirlpoolProgramId(),
|