UNPKG

@kamino-finance/klend-sdk

Version:

Typescript SDK for interacting with the Kamino Lending (klend) protocol

74 lines 4.42 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.computeReservesAllocation = computeReservesAllocation; const decimal_js_1 = __importDefault(require("decimal.js")); const farms_sdk_1 = require("@kamino-finance/farms-sdk"); const ZERO = new decimal_js_1.default(0); /** * Computes the allocation of vault funds across reserves based on weights and caps * @param vaultAUM - Total AUM of the vault, in tokens * @param vaultUnallocatedWeight - Weight for unallocated funds * @param vaultUnallocatedCap - Maximum amount that can remain unallocated * @param initialVaultAllocations - Map of reserve addresses to their allocation configurations * @param vaultTokenDecimals - The number of decimals of the vault token, needed to compute the min amount * @returns Object containing target unallocated amount and target allocations per reserve, in tokens */ function computeReservesAllocation(vaultAUM, vaultUnallocatedWeight, vaultUnallocatedCap, initialVaultAllocations, vaultTokenDecimals) { let totalAllocation = new decimal_js_1.default(0); const allReserves = Array.from(initialVaultAllocations.keys()); const expectedHoldingsDistribution = new Map(); // Initialize reserve allocations and calculate total weight allReserves.forEach((reserve) => { expectedHoldingsDistribution.set(reserve, ZERO); totalAllocation = totalAllocation.add(initialVaultAllocations.get(reserve).targetWeight); }); let totalLeftToInvest = vaultAUM; const totalAllocationsIncludingUnallocated = totalAllocation.add(vaultUnallocatedWeight); // Calculate initial unallocated amount let unallocatedAllocation = totalLeftToInvest.mul(vaultUnallocatedWeight).div(totalAllocationsIncludingUnallocated); if (unallocatedAllocation.gt(vaultUnallocatedCap)) { unallocatedAllocation = vaultUnallocatedCap; } totalLeftToInvest = totalLeftToInvest.sub(unallocatedAllocation); let currentAllocationSum = totalAllocation; const reservesCount = allReserves.length; const maxRemainedUninvestedLamports = (0, farms_sdk_1.lamportsToCollDecimal)(new decimal_js_1.default(reservesCount), vaultTokenDecimals); // invest only if the AUM has more lamports than the number of reserves // Iteratively allocate funds to reserves based on weights and caps while (totalLeftToInvest.gt(maxRemainedUninvestedLamports) && currentAllocationSum.gt(ZERO)) { const totalLeftover = totalLeftToInvest; for (const reserve of allReserves) { const reserveWithWeight = initialVaultAllocations.get(reserve); if (!reserveWithWeight) continue; const targetAllocation = reserveWithWeight.targetWeight.mul(totalLeftover).div(currentAllocationSum); const reserveCap = reserveWithWeight.tokenAllocationCap; let amountToInvest = decimal_js_1.default.min(targetAllocation, totalLeftToInvest); // Handle reserve caps if (reserveCap.gt(ZERO)) { const currentReserveAllocation = expectedHoldingsDistribution.get(reserve); const remainingCapacity = reserveCap.sub(currentReserveAllocation); amountToInvest = decimal_js_1.default.min(amountToInvest, remainingCapacity); } else if (reserveCap.eq(ZERO)) { // Zero cap means no investment allowed amountToInvest = ZERO; } totalLeftToInvest = totalLeftToInvest.sub(amountToInvest); // Check if reserve is now capped and should be removed from future allocations const newReserveAllocation = expectedHoldingsDistribution.get(reserve).add(amountToInvest); if (reserveCap.eq(ZERO) || (reserveCap.gt(ZERO) && newReserveAllocation.gte(reserveCap))) { currentAllocationSum = currentAllocationSum.sub(reserveWithWeight.targetWeight); } // Update reserve allocation expectedHoldingsDistribution.set(reserve, newReserveAllocation); } } return { targetUnallocatedAmount: unallocatedAllocation.add(totalLeftToInvest), targetReservesAllocation: expectedHoldingsDistribution, }; } //# sourceMappingURL=vaultAllocation.js.map