@kamino-finance/klend-sdk
Version:
Typescript SDK for interacting with the Kamino Lending (klend) protocol
107 lines • 5.44 kB
JavaScript
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.LtvBasedOrderTriggerType = void 0;
exports.createLtvBasedOrder = createLtvBasedOrder;
exports.readLtvBasedOrder = readLtvBasedOrder;
const decimal_js_1 = __importDefault(require("decimal.js"));
const obligationOrder_1 = require("../classes/obligationOrder");
const validations_1 = require("../utils/validations");
const common_1 = require("./common");
const internal_1 = require("./internal");
/**
* Creates an LTV-based {@link ObligationOrderAtIndex} based on the given stop-loss or take-profit specification.
*
* The returned object can then be passed directly to {@link KaminoAction.buildSetObligationOrderIxn()} to build an
* instruction which replaces (or cancels, if the specification is `null`) the given obligation's stop-loss or
* take-profit order on-chain.
*
* The given obligation cannot use 0-LTV collaterals (see {@link checkObligationCompatible()} for rationale).
*/
function createLtvBasedOrder(context, orderType, specification) {
checkObligationCompatible(context);
const index = (0, internal_1.toOrderIndex)(orderType);
if (specification === null) {
return obligationOrder_1.ObligationOrderAtIndex.empty(index);
}
const condition = toOrderCondition(orderType, specification.trigger);
(0, validations_1.checkThat)(condition.threshold().gte(MIN_LTV_THRESHOLD) && condition.threshold().lte(MAX_LTV_THRESHOLD), `LTV-based trigger outside valid range [${MIN_LTV_THRESHOLD}%; ${MAX_LTV_THRESHOLD}%]: ${condition.threshold()}%`);
return (0, internal_1.createConditionBasedOrder)(context, condition, specification).atIndex(index);
}
/**
* Parses an {@link OrderSpecification} from the selected stop-loss or take-profit order of the given obligation.
*
* The given obligation cannot use 0-LTV collaterals (see {@link checkObligationCompatible()} for rationale).
*
* The selected order is expected to be of matching type (i.e. as if it was created using the
* {@link createLtvBasedOrder()}).
*/
function readLtvBasedOrder(context, orderType) {
checkObligationCompatible(context);
const kaminoOrder = context.kaminoObligation.getOrders()[(0, internal_1.toOrderIndex)(orderType)];
if (kaminoOrder === null) {
return null;
}
const trigger = toTrigger(kaminoOrder.condition, orderType);
return (0, internal_1.readTriggerBasedOrder)(kaminoOrder, trigger);
}
/**
* A discriminator enum for {@link LtvBasedOrderTrigger};
*/
var LtvBasedOrderTriggerType;
(function (LtvBasedOrderTriggerType) {
LtvBasedOrderTriggerType["StopLoss"] = "StopLoss";
LtvBasedOrderTriggerType["TakeProfit"] = "TakeProfit";
})(LtvBasedOrderTriggerType || (exports.LtvBasedOrderTriggerType = LtvBasedOrderTriggerType = {}));
// Only internals below:
const FULL_PCT = 100;
const MIN_LTV_THRESHOLD = 0.01;
const MAX_LTV_THRESHOLD = 0.99;
function checkObligationCompatible({ kaminoMarket, kaminoObligation }) {
for (const depositReserveAddress of kaminoObligation.deposits.keys()) {
const depositReserve = kaminoMarket.getExistingReserveByAddress(depositReserveAddress);
// Note: the seemingly over-cautious requirement below ensures that the user-facing LTV calculation gives the same
// result as on the Klend SC side (they differ in the handling of 0-LTV collaterals; see
// `KaminoObligation.loanToValue()` doc for details). We may unify the 0-LTV handling some day and remove this.
(0, validations_1.checkThat)(depositReserve.state.config.loanToValuePct !== 0, `LTV-based orders cannot be used with a 0-LTV collateral: ${depositReserve.symbol}`);
}
}
function toOrderCondition(orderType, trigger) {
switch (orderType) {
case common_1.OrderType.StopLoss:
if (trigger.type === LtvBasedOrderTriggerType.StopLoss) {
return new obligationOrder_1.UserLtvAbove(new decimal_js_1.default(trigger.whenLtvPctAbove).div(FULL_PCT));
}
break;
case common_1.OrderType.TakeProfit:
if (trigger.type === LtvBasedOrderTriggerType.TakeProfit) {
return new obligationOrder_1.UserLtvBelow(new decimal_js_1.default(trigger.whenLtvPctBelow).div(FULL_PCT));
}
break;
}
throw new Error(`an LTV-based ${orderType} order cannot use ${trigger.type} condition`);
}
function toTrigger(condition, orderType) {
switch (orderType) {
case common_1.OrderType.StopLoss:
if (condition instanceof obligationOrder_1.UserLtvAbove) {
return {
type: LtvBasedOrderTriggerType.StopLoss,
whenLtvPctAbove: condition.minUserLtvExclusive.mul(FULL_PCT).toNumber(),
};
}
break;
case common_1.OrderType.TakeProfit:
if (condition instanceof obligationOrder_1.UserLtvBelow) {
return {
type: LtvBasedOrderTriggerType.TakeProfit,
whenLtvPctBelow: condition.maxUserLtvExclusive.mul(FULL_PCT).toNumber(),
};
}
break;
}
throw new Error(`an LTV-based ${orderType} order has an incompatible on-chain condition ${condition.constructor.name}`);
}
//# sourceMappingURL=ltv_based.js.map
;