diff --git a/.changeset/breezy-dodos-explode.md b/.changeset/breezy-dodos-explode.md new file mode 100644 index 0000000..5f54765 --- /dev/null +++ b/.changeset/breezy-dodos-explode.md @@ -0,0 +1,5 @@ +--- +"@shadeprotocol/shadejs": patch +--- + +Money market interface, pending tests and docs diff --git a/src/contracts/definitions/index.ts b/src/contracts/definitions/index.ts index c2f88d0..628d1c7 100644 --- a/src/contracts/definitions/index.ts +++ b/src/contracts/definitions/index.ts @@ -7,3 +7,4 @@ export * from './derivativeScrt'; export * from './shadeStaking'; export * from './lend'; export * from './silkBasket'; +export * from './moneyMarket'; diff --git a/src/contracts/definitions/moneyMarket.ts b/src/contracts/definitions/moneyMarket.ts new file mode 100644 index 0000000..002d841 --- /dev/null +++ b/src/contracts/definitions/moneyMarket.ts @@ -0,0 +1,191 @@ +import { AccountPermit } from '~/types/permit'; +import { Pagination } from '~/types/contracts/moneyMarket/model'; +import { generatePadding } from '~/index'; +import { snip20 } from './snip20'; + +/** + * Query the contract status info + * NOT FOR PRODUCTION USE, CONTRACT IS IN DEVELOPMENT ON TESTNET ONLY + */ +const msgQueryMoneyMarketConfig = () => ({ config: {} }); + +/** + * Query the collateral state and config info + * NOT FOR PRODUCTION USE, CONTRACT IS IN DEVELOPMENT ON TESTNET ONLY + */ +const msgQueryMoneyMarketCollaterals = ( + pagination?: Pagination, +) => ({ + get_collateral: { + pagination, + }, +}); + +/** + * Query the markets' state and config info + * NOT FOR PRODUCTION USE, CONTRACT IS IN DEVELOPMENT ON TESTNET ONLY + */ +const msgQueryMoneyMarketMarkets = ( + pagination?: Pagination, +) => ({ + get_markets: { + pagination, + }, +}); + +/** + * Query a user's collateral and debt positions + * NOT FOR PRODUCTION USE, CONTRACT IS IN DEVELOPMENT ON TESTNET ONLY + */ +const msgQueryMoneyMarketUserPosition = ( + address: string, + permit: AccountPermit, +) => ({ + user_position: { + address, + authentication: { + permit: { + query_permit: permit, + }, + }, + }, +}); + +/** + * message to borrow a debt token against deposited collateral + * NOT FOR PRODUCTION USE, CONTRACT IS IN DEVELOPMENT ON TESTNET ONLY + */ +function msgMoneyMarketBorrow({ + borrowAmount, + debtTokenAddress, +}: { + borrowAmount: string, + debtTokenAddress: string, +}) { + return { + borrow: { + token: debtTokenAddress, + amount: borrowAmount, + }, + }; +} + +/** + * message to withdraw collateral against an existing user position + * NOT FOR PRODUCTION USE, CONTRACT IS IN DEVELOPMENT ON TESTNET ONLY + */ +function msgMoneyMarketWithdrawCollateral({ + withdrawAmount, + collateralTokenAddress, +}: { + withdrawAmount: string, + collateralTokenAddress: string, +}) { + return { + deposit_collateral: { + token: collateralTokenAddress, + amount: withdrawAmount, + }, + }; +} + +/** + * message to deposit collateral to borrow against + * NOT FOR PRODUCTION USE, CONTRACT IS IN DEVELOPMENT ON TESTNET ONLY + */ +function msgMoneyMarketDepositCollateral({ + moneyMarketContractAddress, + moneyMarketCodeHash, + depositAmount, +}: { + moneyMarketContractAddress: string, + moneyMarketCodeHash?: string, + depositAmount: string, +}) { + return snip20.messages.send({ + recipient: moneyMarketContractAddress, + recipientCodeHash: moneyMarketCodeHash, + amount: depositAmount, + handleMsg: { deposit_collateral: {} }, + padding: generatePadding(), + }).msg; +} + +/** + * message to supply tokens to be lent out + * NOT FOR PRODUCTION USE, CONTRACT IS IN DEVELOPMENT ON TESTNET ONLY + */ +function msgMoneyMarketSupply({ + moneyMarketContractAddress, + moneyMarketCodeHash, + supplyAmount, +}: { + moneyMarketContractAddress: string, + moneyMarketCodeHash?: string, + supplyAmount: string, +}) { + return snip20.messages.send({ + recipient: moneyMarketContractAddress, + recipientCodeHash: moneyMarketCodeHash, + amount: supplyAmount, + handleMsg: { supply: {} }, + padding: generatePadding(), + }).msg; +} + +/** + * message to withdraw supply by sending an ltoken amount + * NOT FOR PRODUCTION USE, CONTRACT IS IN DEVELOPMENT ON TESTNET ONLY + */ +function msgMoneyMarketWithdrawSupply({ + moneyMarketContractAddress, + moneyMarketCodeHash, + withdrawAmount, +}: { + moneyMarketContractAddress: string, + moneyMarketCodeHash?: string, + withdrawAmount: string, +}) { + return snip20.messages.send({ + recipient: moneyMarketContractAddress, + recipientCodeHash: moneyMarketCodeHash, + amount: withdrawAmount, + handleMsg: { withdraw_supply: {} }, + padding: generatePadding(), + }).msg; +} + +/** + * message to repay a loan that has been taken out + * NOT FOR PRODUCTION USE, CONTRACT IS IN DEVELOPMENT ON TESTNET ONLY + */ +function msgMoneyMarketRepay({ + moneyMarketContractAddress, + moneyMarketCodeHash, + repayAmount, +}: { + moneyMarketContractAddress: string, + moneyMarketCodeHash?: string, + repayAmount: string, +}) { + return snip20.messages.send({ + recipient: moneyMarketContractAddress, + recipientCodeHash: moneyMarketCodeHash, + amount: repayAmount, + handleMsg: { repay: {} }, + padding: generatePadding(), + }).msg; +} + +export { + msgQueryMoneyMarketConfig, + msgQueryMoneyMarketCollaterals, + msgQueryMoneyMarketMarkets, + msgQueryMoneyMarketUserPosition, + msgMoneyMarketBorrow, + msgMoneyMarketWithdrawCollateral, + msgMoneyMarketDepositCollateral, + msgMoneyMarketSupply, + msgMoneyMarketWithdrawSupply, + msgMoneyMarketRepay, +}; diff --git a/src/contracts/services/index.ts b/src/contracts/services/index.ts index 0bb38a5..b1a776e 100644 --- a/src/contracts/services/index.ts +++ b/src/contracts/services/index.ts @@ -7,3 +7,4 @@ export * from './derivativeShd'; export * from './shadeStaking'; export * from './lend'; export * from './silkBasket'; +export * from './moneyMarket'; diff --git a/src/contracts/services/moneyMarket.ts b/src/contracts/services/moneyMarket.ts new file mode 100644 index 0000000..36010f8 --- /dev/null +++ b/src/contracts/services/moneyMarket.ts @@ -0,0 +1,583 @@ +import { getActiveQueryClient$ } from '~/client'; +import { + switchMap, + first, + map, + lastValueFrom, +} from 'rxjs'; +import { sendSecretClientContractQuery$ } from '~/client/services/clientServices'; +import { ConfigResponse, GetCollateralResponse, GetMarketsResponse } from '~/types/contracts/moneyMarket/response'; +import { + BatchMoneyMarketConfigs, + BatchMoneyMarketGetCollaterals, + BatchMoneyMarketGetMarkets, + ContractAndPagination, + Pagination, ParsedConfigResponse, ParsedGetCollateralResponse, ParsedGetMarketsResponse, +} from '~/types/contracts/moneyMarket/model'; +import { Contract } from '~/types/contracts/shared/index'; +import { + BatchQueryParams, BatchQueryParsedResponse, +} from '~/types/contracts/batchQuery/model'; +import { MinBlockHeightValidationOptions } from '~/types'; +import { batchQuery$ } from './batchQuery'; +import { msgQueryMoneyMarketCollaterals, msgQueryMoneyMarketConfig, msgQueryMoneyMarketMarkets } from '../definitions/moneyMarket'; + +/** +* Parses the get markets query into a cleaner data model + * NOT FOR PRODUCTION USE, CONTRACT IS IN DEVELOPMENT ON TESTNET ONLY +*/ +const parseMoneyMarketGetMarkets = ( + response: GetMarketsResponse, +): ParsedGetMarketsResponse => ({ + page: response.paginated_response.page, + pageSize: response.paginated_response.page_size, + totalPages: response.paginated_response.total_pages, + totalItems: response.paginated_response.total_items, + data: response.paginated_response.data.reduce((prev, cur) => ({ + ...prev, + [cur.market.market_token.address]: { + marketToken: { + contractAddress: cur.market.market_token.address, + codeHash: cur.market.market_token.code_hash, + }, + lToken: { + contractAddress: cur.market.l_token.address, + codeHash: cur.market.l_token.address, + }, + decimals: cur.market.decimals, + oracleKey: cur.market.oracle_key, + interest: { + base: cur.market.interest.inner.interest.linear?.base + ?? cur.market.interest.inner.interest.piecewise_linear!.base, + slope1: cur.market.interest.inner.interest.linear?.slope + ?? cur.market.interest.inner.interest.piecewise_linear!.slope1, + slope2: cur.market.interest.inner.interest.piecewise_linear?.slope2, + optimalUtilisation: + cur.market.interest.inner.interest.piecewise_linear?.optimal_utilisation, + }, + loanableAmount: cur.market.loanable, + lentAmount: cur.market.lent_amount, + lifetimeInterestPaid: cur.market.lifetime_interest_paid, + lifetimeInterestOwed: cur.market.lifetime_interest_owed, + interestPerUtoken: cur.market.interest_per_utoken, + lastInterestAccrued: new Date(cur.market.last_interest_accrued), + maxSupplyAmount: cur.market.max_supply, + flashLoanInterest: cur.market.flash_loan_interest, + supplyEnabled: cur.market.status.market_status.supply_enabled, + borrowEnabled: cur.market.status.market_status.borrow_enabled, + repayEnabled: cur.market.status.market_status.repay_enabled, + liquidationEnabled: cur.market.status.market_status.liquidation_enabled, + interestAccrualEnabled: cur.market.status.market_status.interest_accrual_enabled, + }, + }), {}), +}); + +/** +* Parses the config query into a cleaner data model + * NOT FOR PRODUCTION USE, CONTRACT IS IN DEVELOPMENT ON TESTNET ONLY +*/ +const parseMoneyMarketConfig = ( + response: ConfigResponse, +):ParsedConfigResponse => ({ + adminAuth: { + contractAddress: response.config.admin_auth.address, + codeHash: response.config.admin_auth.code_hash, + }, + queryAuth: { + contractAddress: response.config.query_auth.address, + codeHash: response.config.query_auth.code_hash, + }, + oracle: { + contractAddress: response.config.oracle.address, + codeHash: response.config.query_auth.code_hash, + }, + feeCollector: response.config.fee_collector, + lTokenId: response.config.l_token_id, + lTokenCodeHash: response.config.l_token_code_hash, + lTokenBlockchainAdmin: response.config.l_token_blockchain_admin, + supplyEnabled: response.config.status.global_status.supply_enabled, + borrowEnabled: response.config.status.global_status.borrow_enabled, + repayEnabled: response.config.status.global_status.repay_enabled, + liquidationEnabled: response.config.status.global_status.liquidation_enabled, + interestAccrualEnabled: response.config.status.global_status.interest_accrual_enabled, + collateralDepositEnabled: response.config.status.global_status.collateral_deposit_enabled, +}); + +/** +* Parses the get collateral query into a cleaner data model + * NOT FOR PRODUCTION USE, CONTRACT IS IN DEVELOPMENT ON TESTNET ONLY +*/ +const parseMoneyMarketGetCollateral = ( + response: GetCollateralResponse, +): ParsedGetCollateralResponse => ({ + page: response.paginated_response.page, + pageSize: response.paginated_response.page_size, + totalPages: response.paginated_response.total_pages, + totalItems: response.paginated_response.total_items, + data: response.paginated_response.data.reduce((prev, cur) => ({ + ...prev, + [cur.collateral_state.token.address]: { + token: { + contractAddress: cur.collateral_state.token.address, + codeHash: cur.collateral_state.token.code_hash, + }, + collateralAmount: cur.collateral_state.amount, + decimals: cur.collateral_state.decimals, + maxInitialLtv: cur.collateral_state.max_initial_ltv, + liquidationThreshold: cur.collateral_state.liquidation_threshold, + liquidationDiscount: cur.collateral_state.liquidation_discount, + oracleKey: cur.collateral_state.oracle_key, + depositEnabled: cur.collateral_state.status.collateral_status.deposit_enabled, + liquidationEnabled: cur.collateral_state.status.collateral_status.liquidation_enabled, + }, + }), {}), +}); + +/** + * query the money market config + * NOT FOR PRODUCTION USE, CONTRACT IS IN DEVELOPMENT ON TESTNET ONLY + */ +const queryMoneyMarketConfig$ = ({ + contractAddress, + codeHash, + lcdEndpoint, + chainId, +}: { + contractAddress: string, + codeHash?: string, + lcdEndpoint?: string, + chainId?: string, +}) => getActiveQueryClient$(lcdEndpoint, chainId).pipe( + switchMap(({ client }) => sendSecretClientContractQuery$({ + queryMsg: msgQueryMoneyMarketConfig(), + client, + contractAddress, + codeHash, + })), + map((response) => parseMoneyMarketConfig(response as ConfigResponse)), + first(), +); + +/** + * query the money market collateral + * NOT FOR PRODUCTION USE, CONTRACT IS IN DEVELOPMENT ON TESTNET ONLY + */ +const queryMoneyMarketGetCollateral$ = ({ + contractAddress, + codeHash, + lcdEndpoint, + chainId, + pagination, +}: { + contractAddress: string, + codeHash?: string, + lcdEndpoint?: string, + chainId?: string, + pagination?: Pagination, +}) => getActiveQueryClient$(lcdEndpoint, chainId).pipe( + switchMap(({ client }) => sendSecretClientContractQuery$({ + queryMsg: msgQueryMoneyMarketCollaterals(pagination), + client, + contractAddress, + codeHash, + })), + map((response) => parseMoneyMarketGetCollateral(response as GetCollateralResponse)), + first(), +); + +/** + * query the money market markets + * NOT FOR PRODUCTION USE, CONTRACT IS IN DEVELOPMENT ON TESTNET ONLY + */ +const queryMoneyMarketGetMarkets$ = ({ + contractAddress, + codeHash, + lcdEndpoint, + chainId, + pagination, +}: { + contractAddress: string, + codeHash?: string, + lcdEndpoint?: string, + chainId?: string, + pagination?: Pagination, +}) => getActiveQueryClient$(lcdEndpoint, chainId).pipe( + switchMap(({ client }) => sendSecretClientContractQuery$({ + queryMsg: msgQueryMoneyMarketMarkets(pagination), + client, + contractAddress, + codeHash, + })), + map((response) => parseMoneyMarketGetMarkets(response as GetMarketsResponse)), + first(), +); + +/** + * query the money market config + * NOT FOR PRODUCTION USE, CONTRACT IS IN DEVELOPMENT ON TESTNET ONLY + */ +async function queryMoneyMarketConfig({ + contractAddress, + codeHash, + lcdEndpoint, + chainId, +}: { + contractAddress: string, + codeHash?: string, + lcdEndpoint?: string, + chainId?: string, +}) { + return lastValueFrom(queryMoneyMarketConfig$({ + contractAddress, + codeHash, + lcdEndpoint, + chainId, + })); +} + +/** + * query the money market get markets query + * NOT FOR PRODUCTION USE, CONTRACT IS IN DEVELOPMENT ON TESTNET ONLY + */ +async function queryMoneyMarketGetMarkets({ + contractAddress, + codeHash, + lcdEndpoint, + chainId, + pageSize, + page, +}: { + contractAddress: string, + codeHash?: string, + lcdEndpoint?: string, + chainId?: string, + pageSize?: number, + page?: number, +}) { + return lastValueFrom(queryMoneyMarketGetMarkets$({ + contractAddress, + codeHash, + lcdEndpoint, + chainId, + pagination: pageSize !== undefined && page !== undefined ? { + page_size: pageSize, + page, + } : undefined, + })); +} + +/** + * query the money market get collateral query + * NOT FOR PRODUCTION USE, CONTRACT IS IN DEVELOPMENT ON TESTNET ONLY + */ +async function queryMoneyMarketGetCollateral({ + contractAddress, + codeHash, + lcdEndpoint, + chainId, + pageSize, + page, +}: { + contractAddress: string, + codeHash?: string, + lcdEndpoint?: string, + chainId?: string, + pageSize?: number, + page?: number, +}) { + return lastValueFrom(queryMoneyMarketGetCollateral$({ + contractAddress, + codeHash, + lcdEndpoint, + chainId, + pagination: pageSize !== undefined && page !== undefined ? { + page_size: pageSize, + page, + } : undefined, + })); +} + +/** + * parses the config reponse from a batch query of + * multiple money market contracts + * NOT FOR PRODUCTION USE, CONTRACT IS IN DEVELOPMENT ON TESTNET ONLY + */ +const parseBatchQueryMoneyMarketConfig = ( + response: BatchQueryParsedResponse, +): BatchMoneyMarketConfigs => response.map((item) => ({ + moneyMarketContractAddress: item.id as string, + config: parseMoneyMarketConfig(item.response), + blockHeight: item.blockHeight, +})); + +/** + * query the config for money market contracts at one time + * NOT FOR PRODUCTION USE, CONTRACT IS IN DEVELOPMENT ON TESTNET ONLY + */ +function batchQueryMoneyMarketConfig$({ + queryRouterContractAddress, + queryRouterCodeHash, + lcdEndpoint, + chainId, + moneyMarketContracts, + batchSize, + minBlockHeightValidationOptions, + blockHeight, +}:{ + queryRouterContractAddress: string, + queryRouterCodeHash?: string, + lcdEndpoint?: string, + chainId?: string, + moneyMarketContracts: Contract[], + batchSize?: number, + minBlockHeightValidationOptions?: MinBlockHeightValidationOptions, + blockHeight?: number, +}) { + const queries:BatchQueryParams[] = moneyMarketContracts.map((contract) => ({ + id: contract.address, + contract: { + address: contract.address, + codeHash: contract.codeHash, + }, + queryMsg: msgQueryMoneyMarketConfig(), + })); + return batchQuery$({ + contractAddress: queryRouterContractAddress, + codeHash: queryRouterCodeHash, + lcdEndpoint, + chainId, + queries, + batchSize, + minBlockHeightValidationOptions, + blockHeight, + }).pipe( + map(parseBatchQueryMoneyMarketConfig), + first(), + ); +} + +/** + * query the config for money market contracts at one time + * NOT FOR PRODUCTION USE, CONTRACT IS IN DEVELOPMENT ON TESTNET ONLY + */ +async function batchQueryMoneyMarketConfig({ + queryRouterContractAddress, + queryRouterCodeHash, + lcdEndpoint, + chainId, + moneyMarketContracts, + minBlockHeightValidationOptions, +}:{ + queryRouterContractAddress: string, + queryRouterCodeHash?: string, + lcdEndpoint?: string, + chainId?: string, + moneyMarketContracts: Contract[] + minBlockHeightValidationOptions?: MinBlockHeightValidationOptions, +}) { + return lastValueFrom(batchQueryMoneyMarketConfig$({ + queryRouterContractAddress, + queryRouterCodeHash, + lcdEndpoint, + chainId, + moneyMarketContracts, + minBlockHeightValidationOptions, + })); +} + +/** + * parses the markets response from a batch query of + * multiple money market contracts + * NOT FOR PRODUCTION USE, CONTRACT IS IN DEVELOPMENT ON TESTNET ONLY + */ +const parseBatchQueryMoneyMarketGetMarkets = ( + response: BatchQueryParsedResponse, +): BatchMoneyMarketGetMarkets => response.map((item) => ({ + moneyMarketContractAddress: item.id as string, + config: parseMoneyMarketGetMarkets(item.response), + blockHeight: item.blockHeight, +})); + +/** + * query the markets for money market contracts at one time + * NOT FOR PRODUCTION USE, CONTRACT IS IN DEVELOPMENT ON TESTNET ONLY + */ +function batchQueryMoneyMarketGetMarkets$({ + queryRouterContractAddress, + queryRouterCodeHash, + lcdEndpoint, + chainId, + moneyMarketContracts, + batchSize, + minBlockHeightValidationOptions, + blockHeight, +}:{ + queryRouterContractAddress: string, + queryRouterCodeHash?: string, + lcdEndpoint?: string, + chainId?: string, + moneyMarketContracts: ContractAndPagination[], + batchSize?: number, + minBlockHeightValidationOptions?: MinBlockHeightValidationOptions, + blockHeight?: number, +}) { + const queries:BatchQueryParams[] = moneyMarketContracts.map((contract) => ({ + id: contract.address, + contract: { + address: contract.address, + codeHash: contract.codeHash, + }, + queryMsg: msgQueryMoneyMarketMarkets( + contract.pageSize !== undefined && contract.page !== undefined + ? { + page_size: contract.pageSize, + page: contract.page, + } : undefined, + ), + })); + return batchQuery$({ + contractAddress: queryRouterContractAddress, + codeHash: queryRouterCodeHash, + lcdEndpoint, + chainId, + queries, + batchSize, + minBlockHeightValidationOptions, + blockHeight, + }).pipe( + map(parseBatchQueryMoneyMarketGetMarkets), + first(), + ); +} + +/** + * query the markets for money market contracts at one time + * NOT FOR PRODUCTION USE, CONTRACT IS IN DEVELOPMENT ON TESTNET ONLY + */ +async function batchQueryMoneyMarketGetMarkets({ + queryRouterContractAddress, + queryRouterCodeHash, + lcdEndpoint, + chainId, + moneyMarketContracts, + minBlockHeightValidationOptions, +}:{ + queryRouterContractAddress: string, + queryRouterCodeHash?: string, + lcdEndpoint?: string, + chainId?: string, + moneyMarketContracts: ContractAndPagination[], + minBlockHeightValidationOptions?: MinBlockHeightValidationOptions, +}) { + return lastValueFrom(batchQueryMoneyMarketGetMarkets$({ + queryRouterContractAddress, + queryRouterCodeHash, + lcdEndpoint, + chainId, + moneyMarketContracts, + minBlockHeightValidationOptions, + })); +} + +/** + * parses the collateral response from a batch query of + * multiple money market contracts + * NOT FOR PRODUCTION USE, CONTRACT IS IN DEVELOPMENT ON TESTNET ONLY + */ +const parseBatchQueryMoneyMarketGetCollateral = ( + response: BatchQueryParsedResponse, +): BatchMoneyMarketGetCollaterals => response.map((item) => ({ + moneyMarketContractAddress: item.id as string, + config: parseMoneyMarketGetCollateral(item.response), + blockHeight: item.blockHeight, +})); + +/** + * query the collaterals for money market contracts at one time + * NOT FOR PRODUCTION USE, CONTRACT IS IN DEVELOPMENT ON TESTNET ONLY + */ +function batchQueryMoneyMarketGetCollateral$({ + queryRouterContractAddress, + queryRouterCodeHash, + lcdEndpoint, + chainId, + moneyMarketContracts, + batchSize, + minBlockHeightValidationOptions, + blockHeight, +}:{ + queryRouterContractAddress: string, + queryRouterCodeHash?: string, + lcdEndpoint?: string, + chainId?: string, + moneyMarketContracts: ContractAndPagination[], + batchSize?: number, + minBlockHeightValidationOptions?: MinBlockHeightValidationOptions, + blockHeight?: number, +}) { + const queries:BatchQueryParams[] = moneyMarketContracts.map((contract) => ({ + id: contract.address, + contract: { + address: contract.address, + codeHash: contract.codeHash, + }, + queryMsg: msgQueryMoneyMarketCollaterals( + contract.pageSize !== undefined && contract.page !== undefined + ? { + page_size: contract.pageSize, + page: contract.page, + } : undefined, + ), + })); + return batchQuery$({ + contractAddress: queryRouterContractAddress, + codeHash: queryRouterCodeHash, + lcdEndpoint, + chainId, + queries, + batchSize, + minBlockHeightValidationOptions, + blockHeight, + }).pipe( + map(parseBatchQueryMoneyMarketGetCollateral), + first(), + ); +} + +/** + * query the collaterals for money market contracts at one time + * NOT FOR PRODUCTION USE, CONTRACT IS IN DEVELOPMENT ON TESTNET ONLY + */ +async function batchQueryMoneyMarketGetCollateral({ + queryRouterContractAddress, + queryRouterCodeHash, + lcdEndpoint, + chainId, + moneyMarketContracts, + minBlockHeightValidationOptions, +}:{ + queryRouterContractAddress: string, + queryRouterCodeHash?: string, + lcdEndpoint?: string, + chainId?: string, + moneyMarketContracts: ContractAndPagination[], + minBlockHeightValidationOptions?: MinBlockHeightValidationOptions, +}) { + return lastValueFrom(batchQueryMoneyMarketGetCollateral$({ + queryRouterContractAddress, + queryRouterCodeHash, + lcdEndpoint, + chainId, + moneyMarketContracts, + minBlockHeightValidationOptions, + })); +} + +export { + queryMoneyMarketConfig, + queryMoneyMarketGetMarkets, + queryMoneyMarketGetCollateral, + batchQueryMoneyMarketConfig, + batchQueryMoneyMarketGetMarkets, + batchQueryMoneyMarketGetCollateral, +}; diff --git a/src/types/contracts/index.ts b/src/types/contracts/index.ts index 96a963d..08bac19 100644 --- a/src/types/contracts/index.ts +++ b/src/types/contracts/index.ts @@ -8,3 +8,4 @@ export * from './derivativeShd'; export * from './shadeStaking'; export * from './lend'; export * from './silkBasket'; +export * from './moneyMarket'; diff --git a/src/types/contracts/moneyMarket/index.ts b/src/types/contracts/moneyMarket/index.ts new file mode 100644 index 0000000..ed9aa71 --- /dev/null +++ b/src/types/contracts/moneyMarket/index.ts @@ -0,0 +1,2 @@ +export * from './model'; +export * from './response'; diff --git a/src/types/contracts/moneyMarket/model.ts b/src/types/contracts/moneyMarket/model.ts new file mode 100644 index 0000000..18f6c5c --- /dev/null +++ b/src/types/contracts/moneyMarket/model.ts @@ -0,0 +1,165 @@ +type Pagination = { + page: number, + page_size: number, +} + +type ContractAndPagination = { + address: string, + codeHash: string, + page?: number, + pageSize?: number, +} + +type ParsedPagination = { + page: number, + pageSize: number, + totalPages: number, + totalItems: number, + data: T, +} + +type ParsedConfigResponse = { + adminAuth: { + contractAddress: string + codeHash: string, + }, + queryAuth: { + contractAddress: string, + codeHash: string, + }, + oracle: { + contractAddress: string, + codeHash: string, + }, + feeCollector: string, + lTokenId: number, + lTokenCodeHash: string, + lTokenBlockchainAdmin: string, + supplyEnabled: boolean, + borrowEnabled: boolean, + repayEnabled: boolean, + liquidationEnabled: boolean, + interestAccrualEnabled: boolean, + collateralDepositEnabled: boolean, +} + +type BatchMoneyMarketConfig = { + moneyMarketContractAddress: string, + config: ParsedConfigResponse, + blockHeight: number, +} + +type BatchMoneyMarketConfigs = BatchMoneyMarketConfig[]; + +type ParsedMarketResponse = { + marketToken: { + contractAddress: string, + codeHash: string, + }, + lToken: { + contractAddress: string, + codeHash: string, + }, + decimals: number, + oracleKey: string, + interest: { + base: string, + slope1: string, + slope2?: string, + optimalUtilisation?: string, + }, + loanableAmount: string, + lentAmount: string, + lifetimeInterestPaid: string, + lifetimeInterestOwed: string, + interestPerUtoken: string, + lastInterestAccrued: Date, + maxSupplyAmount: string, + flashLoanInterest: string, + supplyEnabled: boolean, + borrowEnabled: boolean, + repayEnabled: boolean, + liquidationEnabled: boolean, + interestAccrualEnabled: boolean, +} + +type ParsedGetMarketsResponse = ParsedPagination>; + +type BatchMoneyMarketGetMarket = { + moneyMarketContractAddress: string, + config: ParsedGetMarketsResponse, + blockHeight: number, +} + +type BatchMoneyMarketGetMarkets = BatchMoneyMarketGetMarket[]; + +type ParsedCollateralReponse = { + token: { + contractAddress: string, + codeHash: string, + }, + collateralAmount: string, + decimals: number, + maxInitialLtv: string, + liquidationThreshold: string, + liquidationDiscount: string, + oracleKey: string, + depositEnabled: boolean, + liquidationEnabled: boolean, +} + +type ParsedGetCollateralResponse = ParsedPagination>; + +type BatchMoneyMarketGetCollateral = { + moneyMarketContractAddress: string, + config: ParsedGetCollateralResponse, + blockHeight: number, +} + +type BatchMoneyMarketGetCollaterals = BatchMoneyMarketGetCollateral[]; + +type ParsedCalculatedUserCollateralReponse = { + [token: string]: { + token: string, + amount: string, + price: string, + value: string, + } +} + +type ParsedCalculatedUserDebtResponse = { + [token: string]: { + token: string, + price: string, + principal: string, + principalValue: string, + interestAccrued: string, + interestAccruedValue: string, + } +} + +type ParsedUserPositionResponse = { + id: string, + collateral: ParsedCalculatedUserCollateralReponse, + debt: ParsedCalculatedUserDebtResponse, + totalCollateralValue: string, + totalPrincipalValue: string, + totalInterestAccruedValue: string, + loanMaxPoint: string, + loanLiquidationPoint: string, +} + +export type { + Pagination, + ContractAndPagination, + ParsedPagination, + ParsedConfigResponse, + BatchMoneyMarketConfigs, + ParsedMarketResponse, + ParsedGetMarketsResponse, + ParsedCollateralReponse, + ParsedGetCollateralResponse, + ParsedUserPositionResponse, + BatchMoneyMarketGetMarkets, + BatchMoneyMarketGetCollaterals, +}; diff --git a/src/types/contracts/moneyMarket/response.ts b/src/types/contracts/moneyMarket/response.ts new file mode 100644 index 0000000..8eec99c --- /dev/null +++ b/src/types/contracts/moneyMarket/response.ts @@ -0,0 +1,153 @@ +type ConfigResponse = { + config: { + admin_auth: { + address: string, + code_hash: string, + } + query_auth: { + address: string, + code_hash: string, + } + oracle: { + address: string, + code_hash: string, + } + fee_collector: string, + l_token_id: number, + l_token_code_hash: string, + l_token_blockchain_admin: string, + status: { + global_status: { + supply_enabled: boolean, + borrow_enabled: boolean, + repay_enabled: boolean, + liquidation_enabled: boolean, + interest_accrual_enabled: boolean, + collateral_deposit_enabled: boolean, + } + } + } +} + +type PaginatedResponse = { + paginated_response: { + page: number, + page_size: number, + total_pages: number, + total_items: number, + data: T[] + } +} + +type MarketReponse = { + market: { + market_token: { + address: string, + code_hash: string, + }, + l_token: { + address: string, + code_hash: string, + }, + decimals: number, + oracle_key: string, + interest: { + inner: { + interest: { + linear?: { + base: string, + slope: string, + }, + piecewise_linear?: { + base: string, + slope1: string, + slope2: string, + optimal_utilisation: string, + } + } + } + } + loanable: string, + lent_amount: string, + lifetime_interest_paid: string, + lifetime_interest_owed: string, + interest_per_utoken: string, + last_interest_accrued: number, + max_supply: string, + flash_loan_interest: string, + status: { + market_status: { + supply_enabled: boolean, + borrow_enabled: boolean, + repay_enabled: boolean, + liquidation_enabled: boolean, + interest_accrual_enabled: boolean, + } + } + } +} + +type GetMarketsResponse = PaginatedResponse; + +type CollateralReponse = { + collateral_state: { + token: { + address: string, + code_hash: string, + }, + amount: string, + decimals: number, + max_initial_ltv: string, + liquidation_threshold: string, + liquidation_discount: string, + oracle_key: string, + status: { + collateral_status: { + deposit_enabled: boolean, + liquidation_enabled: boolean, + } + } + } +} + +type GetCollateralResponse = PaginatedResponse; + +type CalculatedUserCollateralReponse = { + calculated_user_collateral: { + token: string, + amount: string, + price: string, + value: string, + } +} + +type CalculatedUserDebtResponse = { + calculated_user_debt: { + token: string, + price: string, + principal: string, + principal_value: string, + interest_accrued: string, + interest_accrued_value: string, + } +} + +type UserPositionResponse = { + calcualted_user_position: { + id: string, + collateral: CalculatedUserCollateralReponse[], + debt: CalculatedUserDebtResponse[], + total_collateral_value: string, + total_principal_value: string, + total_interest_accrued_value: string, + loan_max_point: string, + loan_liquidation_point: string, + } +} + +export type { + ConfigResponse, + GetMarketsResponse, + GetCollateralResponse, + UserPositionResponse, +};