@kamino-finance/klend-sdk
Version:
Typescript SDK for interacting with the Kamino Lending (klend) protocol
167 lines • 8.74 kB
JavaScript
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.PriceBasedOrderTriggerType = void 0;
exports.createPriceBasedOrder = createPriceBasedOrder;
exports.readPriceBasedOrder = readPriceBasedOrder;
const decimal_js_1 = __importDefault(require("decimal.js"));
const obligationOrder_1 = require("../classes/obligationOrder");
const utils_1 = require("../utils");
const validations_1 = require("../utils/validations");
const common_1 = require("./common");
const internal_1 = require("./internal");
/**
* Creates a price-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 is expected to be a "price-based position" - a single-debt, single-coll obligation which either
* deposits or borrows a stablecoin (i.e. a long or short position of some token against a stablecoin).
*/
function createPriceBasedOrder(context, orderType, specification) {
const positionType = resolvePositionType(context); // resolving this first has an intentional side effect of validating the obligation being compatible
const index = (0, internal_1.toOrderIndex)(orderType);
if (specification === null) {
return obligationOrder_1.ObligationOrderAtIndex.empty(index);
}
const condition = toOrderCondition(positionType, orderType, specification.trigger);
return (0, internal_1.createConditionBasedOrder)(context, condition, specification).atIndex(index);
}
/**
* Parses an {@link PriceBasedOrderSpecification} from the selected stop-loss or take-profit order of the given obligation.
*
* The given obligation is expected to be a "price-based position" - a single-debt, single-coll obligation which either
* deposits or borrows a stablecoin (i.e. a long or short position of some token against a stablecoin).
*
* The selected order is expected to be of matching type (i.e. as if it was created using the
* {@link createPriceBasedOrder()}).
*/
function readPriceBasedOrder(context, orderType) {
const positionType = resolvePositionType(context); // resolving this first has an intentional side effect of validating the obligation being compatible
const kaminoOrder = context.kaminoObligation.getOrders()[(0, internal_1.toOrderIndex)(orderType)];
if (kaminoOrder === null) {
return null;
}
const trigger = toTrigger(positionType, kaminoOrder.condition, orderType);
return (0, internal_1.readTriggerBasedOrder)(kaminoOrder, trigger);
}
/**
* A discriminator enum for {@link PriceBasedOrderTrigger};
*/
var PriceBasedOrderTriggerType;
(function (PriceBasedOrderTriggerType) {
PriceBasedOrderTriggerType["LongStopLoss"] = "LongStopLoss";
PriceBasedOrderTriggerType["LongTakeProfit"] = "LongTakeProfit";
PriceBasedOrderTriggerType["ShortStopLoss"] = "ShortStopLoss";
PriceBasedOrderTriggerType["ShortTakeProfit"] = "ShortTakeProfit";
})(PriceBasedOrderTriggerType || (exports.PriceBasedOrderTriggerType = PriceBasedOrderTriggerType = {}));
// Only internals below:
function toOrderCondition(positionType, orderType, trigger) {
switch (positionType) {
case PositionType.Long:
switch (orderType) {
case common_1.OrderType.StopLoss:
if (trigger.type === PriceBasedOrderTriggerType.LongStopLoss) {
return new obligationOrder_1.DebtCollPriceRatioAbove(invertPriceRatio(trigger.whenCollateralPriceBelow));
}
break;
case common_1.OrderType.TakeProfit:
if (trigger.type === PriceBasedOrderTriggerType.LongTakeProfit) {
return new obligationOrder_1.DebtCollPriceRatioBelow(invertPriceRatio(trigger.whenCollateralPriceAbove));
}
break;
}
break;
case PositionType.Short:
switch (orderType) {
case common_1.OrderType.StopLoss:
if (trigger.type === PriceBasedOrderTriggerType.ShortStopLoss) {
return new obligationOrder_1.DebtCollPriceRatioAbove(trigger.whenDebtPriceAbove);
}
break;
case common_1.OrderType.TakeProfit:
if (trigger.type === PriceBasedOrderTriggerType.ShortTakeProfit) {
return new obligationOrder_1.DebtCollPriceRatioBelow(trigger.whenDebtPriceBelow);
}
break;
}
break;
}
throw new Error(`a ${orderType} order on a ${positionType} position cannot use ${trigger.type} condition`);
}
function toTrigger(positionType, condition, orderType) {
switch (positionType) {
case PositionType.Long:
switch (orderType) {
case common_1.OrderType.StopLoss:
if (condition instanceof obligationOrder_1.DebtCollPriceRatioAbove) {
return {
type: PriceBasedOrderTriggerType.LongStopLoss,
whenCollateralPriceBelow: invertPriceRatio(condition.minDebtCollPriceRatioExclusive),
};
}
break;
case common_1.OrderType.TakeProfit:
if (condition instanceof obligationOrder_1.DebtCollPriceRatioBelow) {
return {
type: PriceBasedOrderTriggerType.LongTakeProfit,
whenCollateralPriceAbove: invertPriceRatio(condition.maxDebtCollPriceRatioExclusive),
};
}
break;
}
break;
case PositionType.Short:
switch (orderType) {
case common_1.OrderType.StopLoss:
if (condition instanceof obligationOrder_1.DebtCollPriceRatioAbove) {
return {
type: PriceBasedOrderTriggerType.ShortStopLoss,
whenDebtPriceAbove: condition.minDebtCollPriceRatioExclusive,
};
}
break;
case common_1.OrderType.TakeProfit:
if (condition instanceof obligationOrder_1.DebtCollPriceRatioBelow) {
return {
type: PriceBasedOrderTriggerType.ShortTakeProfit,
whenDebtPriceBelow: condition.maxDebtCollPriceRatioExclusive,
};
}
break;
}
break;
}
throw new Error(`a ${orderType} order on a ${positionType} position has an incompatible on-chain condition ${condition.constructor.name}`);
}
function invertPriceRatio(priceRatio) {
return new decimal_js_1.default(1).div(priceRatio);
}
var PositionType;
(function (PositionType) {
PositionType["Long"] = "Long";
PositionType["Short"] = "Short";
})(PositionType || (PositionType = {}));
function resolvePositionType(context) {
const collateralReserveAddress = (0, validations_1.getSingleElement)(context.kaminoObligation.deposits.keys(), 'deposit');
const debtReserveAddress = (0, validations_1.getSingleElement)(context.kaminoObligation.borrows.keys(), 'borrow');
const stablecoinReserveAddresses = collectReserveAddresses(context.kaminoMarket, context.stablecoins);
if (stablecoinReserveAddresses.contains(collateralReserveAddress)) {
(0, validations_1.checkThat)(!stablecoinReserveAddresses.contains(debtReserveAddress), 'cannot resolve long vs short position from all-stablecoins obligation');
return PositionType.Short;
}
else {
(0, validations_1.checkThat)(stablecoinReserveAddresses.contains(debtReserveAddress), 'cannot resolve long vs short position from no-stablecoins obligation');
return PositionType.Long;
}
}
function collectReserveAddresses(kaminoMarket, symbolOrMintAddresses) {
return new utils_1.PublicKeySet(symbolOrMintAddresses.map((symbolOrMintAddress) => typeof symbolOrMintAddress === 'string'
? kaminoMarket.getExistingReserveBySymbol(symbolOrMintAddress).address
: kaminoMarket.getExistingReserveByMint(symbolOrMintAddress).address));
}
//# sourceMappingURL=price_based.js.map
;