11import type { Address , Chain , PublicClient } from "viem" ;
2- import { createPublicClient , http } from "viem" ;
2+ import { createPublicClient , fallback , http } from "viem" ;
33import { bsc , mainnet } from "viem/chains" ;
44import {
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" ;
1114import 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+
105128export 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