Skip to content

Commit 6e2f05d

Browse files
committed
Add baseLoanable and computeLoanableForLTV to market borrow simulations
1 parent f3cc9b7 commit 6e2f05d

5 files changed

Lines changed: 691 additions & 539 deletions

File tree

packages/moolah-sdk-core/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# @lista-dao/moolah-sdk-core
22

3+
## 1.0.2
4+
5+
### Patch Changes
6+
7+
- Add baseLoanable and computeLoanableForLTV to market borrow simulations
8+
39
## 1.0.1
410

511
### Patch Changes

packages/moolah-sdk-core/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@lista-dao/moolah-sdk-core",
3-
"version": "1.0.1",
3+
"version": "1.0.2",
44
"type": "module",
55
"main": "./dist/index.js",
66
"module": "./dist/index.js",

packages/moolah-sdk-core/src/__tests__/simulate.test.ts

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,49 @@ describe('Market Simulation', () => {
204204
expect(result.liqPriceRate.gt(Decimal.ZERO)).toBe(true);
205205
});
206206

207+
it('should return baseLoanable not affected by borrowAmount', () => {
208+
const base = simulateMarketBorrow({
209+
supplyAmount: Decimal.parse('1', 18),
210+
borrowAmount: Decimal.ZERO,
211+
userPosition: {
212+
collateral: Decimal.parse('1', 18),
213+
borrowed: Decimal.ZERO,
214+
},
215+
marketState,
216+
});
217+
const withBorrow = simulateMarketBorrow({
218+
supplyAmount: Decimal.parse('1', 18),
219+
borrowAmount: Decimal.parse('500', 18),
220+
userPosition: {
221+
collateral: Decimal.parse('1', 18),
222+
borrowed: Decimal.ZERO,
223+
},
224+
marketState,
225+
});
226+
227+
// baseLoanable should be identical regardless of borrowAmount
228+
expect(base.baseLoanable.toString(18)).toBe(withBorrow.baseLoanable.toString(18));
229+
// loanable should differ (post-borrow remaining)
230+
expect(base.loanable.gt(withBorrow.loanable)).toBe(true);
231+
});
232+
233+
it('should compute loanable for a target LTV via computeLoanableForLTV', () => {
234+
const result = simulateMarketBorrow({
235+
supplyAmount: Decimal.parse('1', 18),
236+
borrowAmount: Decimal.ZERO,
237+
userPosition: {
238+
collateral: Decimal.parse('1', 18),
239+
borrowed: Decimal.ZERO,
240+
},
241+
marketState,
242+
});
243+
244+
// collateral=2, priceRate=2000, targetLTV=0.4
245+
// loanable = 2 * 0.4 * 2000 - 0 = 1600
246+
const loanable = result.computeLoanableForLTV(0.4);
247+
expect(Number(loanable.toString(18))).toBeCloseTo(1600, 0);
248+
});
249+
207250
it('should calculate borrow rate when computeBorrowRate provided', () => {
208251
const result = simulateMarketBorrow({
209252
supplyAmount: Decimal.ZERO,
@@ -437,11 +480,61 @@ describe('Smart Market Simulation', () => {
437480
});
438481

439482
// Collateral should increase by LP amount
483+
expect(result.collateral.toString(18)).toBe('200');
440484
expect(result.borrowed.toString(18)).toBe('50');
441485
expect(result.LTV.gt(Decimal.ZERO)).toBe(true);
442486
expect(result.loanable.gte(Decimal.ZERO)).toBe(true);
443487
});
444488

489+
it('should return baseLoanable not affected by borrowAmount', () => {
490+
const userPosition = {
491+
collateral: Decimal.parse('100', 18),
492+
borrowed: Decimal.ZERO,
493+
lpTokenA: Decimal.parse('50', 18),
494+
lpTokenB: Decimal.parse('50', 18),
495+
};
496+
const base = simulateSmartMarketBorrow({
497+
supplyLpAmount: Decimal.parse('100', 18),
498+
tokenAAmount: Decimal.ZERO,
499+
tokenBAmount: Decimal.ZERO,
500+
borrowAmount: Decimal.ZERO,
501+
userPosition,
502+
marketState: smartMarketState,
503+
});
504+
const withBorrow = simulateSmartMarketBorrow({
505+
supplyLpAmount: Decimal.parse('100', 18),
506+
tokenAAmount: Decimal.ZERO,
507+
tokenBAmount: Decimal.ZERO,
508+
borrowAmount: Decimal.parse('50', 18),
509+
userPosition,
510+
marketState: smartMarketState,
511+
});
512+
513+
expect(base.baseLoanable.toString(18)).toBe(withBorrow.baseLoanable.toString(18));
514+
expect(base.loanable.gt(withBorrow.loanable)).toBe(true);
515+
});
516+
517+
it('should compute loanable for a target LTV via computeLoanableForLTV', () => {
518+
const result = simulateSmartMarketBorrow({
519+
supplyLpAmount: Decimal.parse('100', 18),
520+
tokenAAmount: Decimal.ZERO,
521+
tokenBAmount: Decimal.ZERO,
522+
borrowAmount: Decimal.ZERO,
523+
userPosition: {
524+
collateral: Decimal.parse('100', 18),
525+
borrowed: Decimal.ZERO,
526+
lpTokenA: Decimal.parse('50', 18),
527+
lpTokenB: Decimal.parse('50', 18),
528+
},
529+
marketState: smartMarketState,
530+
});
531+
532+
// collateral=200, priceRate=1, targetLTV=0.4
533+
// loanable = 200 * 0.4 * 1 - 0 = 80
534+
const loanable = result.computeLoanableForLTV(0.4);
535+
expect(Number(loanable.toString(18))).toBeCloseTo(80, 0);
536+
});
537+
445538
it('should calculate borrow rate when provided', () => {
446539
const result = simulateSmartMarketBorrow({
447540
supplyLpAmount: Decimal.ZERO,

0 commit comments

Comments
 (0)