Skip to content

Commit cbb13ba

Browse files
committed
Implement market simulation methods in MoolahSDK for borrowing and repaying positions. Introduce new types for simulation parameters and results, enhance transport configuration handling, and update tests to validate new functionality. This update improves the SDK's capability to simulate market interactions based on user data and market state.
1 parent e992de5 commit cbb13ba

10 files changed

Lines changed: 329 additions & 18 deletions

File tree

packages/moolah-lending-sdk/CHANGELOG.md

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

3+
## 1.0.5
4+
5+
### Patch Changes
6+
7+
- Implement market simulation methods in MoolahSDK for borrowing and repaying positions. Introduce new types for simulation parameters and results, enhance transport configuration handling, and update tests to validate new functionality. This update improves the SDK's capability to simulate market interactions based on user data and market state.
8+
- Updated dependencies
9+
- @lista-dao/moolah-sdk-core@1.0.6
10+
311
## 1.0.4
412

513
### Patch Changes

packages/moolah-lending-sdk/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-lending-sdk",
3-
"version": "1.0.4",
3+
"version": "1.0.5",
44
"type": "module",
55
"main": "./dist/index.js",
66
"module": "./dist/index.js",

packages/moolah-lending-sdk/src/MoolahSDK.ts

Lines changed: 161 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
import type { Address, Chain, PublicClient } from "viem";
2-
import { createPublicClient, http } from "viem";
2+
import { createPublicClient, fallback, http } from "viem";
33
import { bsc, mainnet } from "viem/chains";
44
import {
55
getContractAddress,
66
getContractAddressOptional,
77
getApiChain,
88
LISTA_API_URLS,
9+
Decimal,
10+
simulateMarketBorrow,
11+
simulateMarketRepay,
912
toWriteConfig,
1013
} from "@lista-dao/moolah-sdk-core";
1114
import type {
@@ -32,6 +35,7 @@ import type {
3235
ApiMarketListParams,
3336
NetworkName,
3437
NetworkContracts,
38+
SimulateMarketState,
3539
WriteMarketConfig,
3640
} from "@lista-dao/moolah-sdk-core";
3741

@@ -85,6 +89,12 @@ import type {
8589
BuildSmartRepayParams,
8690
BuildBrokerBorrowParams,
8791
BuildBrokerRepayParams,
92+
MarketRuntimeData,
93+
SimulateBorrowPositionParams,
94+
SimulateBorrowPositionResult,
95+
SimulateRepayPositionParams,
96+
SimulateRepayPositionResult,
97+
SdkTransportConfig,
8898
StepParam,
8999
} from "./types.js";
90100

@@ -102,6 +112,19 @@ const CHAIN_BY_NETWORK: Record<NetworkName, Chain> = {
102112
// sepolia: sepolia,
103113
};
104114

115+
const EMPTY_TRANSPORT_CONFIG: SdkTransportConfig = {};
116+
117+
function toMarketSimulationState(extraInfo: MarketExtraInfo): SimulateMarketState {
118+
return {
119+
totalSupply: extraInfo.totalSupply,
120+
totalBorrow: extraInfo.totalBorrow,
121+
LLTV: extraInfo.LLTV,
122+
priceRate: extraInfo.priceRate,
123+
loanDecimals: extraInfo.loanInfo.decimals,
124+
collateralDecimals: extraInfo.collateralInfo.decimals,
125+
};
126+
}
127+
105128
export class MoolahSDK {
106129
private config: MoolahSDKConfig;
107130
private publicClients = new Map<string, PublicClient>();
@@ -113,6 +136,10 @@ export class MoolahSDK {
113136

114137
const apiBaseUrl = config.apiBaseUrl ?? LISTA_API_URLS.prod;
115138
this.apiClient = new MoolahApiClient({ baseUrl: apiBaseUrl });
139+
140+
for (const [chainId, client] of Object.entries(config.publicClients ?? {})) {
141+
this.publicClients.set(chainId, client);
142+
}
116143
}
117144

118145
private getNetwork(chainId: ChainId): NetworkName {
@@ -124,13 +151,30 @@ export class MoolahSDK {
124151
return network;
125152
}
126153

127-
private getRpcUrl(chainId: ChainId): string {
154+
private getRpcUrls(chainId: ChainId): string[] {
128155
const id = String(chainId);
129-
const rpcUrl = this.config.rpcUrls[id];
130-
if (!rpcUrl) {
156+
const value = this.config.rpcUrls[id];
157+
if (!value) {
158+
throw new Error(`RPC URL not configured for chainId ${chainId}`);
159+
}
160+
161+
const rpcUrls = (Array.isArray(value) ? value : [value]).filter(
162+
(url): url is string => typeof url === "string" && url.trim().length > 0,
163+
);
164+
if (rpcUrls.length === 0) {
131165
throw new Error(`RPC URL not configured for chainId ${chainId}`);
132166
}
133-
return rpcUrl;
167+
168+
return rpcUrls;
169+
}
170+
171+
private getTransportConfig(chainId: ChainId): SdkTransportConfig {
172+
const id = String(chainId);
173+
return {
174+
...EMPTY_TRANSPORT_CONFIG,
175+
...(this.config.transport ?? EMPTY_TRANSPORT_CONFIG),
176+
...(this.config.transportByChainId?.[id] ?? EMPTY_TRANSPORT_CONFIG),
177+
};
134178
}
135179

136180
private getPublicClient(chainId: ChainId): PublicClient {
@@ -139,12 +183,21 @@ export class MoolahSDK {
139183
if (cached) return cached;
140184

141185
const network = this.getNetwork(chainId);
142-
const rpcUrl = this.getRpcUrl(chainId);
143186
const chain = CHAIN_BY_NETWORK[network];
187+
const rpcUrls = this.getRpcUrls(chainId);
188+
const transportConfig = this.getTransportConfig(chainId);
189+
190+
const transports = rpcUrls.map((rpcUrl) =>
191+
http(rpcUrl, {
192+
timeout: transportConfig.timeout,
193+
retryCount: transportConfig.retryCount,
194+
retryDelay: transportConfig.retryDelay,
195+
}),
196+
);
144197

145198
const client = createPublicClient({
146199
chain,
147-
transport: http(rpcUrl),
200+
transport: transports.length === 1 ? transports[0] : fallback(transports),
148201
});
149202

150203
this.publicClients.set(id, client);
@@ -220,6 +273,25 @@ export class MoolahSDK {
220273
return toWriteConfig(extraInfo);
221274
}
222275

276+
async getMarketRuntimeData(
277+
chainId: ChainId,
278+
marketId: Address,
279+
walletAddress: Address,
280+
): Promise<MarketRuntimeData> {
281+
const marketExtraInfo = await this.getMarketExtraInfo(chainId, marketId);
282+
return {
283+
marketExtraInfo,
284+
marketInfo: toWriteConfig(marketExtraInfo),
285+
userData: await this.getMarketUserData(
286+
chainId,
287+
marketId,
288+
walletAddress,
289+
undefined,
290+
marketExtraInfo,
291+
),
292+
};
293+
}
294+
223295
async getVaultInfo(
224296
chainId: ChainId,
225297
vaultAddress: Address,
@@ -315,7 +387,7 @@ export class MoolahSDK {
315387
chainId: ChainId,
316388
marketId: Address,
317389
): Promise<MarketInfo> {
318-
return this.apiClient.getMarketInfo(marketId);
390+
return this.apiClient.getMarketInfo(marketId, this.getApiChain(chainId));
319391
}
320392

321393
async getVaultList(params: ApiVaultListParams): Promise<ApiVaultList> {
@@ -357,6 +429,87 @@ export class MoolahSDK {
357429
return this.apiClient.getMarketVaultDetails(marketId, params);
358430
}
359431

432+
// ===== Simulate Methods (Market) =====
433+
434+
async simulateBorrowPosition(
435+
params: SimulateBorrowPositionParams,
436+
): Promise<SimulateBorrowPositionResult> {
437+
const marketExtraInfo =
438+
params.marketExtraInfo ??
439+
(await this.getMarketExtraInfo(params.chainId, params.marketId));
440+
const userData =
441+
params.userData ??
442+
(await this.getMarketUserData(
443+
params.chainId,
444+
params.marketId,
445+
params.walletAddress,
446+
undefined,
447+
marketExtraInfo,
448+
));
449+
450+
const simulation = simulateMarketBorrow({
451+
supplyAmount: new Decimal(
452+
params.supplyAssets ?? 0n,
453+
marketExtraInfo.collateralInfo.decimals,
454+
),
455+
borrowAmount: new Decimal(
456+
params.borrowAssets ?? 0n,
457+
marketExtraInfo.loanInfo.decimals,
458+
),
459+
userPosition: {
460+
collateral: userData.collateral,
461+
borrowed: userData.borrowed,
462+
},
463+
marketState: toMarketSimulationState(marketExtraInfo),
464+
});
465+
466+
return {
467+
marketExtraInfo,
468+
userData,
469+
simulation,
470+
};
471+
}
472+
473+
async simulateRepayPosition(
474+
params: SimulateRepayPositionParams,
475+
): Promise<SimulateRepayPositionResult> {
476+
const marketExtraInfo =
477+
params.marketExtraInfo ??
478+
(await this.getMarketExtraInfo(params.chainId, params.marketId));
479+
const userData =
480+
params.userData ??
481+
(await this.getMarketUserData(
482+
params.chainId,
483+
params.marketId,
484+
params.walletAddress,
485+
undefined,
486+
marketExtraInfo,
487+
));
488+
489+
const simulation = simulateMarketRepay({
490+
repayAmount: new Decimal(
491+
params.repayAssets ?? 0n,
492+
marketExtraInfo.loanInfo.decimals,
493+
),
494+
withdrawAmount: new Decimal(
495+
params.withdrawAssets ?? 0n,
496+
marketExtraInfo.collateralInfo.decimals,
497+
),
498+
isRepayAll: Boolean(params.repayAll),
499+
userPosition: {
500+
collateral: userData.collateral,
501+
borrowed: userData.borrowed,
502+
},
503+
marketState: toMarketSimulationState(marketExtraInfo),
504+
});
505+
506+
return {
507+
marketExtraInfo,
508+
userData,
509+
simulation,
510+
};
511+
}
512+
360513
// ===== Build Methods (Market) =====
361514

362515
async buildSupplyParams(params: BuildSupplyParams): Promise<StepParam[]> {

0 commit comments

Comments
 (0)