@kamino-finance/klend-sdk 7.3.8 → 7.3.10-beta.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/classes/action.d.ts.map +1 -1
- package/dist/classes/action.js +20 -11
- package/dist/classes/action.js.map +1 -1
- package/dist/classes/configItems.d.ts +6 -1
- package/dist/classes/configItems.d.ts.map +1 -1
- package/dist/classes/configItems.js +93 -1
- package/dist/classes/configItems.js.map +1 -1
- package/dist/classes/farm_utils.d.ts +1 -1
- package/dist/classes/farm_utils.d.ts.map +1 -1
- package/dist/classes/farm_utils.js +1 -3
- package/dist/classes/farm_utils.js.map +1 -1
- package/dist/classes/reserve.d.ts +3 -7
- package/dist/classes/reserve.d.ts.map +1 -1
- package/dist/classes/reserve.js +43 -31
- package/dist/classes/reserve.js.map +1 -1
- package/dist/classes/shared.d.ts +2 -2
- package/dist/classes/shared.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/classes/action.ts +25 -25
- package/src/classes/configItems.ts +99 -1
- package/src/classes/farm_utils.ts +1 -5
- package/src/classes/reserve.ts +122 -118
- package/src/classes/shared.ts +2 -2
package/dist/classes/shared.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Address } from '@solana/kit';
|
|
2
2
|
import Decimal from 'decimal.js';
|
|
3
|
-
import {
|
|
3
|
+
import { FarmState, RewardInfo } from '@kamino-finance/farms-sdk';
|
|
4
4
|
export type ConfigType = Array<MarketConfigType>;
|
|
5
5
|
export type MarketConfigType = {
|
|
6
6
|
name: string;
|
|
@@ -48,7 +48,7 @@ export type ReserveRewardYield = {
|
|
|
48
48
|
};
|
|
49
49
|
export type ReserveFarmInfo = {
|
|
50
50
|
fetched: boolean;
|
|
51
|
-
|
|
51
|
+
farmStates: FarmState[];
|
|
52
52
|
};
|
|
53
53
|
export declare enum FeeCalculation {
|
|
54
54
|
Inclusive = "Inclusive",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../src/classes/shared.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACtC,OAAO,OAAO,MAAM,YAAY,CAAC;AACjC,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../src/classes/shared.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACtC,OAAO,OAAO,MAAM,YAAY,CAAC;AACjC,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAElE,MAAM,MAAM,UAAU,GAAG,KAAK,CAAC,gBAAgB,CAAC,CAAC;AAEjD,MAAM,MAAM,gBAAgB,GAAG;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,OAAO,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,cAAc,EAAE;QACd,MAAM,EAAE,MAAM,CAAC;QACf,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;CACH,CAAC;AAEF,oBAAY,aAAa;IACvB,MAAM,WAAW;IACjB,QAAQ,aAAa;IACrB,MAAM,WAAW;CAClB;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B,MAAM,EAAE,aAAa,CAAC;IACtB,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,oBAAoB,EAAE,MAAM,CAAC;IAC7B,mBAAmB,EAAE,OAAO,CAAC;IAC7B,kBAAkB,EAAE,OAAO,CAAC;IAC5B,4BAA4B,EAAE,MAAM,CAAC;IACrC,2BAA2B,EAAE,MAAM,CAAC;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,EAAE,MAAM,CAAC;IACzB,uBAAuB,EAAE,OAAO,CAAC;IACjC,eAAe,EAAE,OAAO,CAAC;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,OAAO,GAAG,SAAS,CAAC;CACrC,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,GAAG,EAAE,OAAO,CAAC;IACb,GAAG,EAAE,OAAO,CAAC;IACb,UAAU,EAAE,UAAU,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,SAAS,EAAE,CAAC;CACzB,CAAC;AAEF,oBAAY,cAAc;IACxB,SAAS,cAAc;IACvB,SAAS,cAAc;CACxB;AAED,MAAM,MAAM,IAAI,GAAG;IACjB,YAAY,EAAE,OAAO,CAAC;IACtB,YAAY,EAAE,OAAO,CAAC;CACvB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG;IACxB;;OAEG;IACH,IAAI,EAAE,OAAO,CAAC;IAEd;;OAEG;IACH,MAAM,EAAE,OAAO,CAAC;CACjB,CAAC"}
|
package/package.json
CHANGED
package/src/classes/action.ts
CHANGED
|
@@ -76,11 +76,7 @@ import { Scope } from '@kamino-finance/scope-sdk';
|
|
|
76
76
|
import { ObligationOrderAtIndex } from './obligationOrder';
|
|
77
77
|
import { ASSOCIATED_TOKEN_PROGRAM_ADDRESS, TOKEN_PROGRAM_ADDRESS } from '@solana-program/token';
|
|
78
78
|
import { SYSVAR_INSTRUCTIONS_ADDRESS, SYSVAR_RENT_ADDRESS } from '@solana/sysvars';
|
|
79
|
-
import {
|
|
80
|
-
getCloseAccountInstruction,
|
|
81
|
-
getSyncNativeInstruction,
|
|
82
|
-
TOKEN_2022_PROGRAM_ADDRESS,
|
|
83
|
-
} from '@solana-program/token-2022';
|
|
79
|
+
import { getCloseAccountInstruction, getSyncNativeInstruction } from '@solana-program/token-2022';
|
|
84
80
|
import { getTransferSolInstruction, SYSTEM_PROGRAM_ADDRESS } from '@solana-program/system';
|
|
85
81
|
import { noopSigner } from '../utils/signer';
|
|
86
82
|
|
|
@@ -3293,13 +3289,8 @@ export class KaminoAction {
|
|
|
3293
3289
|
action === 'mint' ||
|
|
3294
3290
|
(action === 'liquidate' && this.mint === WRAPPED_SOL_MINT); // only sync WSOL amount if liquidator repays SOL which is secondaryMint
|
|
3295
3291
|
|
|
3296
|
-
const isValidTokenAccount =
|
|
3297
|
-
userWSOLAccountInfo.exists &&
|
|
3298
|
-
(userWSOLAccountInfo.programAddress === TOKEN_PROGRAM_ADDRESS ||
|
|
3299
|
-
userWSOLAccountInfo.programAddress === TOKEN_2022_PROGRAM_ADDRESS);
|
|
3300
|
-
|
|
3301
3292
|
const transferLamportsIx = getTransferSolInstruction({
|
|
3302
|
-
amount: (
|
|
3293
|
+
amount: (userWSOLAccountInfo.exists ? 0n : rentExemptLamports) + (sendAction ? BigInt(safeRepay.toString()) : 0n),
|
|
3303
3294
|
source: this.owner,
|
|
3304
3295
|
destination: userTokenAccountAddress,
|
|
3305
3296
|
});
|
|
@@ -3321,20 +3312,29 @@ export class KaminoAction {
|
|
|
3321
3312
|
},
|
|
3322
3313
|
{ programAddress: TOKEN_PROGRAM_ADDRESS }
|
|
3323
3314
|
);
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
|
|
3329
|
-
|
|
3330
|
-
|
|
3331
|
-
|
|
3332
|
-
|
|
3333
|
-
|
|
3334
|
-
|
|
3335
|
-
|
|
3336
|
-
|
|
3337
|
-
|
|
3315
|
+
if (userWSOLAccountInfo.exists) {
|
|
3316
|
+
if (sendAction) {
|
|
3317
|
+
preIxs.push(syncIx);
|
|
3318
|
+
preIxsLabels.push(`SyncUserAtaSOL[${userTokenAccountAddress}]`);
|
|
3319
|
+
} else {
|
|
3320
|
+
postIxs.push(closeWSOLAccountIx);
|
|
3321
|
+
postIxsLabels.push(`CloseUserAtaSOL[${userTokenAccountAddress}]`);
|
|
3322
|
+
}
|
|
3323
|
+
} else {
|
|
3324
|
+
const [, createUserWSOLAccountIx] = await createAssociatedTokenAccountIdempotentInstruction(
|
|
3325
|
+
this.owner,
|
|
3326
|
+
WRAPPED_SOL_MINT,
|
|
3327
|
+
this.owner.address,
|
|
3328
|
+
TOKEN_PROGRAM_ADDRESS,
|
|
3329
|
+
userTokenAccountAddress
|
|
3330
|
+
);
|
|
3331
|
+
preIxs.push(createUserWSOLAccountIx);
|
|
3332
|
+
preIxsLabels.push(`CreateUserAtaSOL[${userTokenAccountAddress}]`);
|
|
3333
|
+
preIxs.push(syncIx);
|
|
3334
|
+
preIxsLabels.push(`SyncUserAtaSOL[${userTokenAccountAddress}]`);
|
|
3335
|
+
postIxs.push(closeWSOLAccountIx);
|
|
3336
|
+
postIxsLabels.push(`CloseUserAtaSOL[${userTokenAccountAddress}]`);
|
|
3337
|
+
}
|
|
3338
3338
|
|
|
3339
3339
|
this.setupIxs.unshift(...preIxs);
|
|
3340
3340
|
this.setupIxsLabels.unshift(...preIxsLabels);
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { struct, Layout } from '@coral-xyz/borsh';
|
|
2
2
|
import { blobEquals, orThrow, toJson } from './utils';
|
|
3
3
|
import { Buffer } from 'buffer';
|
|
4
|
+
import { ReserveConfig } from '../lib';
|
|
5
|
+
import { UpdateConfigModeKind, UpdateConfigMode } from '../@codegen/klend/types';
|
|
4
6
|
|
|
5
7
|
/**
|
|
6
8
|
* An object literal specifying *all* "update mode" enum values (of type {@code M}) and their corresponding config items
|
|
@@ -151,7 +153,7 @@ export class ConfigItemUpdater<C, A> {
|
|
|
151
153
|
* A resolver of config item changes.
|
|
152
154
|
*/
|
|
153
155
|
export class ConfigUpdater<M extends BorshEnum, C> {
|
|
154
|
-
|
|
156
|
+
protected readonly itemUpdaters: Map<M['kind'], [M, ConfigItemUpdater<C, any>[]]>;
|
|
155
157
|
|
|
156
158
|
/**
|
|
157
159
|
* A resolving constructor.
|
|
@@ -235,6 +237,61 @@ export class ConfigUpdater<M extends BorshEnum, C> {
|
|
|
235
237
|
}
|
|
236
238
|
}
|
|
237
239
|
|
|
240
|
+
export class EntireReserveConfigUpdater extends ConfigUpdater<UpdateConfigModeKind, ReserveConfig> {
|
|
241
|
+
encodeAllUpdates(
|
|
242
|
+
currentConfig: ReserveConfig | undefined,
|
|
243
|
+
newConfig: ReserveConfig
|
|
244
|
+
): EncodedConfigUpdate<UpdateConfigModeKind>[] {
|
|
245
|
+
const updates: EncodedConfigUpdate<UpdateConfigModeKind>[] = [];
|
|
246
|
+
let ltvUpdate: EncodedConfigUpdate<UpdateConfigModeKind> | undefined;
|
|
247
|
+
let liquidationThresholdUpdate: EncodedConfigUpdate<UpdateConfigModeKind> | undefined;
|
|
248
|
+
|
|
249
|
+
for (const [mode, itemUpdaters] of this.itemUpdaters.values()) {
|
|
250
|
+
for (const itemUpdater of itemUpdaters) {
|
|
251
|
+
const value = itemUpdater.encodeUpdatedItemFrom(currentConfig, newConfig);
|
|
252
|
+
if (value === undefined) {
|
|
253
|
+
continue;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
const update = { mode, value };
|
|
257
|
+
|
|
258
|
+
if (mode.discriminator === UpdateConfigMode.UpdateLoanToValuePct.discriminator) {
|
|
259
|
+
ltvUpdate = update;
|
|
260
|
+
} else if (mode.discriminator === UpdateConfigMode.UpdateLiquidationThresholdPct.discriminator) {
|
|
261
|
+
liquidationThresholdUpdate = update;
|
|
262
|
+
// If reserve is already initialized, skip fields that require global admin signature on update
|
|
263
|
+
} else {
|
|
264
|
+
updates.push(update);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// Handle ordering of LTV and LiquidationThreshold updates
|
|
270
|
+
// ensure LiquidationThreshold >= LTV at all times
|
|
271
|
+
if (ltvUpdate && liquidationThresholdUpdate) {
|
|
272
|
+
const currentLiquidationThreshold = currentConfig ? currentConfig.liquidationThresholdPct : 0;
|
|
273
|
+
const newLiquidationThreshold = newConfig.liquidationThresholdPct;
|
|
274
|
+
|
|
275
|
+
if (newLiquidationThreshold > currentLiquidationThreshold) {
|
|
276
|
+
// Liquidation threshold is increasing, so it must be updated first
|
|
277
|
+
updates.push(liquidationThresholdUpdate);
|
|
278
|
+
updates.push(ltvUpdate);
|
|
279
|
+
} else {
|
|
280
|
+
// All other cases, it's safer to update the LTV first
|
|
281
|
+
updates.push(ltvUpdate);
|
|
282
|
+
updates.push(liquidationThresholdUpdate);
|
|
283
|
+
}
|
|
284
|
+
} else if (ltvUpdate) {
|
|
285
|
+
updates.push(ltvUpdate);
|
|
286
|
+
} else if (liquidationThresholdUpdate) {
|
|
287
|
+
updates.push(liquidationThresholdUpdate);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
updates.sort((left, right) => priorityOf(left.mode) - priorityOf(right.mode));
|
|
291
|
+
return updates;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
238
295
|
/**
|
|
239
296
|
* The update mode discriminator and the serialized value needed to construct an update ix.
|
|
240
297
|
*/
|
|
@@ -293,3 +350,44 @@ type Getter<C, A> = (config: C) => A;
|
|
|
293
350
|
function toArray<T>(singleOrArray: SingleOrArray<T>): T[] {
|
|
294
351
|
return Array.isArray(singleOrArray) ? singleOrArray : [singleOrArray];
|
|
295
352
|
}
|
|
353
|
+
|
|
354
|
+
// Lowest priority gets updated first
|
|
355
|
+
function priorityOf(mode: UpdateConfigModeKind): number {
|
|
356
|
+
switch (mode.discriminator) {
|
|
357
|
+
case UpdateConfigMode.UpdateScopePriceFeed.discriminator:
|
|
358
|
+
return 0;
|
|
359
|
+
case UpdateConfigMode.UpdateTokenInfoScopeTwap.discriminator:
|
|
360
|
+
return 0;
|
|
361
|
+
case UpdateConfigMode.UpdateTokenInfoScopeChain.discriminator:
|
|
362
|
+
return 0;
|
|
363
|
+
case UpdateConfigMode.UpdateTokenInfoLowerHeuristic.discriminator:
|
|
364
|
+
return 0;
|
|
365
|
+
case UpdateConfigMode.UpdateTokenInfoUpperHeuristic.discriminator:
|
|
366
|
+
return 0;
|
|
367
|
+
case UpdateConfigMode.UpdateTokenInfoExpHeuristic.discriminator:
|
|
368
|
+
return 0;
|
|
369
|
+
case UpdateConfigMode.UpdateTokenInfoTwapDivergence.discriminator:
|
|
370
|
+
return 0;
|
|
371
|
+
case UpdateConfigMode.UpdateTokenInfoName.discriminator:
|
|
372
|
+
return 0;
|
|
373
|
+
case UpdateConfigMode.UpdateTokenInfoPriceMaxAge.discriminator:
|
|
374
|
+
return 0;
|
|
375
|
+
case UpdateConfigMode.UpdateTokenInfoTwapMaxAge.discriminator:
|
|
376
|
+
return 0;
|
|
377
|
+
case UpdateConfigMode.UpdateDeleveragingBonusIncreaseBpsPerDay.discriminator:
|
|
378
|
+
return priorityOf(new UpdateConfigMode.UpdateAutodeleverageEnabled()) - 1;
|
|
379
|
+
case UpdateConfigMode.UpdateDeleveragingMarginCallPeriod.discriminator:
|
|
380
|
+
return priorityOf(new UpdateConfigMode.UpdateAutodeleverageEnabled()) - 1;
|
|
381
|
+
case UpdateConfigMode.UpdateDeleveragingThresholdDecreaseBpsPerDay.discriminator:
|
|
382
|
+
return priorityOf(new UpdateConfigMode.UpdateAutodeleverageEnabled()) - 1;
|
|
383
|
+
case UpdateConfigMode.UpdateAutodeleverageEnabled.discriminator:
|
|
384
|
+
return 4;
|
|
385
|
+
// Always update last bc we cannot skip validation
|
|
386
|
+
case UpdateConfigMode.UpdateDepositLimit.discriminator:
|
|
387
|
+
return 63;
|
|
388
|
+
case UpdateConfigMode.UpdateBorrowLimit.discriminator:
|
|
389
|
+
return 63;
|
|
390
|
+
default:
|
|
391
|
+
return 10;
|
|
392
|
+
}
|
|
393
|
+
}
|
|
@@ -8,7 +8,6 @@ import {
|
|
|
8
8
|
scaleDownWads,
|
|
9
9
|
WAD,
|
|
10
10
|
RewardInfo,
|
|
11
|
-
RewardType,
|
|
12
11
|
} from '@kamino-finance/farms-sdk';
|
|
13
12
|
import {
|
|
14
13
|
address,
|
|
@@ -175,7 +174,7 @@ export type UnstakeAndWithdrawFromFarmIxs = {
|
|
|
175
174
|
withdrawIx: Instruction;
|
|
176
175
|
};
|
|
177
176
|
|
|
178
|
-
export function getRewardPerTimeUnitSecond(reward: RewardInfo
|
|
177
|
+
export function getRewardPerTimeUnitSecond(reward: RewardInfo) {
|
|
179
178
|
const now = new Decimal(new Date().getTime()).div(1000);
|
|
180
179
|
let rewardPerTimeUnitSecond = new Decimal(0);
|
|
181
180
|
for (let i = 0; i < reward.rewardScheduleCurve.points.length - 1; i++) {
|
|
@@ -197,11 +196,8 @@ export function getRewardPerTimeUnitSecond(reward: RewardInfo, farmTotalStakeLam
|
|
|
197
196
|
const rewardTokenDecimals = reward.token.decimals.toNumber();
|
|
198
197
|
const rewardAmountPerUnitDecimals = new Decimal(10).pow(reward.rewardsPerSecondDecimals.toString());
|
|
199
198
|
const rewardAmountPerUnitLamports = new Decimal(10).pow(rewardTokenDecimals.toString());
|
|
200
|
-
const constantRewardStakeAdjustment =
|
|
201
|
-
reward.rewardType === RewardType.Constant.discriminator ? farmTotalStakeLamports : new Decimal(1);
|
|
202
199
|
|
|
203
200
|
const rpsAdjusted = new Decimal(rewardPerTimeUnitSecond.toString())
|
|
204
|
-
.mul(constantRewardStakeAdjustment)
|
|
205
201
|
.div(rewardAmountPerUnitDecimals)
|
|
206
202
|
.div(rewardAmountPerUnitLamports);
|
|
207
203
|
|
package/src/classes/reserve.ts
CHANGED
|
@@ -24,7 +24,6 @@ import {
|
|
|
24
24
|
INITIAL_COLLATERAL_RATE,
|
|
25
25
|
lendingMarketAuthPda,
|
|
26
26
|
MarketWithAddress,
|
|
27
|
-
MIN_INITIAL_DEPOSIT,
|
|
28
27
|
ONE_HUNDRED_PCT_IN_BPS,
|
|
29
28
|
reservePdas,
|
|
30
29
|
SLOTS_PER_DAY,
|
|
@@ -37,7 +36,7 @@ import { FeeCalculation, Fees, ReserveDataType, ReserveFarmInfo, ReserveRewardYi
|
|
|
37
36
|
import { Reserve, ReserveFields } from '../@codegen/klend/accounts';
|
|
38
37
|
import { CurvePointFields, ReserveConfig, UpdateConfigMode, UpdateConfigModeKind } from '../@codegen/klend/types';
|
|
39
38
|
import { calculateAPYFromAPR, getBorrowRate, lamportsToNumberDecimal, parseTokenSymbol, positiveOrZero } from './utils';
|
|
40
|
-
import { CompositeConfigItem, encodeUsingLayout,
|
|
39
|
+
import { CompositeConfigItem, encodeUsingLayout, EntireReserveConfigUpdater } from './configItems';
|
|
41
40
|
import { bfToDecimal, Fraction } from './fraction';
|
|
42
41
|
import { ActionType } from './action';
|
|
43
42
|
import { BorrowCapsAndCounters, ElevationGroupDescription, KaminoMarket } from './market';
|
|
@@ -49,7 +48,7 @@ import {
|
|
|
49
48
|
UpdateReserveConfigArgs,
|
|
50
49
|
} from '../lib';
|
|
51
50
|
import { aprToApy, KaminoPrices } from '@kamino-finance/kliquidity-sdk';
|
|
52
|
-
import {
|
|
51
|
+
import { FarmState, RewardInfo } from '@kamino-finance/farms-sdk';
|
|
53
52
|
import { TOKEN_PROGRAM_ADDRESS } from '@solana-program/token';
|
|
54
53
|
import { maxBigInt } from '../utils/bigint';
|
|
55
54
|
import { getCreateAccountInstruction, SYSTEM_PROGRAM_ADDRESS } from '@solana-program/system';
|
|
@@ -70,7 +69,7 @@ export class KaminoReserve {
|
|
|
70
69
|
|
|
71
70
|
tokenOraclePrice: TokenOracleData;
|
|
72
71
|
stats: ReserveDataType;
|
|
73
|
-
private farmData: ReserveFarmInfo = { fetched: false,
|
|
72
|
+
private farmData: ReserveFarmInfo = { fetched: false, farmStates: [] };
|
|
74
73
|
|
|
75
74
|
private rpc: Rpc<KaminoReserveRpcApi>;
|
|
76
75
|
private readonly recentSlotDurationMs: number;
|
|
@@ -813,22 +812,22 @@ export class KaminoReserve {
|
|
|
813
812
|
|
|
814
813
|
async loadFarmStates() {
|
|
815
814
|
if (!this.farmData.fetched) {
|
|
816
|
-
const farmStates:
|
|
815
|
+
const farmStates: FarmState[] = [];
|
|
817
816
|
const debtFarmAddress = this.getDebtFarmAddress();
|
|
818
817
|
if (isSome(debtFarmAddress)) {
|
|
819
818
|
const farmState = await FarmState.fetch(this.rpc, debtFarmAddress.value);
|
|
820
819
|
if (farmState !== null) {
|
|
821
|
-
farmStates.push(
|
|
820
|
+
farmStates.push(farmState);
|
|
822
821
|
}
|
|
823
822
|
}
|
|
824
823
|
const collateralFarmAddress = this.getCollateralFarmAddress();
|
|
825
824
|
if (isSome(collateralFarmAddress)) {
|
|
826
825
|
const farmState = await FarmState.fetch(this.rpc, collateralFarmAddress.value);
|
|
827
826
|
if (farmState !== null) {
|
|
828
|
-
farmStates.push(
|
|
827
|
+
farmStates.push(farmState);
|
|
829
828
|
}
|
|
830
829
|
}
|
|
831
|
-
this.farmData.
|
|
830
|
+
this.farmData.farmStates = farmStates;
|
|
832
831
|
this.farmData.fetched = true;
|
|
833
832
|
}
|
|
834
833
|
}
|
|
@@ -839,19 +838,14 @@ export class KaminoReserve {
|
|
|
839
838
|
throw Error('KaminoMarket must call loadReserves.');
|
|
840
839
|
}
|
|
841
840
|
|
|
841
|
+
const isDebtReward = this.state.farmDebt === this.address;
|
|
842
842
|
await this.loadFarmStates();
|
|
843
843
|
const yields: ReserveRewardYield[] = [];
|
|
844
|
-
for (const
|
|
845
|
-
const
|
|
846
|
-
for (const rewardInfo of farmAndKey.farmState.rewardInfos.filter(
|
|
844
|
+
for (const farmState of this.farmData.farmStates) {
|
|
845
|
+
for (const rewardInfo of farmState.rewardInfos.filter(
|
|
847
846
|
(x) => x.token.mint !== DEFAULT_PUBLIC_KEY && !x.rewardsAvailable.isZero()
|
|
848
847
|
)) {
|
|
849
|
-
const { apy, apr } = this.calculateRewardYield(
|
|
850
|
-
prices,
|
|
851
|
-
rewardInfo,
|
|
852
|
-
isDebtReward,
|
|
853
|
-
new Decimal(farmAndKey.farmState.totalActiveStakeScaled.toString())
|
|
854
|
-
);
|
|
848
|
+
const { apy, apr } = this.calculateRewardYield(prices, rewardInfo, isDebtReward);
|
|
855
849
|
if (apy.isZero() && apr.isZero()) {
|
|
856
850
|
continue;
|
|
857
851
|
}
|
|
@@ -861,14 +855,9 @@ export class KaminoReserve {
|
|
|
861
855
|
return yields;
|
|
862
856
|
}
|
|
863
857
|
|
|
864
|
-
calculateRewardYield(
|
|
865
|
-
prices: KaminoPrices,
|
|
866
|
-
rewardInfo: RewardInfo,
|
|
867
|
-
isDebtReward: boolean,
|
|
868
|
-
farmTotalStakeLamports: Decimal
|
|
869
|
-
) {
|
|
858
|
+
private calculateRewardYield(prices: KaminoPrices, rewardInfo: RewardInfo, isDebtReward: boolean) {
|
|
870
859
|
const mintAddress = this.getLiquidityMint();
|
|
871
|
-
const rewardPerTimeUnitSecond = getRewardPerTimeUnitSecond(rewardInfo
|
|
860
|
+
const rewardPerTimeUnitSecond = getRewardPerTimeUnitSecond(rewardInfo);
|
|
872
861
|
const reserveToken = prices.spot[mintAddress.toString()];
|
|
873
862
|
const rewardToken = prices.spot[rewardInfo.token.mint.toString()];
|
|
874
863
|
|
|
@@ -1250,69 +1239,74 @@ export async function updateReserveConfigIx(
|
|
|
1250
1239
|
return updateReserveConfig(args, accounts, undefined, programId);
|
|
1251
1240
|
}
|
|
1252
1241
|
|
|
1253
|
-
export const RESERVE_CONFIG_UPDATER = new
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
config.
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
config.
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1242
|
+
export const RESERVE_CONFIG_UPDATER = new EntireReserveConfigUpdater(
|
|
1243
|
+
UpdateConfigMode.fromDecoded,
|
|
1244
|
+
ReserveConfig,
|
|
1245
|
+
(config) => ({
|
|
1246
|
+
[UpdateConfigMode.UpdateLoanToValuePct.kind]: config.loanToValuePct,
|
|
1247
|
+
[UpdateConfigMode.UpdateMaxLiquidationBonusBps.kind]: config.maxLiquidationBonusBps,
|
|
1248
|
+
[UpdateConfigMode.UpdateLiquidationThresholdPct.kind]: config.liquidationThresholdPct,
|
|
1249
|
+
[UpdateConfigMode.UpdateProtocolLiquidationFee.kind]: config.protocolLiquidationFeePct,
|
|
1250
|
+
[UpdateConfigMode.UpdateProtocolTakeRate.kind]: config.protocolTakeRatePct,
|
|
1251
|
+
[UpdateConfigMode.UpdateFeesOriginationFee.kind]: config.fees.originationFeeSf,
|
|
1252
|
+
[UpdateConfigMode.UpdateFeesFlashLoanFee.kind]: config.fees.flashLoanFeeSf,
|
|
1253
|
+
[UpdateConfigMode.DeprecatedUpdateFeesReferralFeeBps.kind]: [], // deprecated
|
|
1254
|
+
[UpdateConfigMode.UpdateDepositLimit.kind]: config.depositLimit,
|
|
1255
|
+
[UpdateConfigMode.UpdateBorrowLimit.kind]: config.borrowLimit,
|
|
1256
|
+
[UpdateConfigMode.UpdateTokenInfoLowerHeuristic.kind]: config.tokenInfo.heuristic.lower,
|
|
1257
|
+
[UpdateConfigMode.UpdateTokenInfoUpperHeuristic.kind]: config.tokenInfo.heuristic.upper,
|
|
1258
|
+
[UpdateConfigMode.UpdateTokenInfoExpHeuristic.kind]: config.tokenInfo.heuristic.exp,
|
|
1259
|
+
[UpdateConfigMode.UpdateTokenInfoTwapDivergence.kind]: config.tokenInfo.maxTwapDivergenceBps,
|
|
1260
|
+
[UpdateConfigMode.UpdateTokenInfoScopeTwap.kind]: config.tokenInfo.scopeConfiguration.twapChain,
|
|
1261
|
+
[UpdateConfigMode.UpdateTokenInfoScopeChain.kind]: config.tokenInfo.scopeConfiguration.priceChain,
|
|
1262
|
+
[UpdateConfigMode.UpdateTokenInfoName.kind]: config.tokenInfo.name,
|
|
1263
|
+
[UpdateConfigMode.UpdateTokenInfoPriceMaxAge.kind]: config.tokenInfo.maxAgePriceSeconds,
|
|
1264
|
+
[UpdateConfigMode.UpdateTokenInfoTwapMaxAge.kind]: config.tokenInfo.maxAgeTwapSeconds,
|
|
1265
|
+
[UpdateConfigMode.UpdateScopePriceFeed.kind]: config.tokenInfo.scopeConfiguration.priceFeed,
|
|
1266
|
+
[UpdateConfigMode.UpdatePythPrice.kind]: config.tokenInfo.pythConfiguration.price,
|
|
1267
|
+
[UpdateConfigMode.UpdateSwitchboardFeed.kind]: config.tokenInfo.switchboardConfiguration.priceAggregator,
|
|
1268
|
+
[UpdateConfigMode.UpdateSwitchboardTwapFeed.kind]: config.tokenInfo.switchboardConfiguration.twapAggregator,
|
|
1269
|
+
[UpdateConfigMode.UpdateBorrowRateCurve.kind]: config.borrowRateCurve,
|
|
1270
|
+
[UpdateConfigMode.UpdateEntireReserveConfig.kind]: [], // technically `config` would be a valid thing here, but we actually do NOT want entire config update among ixs produced for field-by-field updates
|
|
1271
|
+
[UpdateConfigMode.UpdateDebtWithdrawalCap.kind]: new CompositeConfigItem(
|
|
1272
|
+
config.debtWithdrawalCap.configCapacity,
|
|
1273
|
+
config.debtWithdrawalCap.configIntervalLengthSeconds
|
|
1274
|
+
),
|
|
1275
|
+
[UpdateConfigMode.UpdateDepositWithdrawalCap.kind]: new CompositeConfigItem(
|
|
1276
|
+
config.depositWithdrawalCap.configCapacity,
|
|
1277
|
+
config.depositWithdrawalCap.configIntervalLengthSeconds
|
|
1278
|
+
),
|
|
1279
|
+
[UpdateConfigMode.DeprecatedUpdateDebtWithdrawalCapCurrentTotal.kind]: [], // deprecated
|
|
1280
|
+
[UpdateConfigMode.DeprecatedUpdateDepositWithdrawalCapCurrentTotal.kind]: [], // deprecated
|
|
1281
|
+
[UpdateConfigMode.UpdateBadDebtLiquidationBonusBps.kind]: config.badDebtLiquidationBonusBps,
|
|
1282
|
+
[UpdateConfigMode.UpdateMinLiquidationBonusBps.kind]: config.minLiquidationBonusBps,
|
|
1283
|
+
[UpdateConfigMode.UpdateDeleveragingMarginCallPeriod.kind]: config.deleveragingMarginCallPeriodSecs,
|
|
1284
|
+
[UpdateConfigMode.UpdateBorrowFactor.kind]: config.borrowFactorPct,
|
|
1285
|
+
[UpdateConfigMode.UpdateAssetTier.kind]: config.assetTier,
|
|
1286
|
+
[UpdateConfigMode.UpdateElevationGroup.kind]: config.elevationGroups,
|
|
1287
|
+
[UpdateConfigMode.UpdateDeleveragingThresholdDecreaseBpsPerDay.kind]: config.deleveragingThresholdDecreaseBpsPerDay,
|
|
1288
|
+
[UpdateConfigMode.DeprecatedUpdateMultiplierSideBoost.kind]: [], // deprecated
|
|
1289
|
+
[UpdateConfigMode.DeprecatedUpdateMultiplierTagBoost.kind]: [], // deprecated
|
|
1290
|
+
[UpdateConfigMode.UpdateReserveStatus.kind]: config.status,
|
|
1291
|
+
[UpdateConfigMode.UpdateFarmCollateral.kind]: [], // the farm fields live on the `Reserve` level...
|
|
1292
|
+
[UpdateConfigMode.UpdateFarmDebt.kind]: [], // ...so we are not concerned with them in the `ReserveConfig`'s field-by-field update tx
|
|
1293
|
+
[UpdateConfigMode.UpdateDisableUsageAsCollateralOutsideEmode.kind]: config.disableUsageAsCollOutsideEmode,
|
|
1294
|
+
[UpdateConfigMode.UpdateBlockBorrowingAboveUtilizationPct.kind]: config.utilizationLimitBlockBorrowingAbovePct,
|
|
1295
|
+
[UpdateConfigMode.UpdateBlockPriceUsage.kind]: config.tokenInfo.blockPriceUsage,
|
|
1296
|
+
[UpdateConfigMode.UpdateBorrowLimitOutsideElevationGroup.kind]: config.borrowLimitOutsideElevationGroup,
|
|
1297
|
+
[UpdateConfigMode.UpdateBorrowLimitsInElevationGroupAgainstThisReserve.kind]:
|
|
1298
|
+
config.borrowLimitAgainstThisCollateralInElevationGroup,
|
|
1299
|
+
[UpdateConfigMode.UpdateHostFixedInterestRateBps.kind]: config.hostFixedInterestRateBps,
|
|
1300
|
+
[UpdateConfigMode.UpdateAutodeleverageEnabled.kind]: config.autodeleverageEnabled,
|
|
1301
|
+
[UpdateConfigMode.UpdateDeleveragingBonusIncreaseBpsPerDay.kind]: config.deleveragingBonusIncreaseBpsPerDay,
|
|
1302
|
+
[UpdateConfigMode.UpdateProtocolOrderExecutionFee.kind]: config.protocolOrderExecutionFeePct,
|
|
1303
|
+
[UpdateConfigMode.UpdateProposerAuthorityLock.kind]: config.proposerAuthorityLocked,
|
|
1304
|
+
[UpdateConfigMode.UpdateMinDeleveragingBonusBps.kind]: config.minDeleveragingBonusBps,
|
|
1305
|
+
[UpdateConfigMode.UpdateBlockCTokenUsage.kind]: config.blockCtokenUsage,
|
|
1306
|
+
})
|
|
1307
|
+
);
|
|
1308
|
+
|
|
1309
|
+
// TODO : this needs to be deprecated
|
|
1316
1310
|
export async function updateEntireReserveConfigIx(
|
|
1317
1311
|
signer: TransactionSigner,
|
|
1318
1312
|
marketAddress: Address,
|
|
@@ -1348,19 +1342,20 @@ export function parseForChangesReserveConfigAndGetIxs(
|
|
|
1348
1342
|
lendingMarketOwner: TransactionSigner = noopSigner(marketWithAddress.state.lendingMarketOwner)
|
|
1349
1343
|
): Promise<Instruction[]> {
|
|
1350
1344
|
const encodedConfigUpdates = RESERVE_CONFIG_UPDATER.encodeAllUpdates(reserve?.config, reserveConfig);
|
|
1351
|
-
encodedConfigUpdates.sort((left, right) => priorityOf(left.mode) - priorityOf(right.mode));
|
|
1352
1345
|
return Promise.all(
|
|
1353
|
-
encodedConfigUpdates
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1346
|
+
encodedConfigUpdates
|
|
1347
|
+
.filter((encodedConfigUpdate) => !isAdminOnly(encodedConfigUpdate.mode))
|
|
1348
|
+
.map(async (encodedConfigUpdate) =>
|
|
1349
|
+
updateReserveConfigIx(
|
|
1350
|
+
lendingMarketOwner,
|
|
1351
|
+
marketWithAddress.address,
|
|
1352
|
+
reserveAddress,
|
|
1353
|
+
encodedConfigUpdate.mode,
|
|
1354
|
+
encodedConfigUpdate.value,
|
|
1355
|
+
programId,
|
|
1356
|
+
shouldSkipValidation(encodedConfigUpdate.mode, reserve)
|
|
1357
|
+
)
|
|
1362
1358
|
)
|
|
1363
|
-
)
|
|
1364
1359
|
);
|
|
1365
1360
|
}
|
|
1366
1361
|
|
|
@@ -1369,30 +1364,39 @@ export type ReserveWithAddress = {
|
|
|
1369
1364
|
state: Reserve;
|
|
1370
1365
|
};
|
|
1371
1366
|
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
UpdateConfigMode.
|
|
1375
|
-
UpdateConfigMode.
|
|
1376
|
-
UpdateConfigMode.UpdateTokenInfoExpHeuristic.discriminator,
|
|
1377
|
-
UpdateConfigMode.UpdateTokenInfoTwapDivergence.discriminator,
|
|
1378
|
-
UpdateConfigMode.UpdateTokenInfoPriceMaxAge.discriminator,
|
|
1379
|
-
UpdateConfigMode.UpdateTokenInfoTwapMaxAge.discriminator,
|
|
1367
|
+
// Updating the deposit/borrow limit will automatically unblock usage and force validation inside the smart contract
|
|
1368
|
+
const VALIDATED_DISCRIMINATORS = [
|
|
1369
|
+
UpdateConfigMode.UpdateDepositLimit.discriminator,
|
|
1370
|
+
UpdateConfigMode.UpdateBorrowLimit.discriminator,
|
|
1380
1371
|
];
|
|
1381
1372
|
|
|
1382
1373
|
function shouldSkipValidation(mode: UpdateConfigModeKind, reserve: Reserve | undefined): boolean {
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
)
|
|
1374
|
+
if (VALIDATED_DISCRIMINATORS.includes(mode.discriminator)) {
|
|
1375
|
+
return false;
|
|
1376
|
+
}
|
|
1377
|
+
if (reserve == undefined) {
|
|
1378
|
+
return true;
|
|
1379
|
+
}
|
|
1380
|
+
const is_usage_blocked = reserve.config.depositLimit.isZero() && reserve.config.borrowLimit.isZero();
|
|
1381
|
+
return is_usage_blocked;
|
|
1387
1382
|
}
|
|
1388
1383
|
|
|
1389
|
-
function
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
return
|
|
1393
|
-
|
|
1394
|
-
return 0;
|
|
1395
|
-
default:
|
|
1396
|
-
return 1;
|
|
1384
|
+
function isAdminOnly(mode: UpdateConfigModeKind): boolean {
|
|
1385
|
+
for (const adminOnlyMode of ADMIN_ONLY_MODES) {
|
|
1386
|
+
if (mode.discriminator === adminOnlyMode.discriminator) {
|
|
1387
|
+
return true;
|
|
1388
|
+
}
|
|
1397
1389
|
}
|
|
1390
|
+
return false;
|
|
1398
1391
|
}
|
|
1392
|
+
|
|
1393
|
+
// These need to be skipped when updating the entire reserve config
|
|
1394
|
+
const ADMIN_ONLY_MODES = [
|
|
1395
|
+
UpdateConfigMode.UpdateProtocolTakeRate,
|
|
1396
|
+
UpdateConfigMode.UpdateProtocolLiquidationFee,
|
|
1397
|
+
UpdateConfigMode.UpdateHostFixedInterestRateBps,
|
|
1398
|
+
UpdateConfigMode.UpdateProtocolOrderExecutionFee,
|
|
1399
|
+
UpdateConfigMode.UpdateFeesOriginationFee,
|
|
1400
|
+
UpdateConfigMode.UpdateFeesFlashLoanFee,
|
|
1401
|
+
UpdateConfigMode.UpdateBlockCTokenUsage,
|
|
1402
|
+
];
|
package/src/classes/shared.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Address } from '@solana/kit';
|
|
2
2
|
import Decimal from 'decimal.js';
|
|
3
|
-
import {
|
|
3
|
+
import { FarmState, RewardInfo } from '@kamino-finance/farms-sdk';
|
|
4
4
|
|
|
5
5
|
export type ConfigType = Array<MarketConfigType>;
|
|
6
6
|
|
|
@@ -55,7 +55,7 @@ export type ReserveRewardYield = {
|
|
|
55
55
|
|
|
56
56
|
export type ReserveFarmInfo = {
|
|
57
57
|
fetched: boolean;
|
|
58
|
-
|
|
58
|
+
farmStates: FarmState[];
|
|
59
59
|
};
|
|
60
60
|
|
|
61
61
|
export enum FeeCalculation {
|