From 92f16a6f4dfe3acb646fb023f2d558b3b16641b5 Mon Sep 17 00:00:00 2001 From: SissonJ Date: Tue, 20 Aug 2024 17:07:19 -0500 Subject: [PATCH 1/5] feat: adding types for money market --- src/contracts/definitions/index.ts | 1 + src/contracts/definitions/moneyMarket.ts | 191 ++++++++++++++++++++ src/contracts/services/moneyMarket.ts | 41 +++++ src/types/contracts/index.ts | 1 + src/types/contracts/moneyMarket/index.ts | 1 + src/types/contracts/moneyMarket/model.ts | 71 ++++++++ src/types/contracts/moneyMarket/response.ts | 153 ++++++++++++++++ 7 files changed, 459 insertions(+) create mode 100644 src/contracts/definitions/moneyMarket.ts create mode 100644 src/contracts/services/moneyMarket.ts create mode 100644 src/types/contracts/moneyMarket/index.ts create mode 100644 src/types/contracts/moneyMarket/model.ts create mode 100644 src/types/contracts/moneyMarket/response.ts 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/moneyMarket.ts b/src/contracts/services/moneyMarket.ts new file mode 100644 index 0000000..a3f759a --- /dev/null +++ b/src/contracts/services/moneyMarket.ts @@ -0,0 +1,41 @@ +import { getActiveQueryClient$ } from '~/client'; +import { + switchMap, + first, + map, + lastValueFrom, +} from 'rxjs'; +import { sendSecretClientContractQuery$ } from '~/client/services/clientServices'; +import { msgQueryMoneyMarketConfig } from '../definitions/moneyMarket'; + +const parseMoneyMarketConfig = ( + response: ConfigResponse +):ParsedConfigResponse + +/** + * 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) => parseDerivativeShdStakingInfo(response as StakingInfoResponse)), + first(), +); + +export { +}; 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..9f8ccad --- /dev/null +++ b/src/types/contracts/moneyMarket/index.ts @@ -0,0 +1 @@ +export * from './model'; diff --git a/src/types/contracts/moneyMarket/model.ts b/src/types/contracts/moneyMarket/model.ts new file mode 100644 index 0000000..b57e720 --- /dev/null +++ b/src/types/contracts/moneyMarket/model.ts @@ -0,0 +1,71 @@ +type Pagination = { + page: number, + page_size: number, +} + +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 ParsedMarketResponse = { + marketToken: { + contractAddress: string, + codeHash: string, + }, + lToken: { + contractAddress: string, + codeHash: string, + }, + decimals: number, + oracleKey: string, + interest: { + linear?: { + base: string, + slope: string, + }, + piecewise_linear?: { + 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, +} + +export type { + Pagination, +}; 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, +}; From ea1fd676d04d0a4ea736df681aabf8430e21f45e Mon Sep 17 00:00:00 2001 From: SissonJ Date: Wed, 21 Aug 2024 13:45:01 -0500 Subject: [PATCH 2/5] feat: add batch query and the rest of the services --- src/contracts/services/moneyMarket.ts | 549 ++++++++++++++++++++++- src/types/contracts/moneyMarket/model.ts | 116 ++++- 2 files changed, 651 insertions(+), 14 deletions(-) diff --git a/src/contracts/services/moneyMarket.ts b/src/contracts/services/moneyMarket.ts index a3f759a..972ec62 100644 --- a/src/contracts/services/moneyMarket.ts +++ b/src/contracts/services/moneyMarket.ts @@ -6,11 +6,131 @@ import { lastValueFrom, } from 'rxjs'; import { sendSecretClientContractQuery$ } from '~/client/services/clientServices'; -import { msgQueryMoneyMarketConfig } from '../definitions/moneyMarket'; +import { ConfigResponse, GetCollateralResponse, GetMarketsResponse } from '~/types/contracts/moneyMarket/response'; +import { + BatchMoneyMarketConfigs, + BatchMoneyMarketGetCollaterals, + BatchMoneyMarketGetMarkets, + ContractAndPagination, + Pagination, ParsedConfigResponse, ParsedGetCollateralResponse, ParsedGetMarketsResponse, +} from '~/types/contracts/moneyMarket/model'; +import { msgQueryMoneyMarketCollaterals, msgQueryMoneyMarketConfig, msgQueryMoneyMarketMarkets } from '../definitions/moneyMarket'; +import { SERVICE_BATCH_SIZE } from './config'; +import { Contract } from '../../types/contracts/shared/index'; +import { + BatchQueryParams, BatchQueryParsedResponse, MinBlockHeightValidationOptions, batchQuery$, +} from '../..'; + +/** +* 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 + 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 @@ -33,9 +153,430 @@ const queryMoneyMarketConfig$ = ({ contractAddress, codeHash, })), - map((response) => parseDerivativeShdStakingInfo(response as StakingInfoResponse)), + 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 = SERVICE_BATCH_SIZE.PAIR_INFO, + 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 = SERVICE_BATCH_SIZE.PAIR_INFO, + 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 = SERVICE_BATCH_SIZE.PAIR_INFO, + 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/moneyMarket/model.ts b/src/types/contracts/moneyMarket/model.ts index b57e720..62db041 100644 --- a/src/types/contracts/moneyMarket/model.ts +++ b/src/types/contracts/moneyMarket/model.ts @@ -3,6 +3,23 @@ type Pagination = { page_size: number, } +type ContractAndPagination = { + address: string, + codeHash: string, + page?: number, + pageSize?: number, +} + +type ParsedPagination = { + page: number, + pageSize: number, + totalPages: number, + totalItems: number, + data: { + [token: string]: T + }, +} + type ParsedConfigResponse = { adminAuth: { contractAddress: string @@ -28,6 +45,14 @@ type ParsedConfigResponse = { collateralDepositEnabled: boolean, } +type BatchMoneyMarketConfig = { + moneyMarketContractAddress: string, + config: ParsedConfigResponse, + blockHeight: number, +} + +type BatchMoneyMarketConfigs = BatchMoneyMarketConfig[]; + type ParsedMarketResponse = { marketToken: { contractAddress: string, @@ -40,16 +65,10 @@ type ParsedMarketResponse = { decimals: number, oracleKey: string, interest: { - linear?: { - base: string, - slope: string, - }, - piecewise_linear?: { - base: string, - slope1: string, - slope2: string, - optimalUtilisation: string, - } + base: string, + slope1: string, + slope2?: string, + optimalUtilisation?: string, }, loanableAmount: string, lentAmount: string, @@ -66,6 +85,83 @@ type ParsedMarketResponse = { 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, }; From 668aed4480aa72017db28fdb1f61425356118c77 Mon Sep 17 00:00:00 2001 From: SissonJ Date: Wed, 21 Aug 2024 13:48:25 -0500 Subject: [PATCH 3/5] feat: added some exports --- src/contracts/services/index.ts | 1 + src/types/contracts/moneyMarket/index.ts | 1 + 2 files changed, 2 insertions(+) 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/types/contracts/moneyMarket/index.ts b/src/types/contracts/moneyMarket/index.ts index 9f8ccad..ed9aa71 100644 --- a/src/types/contracts/moneyMarket/index.ts +++ b/src/types/contracts/moneyMarket/index.ts @@ -1 +1,2 @@ export * from './model'; +export * from './response'; From f316a95a16cc1c83ec83cf1a5ae07c8e819e93e9 Mon Sep 17 00:00:00 2001 From: SissonJ Date: Wed, 21 Aug 2024 13:52:06 -0500 Subject: [PATCH 4/5] feat: add changeset --- .changeset/lovely-dogs-pretend.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/lovely-dogs-pretend.md diff --git a/.changeset/lovely-dogs-pretend.md b/.changeset/lovely-dogs-pretend.md new file mode 100644 index 0000000..25f9b2a --- /dev/null +++ b/.changeset/lovely-dogs-pretend.md @@ -0,0 +1,5 @@ +--- +"@shadeprotocol/shadejs": minor +--- + +Money market interface pending tests and docs From 95444a58f3c3021b3b972b10be44b9ef2bc3f0f3 Mon Sep 17 00:00:00 2001 From: SissonJ Date: Fri, 23 Aug 2024 15:35:05 -0500 Subject: [PATCH 5/5] chore: small fix --- .changeset/breezy-dodos-explode.md | 5 +++++ .changeset/lovely-dogs-pretend.md | 5 ----- src/contracts/services/moneyMarket.ts | 17 +++++++++-------- src/types/contracts/moneyMarket/model.ts | 8 +++----- 4 files changed, 17 insertions(+), 18 deletions(-) create mode 100644 .changeset/breezy-dodos-explode.md delete mode 100644 .changeset/lovely-dogs-pretend.md 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/.changeset/lovely-dogs-pretend.md b/.changeset/lovely-dogs-pretend.md deleted file mode 100644 index 25f9b2a..0000000 --- a/.changeset/lovely-dogs-pretend.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@shadeprotocol/shadejs": minor ---- - -Money market interface pending tests and docs diff --git a/src/contracts/services/moneyMarket.ts b/src/contracts/services/moneyMarket.ts index 972ec62..36010f8 100644 --- a/src/contracts/services/moneyMarket.ts +++ b/src/contracts/services/moneyMarket.ts @@ -14,12 +14,13 @@ import { ContractAndPagination, Pagination, ParsedConfigResponse, ParsedGetCollateralResponse, ParsedGetMarketsResponse, } from '~/types/contracts/moneyMarket/model'; -import { msgQueryMoneyMarketCollaterals, msgQueryMoneyMarketConfig, msgQueryMoneyMarketMarkets } from '../definitions/moneyMarket'; -import { SERVICE_BATCH_SIZE } from './config'; -import { Contract } from '../../types/contracts/shared/index'; +import { Contract } from '~/types/contracts/shared/index'; import { - BatchQueryParams, BatchQueryParsedResponse, MinBlockHeightValidationOptions, batchQuery$, -} from '../..'; + 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 @@ -319,7 +320,7 @@ function batchQueryMoneyMarketConfig$({ lcdEndpoint, chainId, moneyMarketContracts, - batchSize = SERVICE_BATCH_SIZE.PAIR_INFO, + batchSize, minBlockHeightValidationOptions, blockHeight, }:{ @@ -407,7 +408,7 @@ function batchQueryMoneyMarketGetMarkets$({ lcdEndpoint, chainId, moneyMarketContracts, - batchSize = SERVICE_BATCH_SIZE.PAIR_INFO, + batchSize, minBlockHeightValidationOptions, blockHeight, }:{ @@ -501,7 +502,7 @@ function batchQueryMoneyMarketGetCollateral$({ lcdEndpoint, chainId, moneyMarketContracts, - batchSize = SERVICE_BATCH_SIZE.PAIR_INFO, + batchSize, minBlockHeightValidationOptions, blockHeight, }:{ diff --git a/src/types/contracts/moneyMarket/model.ts b/src/types/contracts/moneyMarket/model.ts index 62db041..18f6c5c 100644 --- a/src/types/contracts/moneyMarket/model.ts +++ b/src/types/contracts/moneyMarket/model.ts @@ -15,9 +15,7 @@ type ParsedPagination = { pageSize: number, totalPages: number, totalItems: number, - data: { - [token: string]: T - }, + data: T, } type ParsedConfigResponse = { @@ -85,7 +83,7 @@ type ParsedMarketResponse = { interestAccrualEnabled: boolean, } -type ParsedGetMarketsResponse = ParsedPagination; +type ParsedGetMarketsResponse = ParsedPagination>; type BatchMoneyMarketGetMarket = { moneyMarketContractAddress: string, @@ -110,7 +108,7 @@ type ParsedCollateralReponse = { liquidationEnabled: boolean, } -type ParsedGetCollateralResponse = ParsedPagination; +type ParsedGetCollateralResponse = ParsedPagination>; type BatchMoneyMarketGetCollateral = { moneyMarketContractAddress: string,