diff --git a/.changeset/beige-teachers-enjoy.md b/.changeset/beige-teachers-enjoy.md new file mode 100644 index 0000000..0bf9f20 --- /dev/null +++ b/.changeset/beige-teachers-enjoy.md @@ -0,0 +1,5 @@ +--- +"@shadeprotocol/shadejs": minor +--- + +lend vault queries diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts index 29802f1..b2b8ef7 100644 --- a/docs/.vitepress/config.ts +++ b/docs/.vitepress/config.ts @@ -26,6 +26,7 @@ export default defineConfig({ collapsed: false, items: [ { text: 'Swap', link: '/queries/swap' }, + { text: 'Lend', link: '/queries/lend' }, { text: 'Oracle', link: '/queries/oracle' }, { text: 'stkd-SCRT', link: '/queries/derivativeScrt' }, { text: 'Shade Staking', link: '/queries/shadeStaking' }, diff --git a/docs/queries/lend.md b/docs/queries/lend.md new file mode 100644 index 0000000..3d7bdb6 --- /dev/null +++ b/docs/queries/lend.md @@ -0,0 +1,132 @@ +# Lend Examples + +This page demonstrates how to query the Shade Lend contracts. + +## All Vaults +Query multiple vault registry contracts and return info about all the vaults in each registry. + +**input** +```ts +async function queryVaults({ + queryRouterContractAddress, + queryRouterCodeHash, + lcdEndpoint, + chainId, + vaultRegistryContracts, +}:{ + queryRouterContractAddress: string, + queryRouterCodeHash?: string, + lcdEndpoint?: string, + chainId?: string, + vaultRegistryContracts: LendVaultRegistryContract[] +}): Promise + +type LendVaultRegistryContract = { + address: string, + codeHash: string, + vaultType: VaultType, +}; + +enum VaultType { + V1 = 'v1', + V2 = 'v2', + V3 = 'v3', +} +``` + +**output** + +```ts + +type BatchVaults = BatchVaultsItem[] + +type BatchVaultsItem = { + vaultRegistryContractAddress: string, + vaults: Vaults, + blockHeight: number, +} + +type Vaults = { + [id: string]: Vault, +} + +type Vault = { + id: string, + vaultType: VaultType, + name: string, + collateralAddress: string, + silkMaxAllowance: string, + silkAllowanceUsed: string, + maxLtv: number, // decimal percent + collateral: { + total: string, + elastic: string, + base: string, + safe: string, + lastAccruedAt: Date, + oracleDelay: number, + }, + debt: { + total: string, + base: string, + lastAccruedAt: Date, + } + interestRate: { + current: number, // decimal percent + target: number, + delta: number, + ratePerSecond: number, + lastUpdatedAt: Date, + }, + borrowFee: { + current: number, // decimal percent + target: number, + delta: number, + ratePerSecond: number, + lastUpdatedAt: Date, + }, + liquidationFee: { + discount: number, + minimumDebt: string, + daoShare: number, + callerShare: number + } + isProtocolOnly: boolean, + status: LendContractStatus, + openPositions: number, + totalPositions: number, + whitelist: string[], +} + +enum LendContractStatus { + NORMAL = 'normal', + DEPRECATED = 'deprecated', + FROZEN = 'frozen' +} +``` + +## Single Vault +Query info for a single vault. + +**input** +```ts +async function queryVault({ + vaultRegistryContractAddress, + vaultRegistryCodeHash, + vaultType, + vaultId, + lcdEndpoint, + chainId, +}:{ + vaultRegistryContractAddress: string, + vaultRegistryCodeHash?: string, + vaultType: VaultType, + vaultId: string, + lcdEndpoint?: string, + chainId?: string, +}): Promise +``` + +**output** + +See "Vault" type in the all vaults output. \ No newline at end of file diff --git a/src/contracts/definitions/index.ts b/src/contracts/definitions/index.ts index 933e643..3769947 100644 --- a/src/contracts/definitions/index.ts +++ b/src/contracts/definitions/index.ts @@ -5,3 +5,4 @@ export * from './swap'; export * from './derivativeShd'; export * from './derivativeScrt'; export * from './shadeStaking'; +export * from './lend'; diff --git a/src/contracts/definitions/lend.test.ts b/src/contracts/definitions/lend.test.ts new file mode 100644 index 0000000..d03763f --- /dev/null +++ b/src/contracts/definitions/lend.test.ts @@ -0,0 +1,132 @@ +import { + test, + expect, +} from 'vitest'; +import { + msgGetVault, + msgGetVaults, + msgGetVaultUserPosition, + msgGetVaultUserPositions, + msgBorrow, + msgWithdraw, +} from './lend'; + +test('it tests the form of the vault info message', () => { + const inputVaultId = '1'; + + const output = { + vault: { + vault_id: inputVaultId, + }, + }; + expect(msgGetVault(inputVaultId)).toStrictEqual(output); +}); + +test('it tests the form of the multiple vaults info message', () => { + const inputStartingPageNumber = '1'; + + const output = { + vaults: { + starting_page: inputStartingPageNumber, + }, + }; + expect(msgGetVaults(inputStartingPageNumber)).toStrictEqual(output); +}); + +test('it tests the form of the vault user position message', () => { + const inputVaultId = '1'; + const permit = { + params: { + data: 'PERMIT_DATA', + contract: 'CONTRACT', + key: 'KEY', + }, + chain_id: 'CHAIN_ID', + signature: { + pub_key: { + type: 'TYPE', + value: 'VALUE', + }, + signature: 'SIGNATURE', + }, + }; + + const output = { + with_permit: { + permit, + query: { + position: { + vault_id: inputVaultId, + }, + }, + }, + }; + expect(msgGetVaultUserPosition(permit, inputVaultId)).toStrictEqual(output); +}); + +test('it tests the form of the vaults user position message', () => { + const inputVaultIds = ['1', '2']; + const permit = { + params: { + data: 'PERMIT_DATA', + contract: 'CONTRACT', + key: 'KEY', + }, + chain_id: 'CHAIN_ID', + signature: { + pub_key: { + type: 'TYPE', + value: 'VALUE', + }, + signature: 'SIGNATURE', + }, + }; + + const output = { + with_permit: { + permit, + query: { + positions: { + vault_ids: inputVaultIds, + }, + }, + }, + }; + expect(msgGetVaultUserPositions(permit, inputVaultIds)).toStrictEqual(output); +}); + +test('it test the form of the borrow message', () => { + const input = { + borrowAmount: 'BORROW_AMOUNT', + maxBorrowFee: 'BORROW_FEE', + vaultId: 'VAULT_ID', + }; + + const output = { + vault_action: { + vault_id: input.vaultId, + msg: { + borrow: { + amount: input.borrowAmount, + max_fee: input.maxBorrowFee, + }, + }, + }, + }; + expect(msgBorrow(input)).toStrictEqual(output); +}); + +test('it test the form of the withdraw message', () => { + const input = { + withdrawAmount: 'WITHDRAW_AMOUNT', + vaultId: 'VAULT_ID', + }; + + const output = { + vault_action: { + vault_id: input.vaultId, + msg: { withdraw: input.withdrawAmount }, + }, + }; + expect(msgWithdraw(input.withdrawAmount, input.vaultId)).toStrictEqual(output); +}); diff --git a/src/contracts/definitions/lend.ts b/src/contracts/definitions/lend.ts new file mode 100644 index 0000000..f5d8245 --- /dev/null +++ b/src/contracts/definitions/lend.ts @@ -0,0 +1,96 @@ +import { AccountPermit } from '~/types/permit'; + +/** + * message for the getting the vault info + */ +const msgGetVault = (vaultId: string) => ({ + vault: { + vault_id: vaultId, + }, +}); + +/** + * message for the getting multiple vaults info. + * @param startingPage The data is paginated and returned + * for the starting page and all pages after. Use "1" to query all vaults. + */ +const msgGetVaults = (startingPage: string) => ({ + vaults: { + starting_page: startingPage, + }, +}); + +/** + * message for the getting a user position + */ +const msgGetVaultUserPosition = (permit: AccountPermit, vaultId: string) => ({ + with_permit: { + permit, + query: { + position: { + vault_id: vaultId, + }, + }, + }, +}); + +/** + * message for getting multiple user positions + */ +const msgGetVaultUserPositions = (permit: AccountPermit, vaultIds: string[]) => ({ + with_permit: { + permit, + query: { + positions: { + vault_ids: vaultIds, + }, + }, + }, +}); + +/** + * message to borrow silk from a lend vault + */ +const msgBorrow = ({ + borrowAmount, + maxBorrowFee, + vaultId, +}: { + borrowAmount: string, + maxBorrowFee?: string, + vaultId: string, +}) => ({ + vault_action: { + vault_id: vaultId, + msg: { + borrow: { + amount: borrowAmount, + max_fee: maxBorrowFee, + }, + }, + }, +}); + +/** + * message to withdraw collateral from a lend vault + */ +const msgWithdraw = ( + withdrawAmount: string, + vaultId: string, +) => ({ + vault_action: { + vault_id: vaultId, + msg: { + withdraw: withdrawAmount, + }, + }, +}); + +export { + msgGetVault, + msgGetVaults, + msgGetVaultUserPosition, + msgGetVaultUserPositions, + msgBorrow, + msgWithdraw, +}; diff --git a/src/contracts/services/index.ts b/src/contracts/services/index.ts index b614292..ffeb0fa 100644 --- a/src/contracts/services/index.ts +++ b/src/contracts/services/index.ts @@ -5,3 +5,4 @@ export * from './swap'; export * from './derivativeScrt'; export * from './derivativeShd'; export * from './shadeStaking'; +export * from './lend'; diff --git a/src/contracts/services/lend.test.ts b/src/contracts/services/lend.test.ts new file mode 100644 index 0000000..57131f3 --- /dev/null +++ b/src/contracts/services/lend.test.ts @@ -0,0 +1,249 @@ +import { + test, + expect, + vi, + beforeAll, +} from 'vitest'; +import { of } from 'rxjs'; +import vaultV1Response from '~/test/mocks/lend/vaultV1Response.json'; +import vaultsV1Response from '~/test/mocks/lend/vaultsV1Response.json'; +import vaultV2Response from '~/test/mocks/lend/vaultV2Response.json'; +import vaultsV2Response from '~/test/mocks/lend/vaultsV2Response.json'; +import vaultV3Response from '~/test/mocks/lend/vaultV3Response.json'; +import vaultsV3Response from '~/test/mocks/lend/vaultsV3Response.json'; +import { VaultVersion } from '~/types/contracts/lend/model'; +import { VaultResponse, VaultsResponse } from '~/types/contracts/lend/response'; +import { + vaultV1Parsed, + vaultsV1Parsed, +} from '~/test/mocks/lend/vaultV1Parsed'; +import { + vaultV2Parsed, + vaultsV2Parsed, +} from '~/test/mocks/lend/vaultV2Parsed'; +import { + vaultV3Parsed, + vaultsV3Parsed, +} from '~/test/mocks/lend/vaultV3Parsed'; +import { batchVaultsResponseUnparsed } from '~/test/mocks/lend/batchVaultsUnparsed'; +import { BatchQueryParsedResponse } from '~/types'; +import { batchVaultsParsed } from '~/test/mocks/lend/batchVaultsParsed'; +import { + parseLendVault, + parseLendVaults, + parseBatchQueryVaultsInfo, + queryVaults$, + queryVaults, + queryVault$, + queryVault, +} from './lend'; + +const sendSecretClientContractQuery$ = vi.hoisted(() => vi.fn()); +const batchQuery$ = vi.hoisted(() => vi.fn()); + +beforeAll(() => { + vi.mock('~/contracts/definitions/lend', () => ({ + msgGetVaults: vi.fn(() => 'GET_VAULTS_MSG'), + msgGetVault: vi.fn(() => 'GET_VAULT_MSG'), + })); + + vi.mock('~/client/index', () => ({ + getActiveQueryClient$: vi.fn(() => of({ client: 'CLIENT' })), + })); + + vi.mock('~/client/services/clientServices', () => ({ + sendSecretClientContractQuery$, + })); + + vi.mock('~/contracts/services/batchQuery', () => ({ + batchQuery$, + })); +}); + +test('it can parse the single lend vault V1 response', () => { + expect(parseLendVault( + vaultV1Response as VaultResponse, + VaultVersion.V1, + )).toStrictEqual(vaultV1Parsed); +}); + +test('it can parse the single lend vault V2 response', () => { + expect(parseLendVault( + vaultV2Response as VaultResponse, + VaultVersion.V2, + )).toStrictEqual(vaultV2Parsed); +}); + +test('it can parse the single lend vault V3 response', () => { + expect(parseLendVault( + vaultV3Response as VaultResponse, + VaultVersion.V3, + )).toStrictEqual(vaultV3Parsed); +}); + +test('it can parse the multiple lend vaults V1 response', () => { + expect(parseLendVaults( + vaultsV1Response as VaultsResponse, + VaultVersion.V1, + )).toStrictEqual(vaultsV1Parsed); +}); + +test('it can parse the multiple lend vaults V2 response', () => { + expect(parseLendVaults( + vaultsV2Response as VaultsResponse, + VaultVersion.V2, + )).toStrictEqual(vaultsV2Parsed); +}); + +test('it can parse the multiple lend vaults V3 response', () => { + expect(parseLendVaults( + vaultsV3Response as VaultsResponse, + VaultVersion.V3, + )).toStrictEqual(vaultsV3Parsed); +}); + +test('it can parse the batch query of multiple lend vault contracts', () => { + expect(parseBatchQueryVaultsInfo( + batchVaultsResponseUnparsed as BatchQueryParsedResponse, + [VaultVersion.V1, VaultVersion.V2, VaultVersion.V3], + )).toStrictEqual(batchVaultsParsed); +}); + +test('it can call the batch vaults query service', async () => { + const input = { + queryRouterContractAddress: 'QUERY_ROUTER_CONTRACT_ADDRESS', + queryRouterCodeHash: 'QUERY_ROUTER_CODE_HASH', + lcdEndpoint: 'LCD_ENDPOINT', + chainId: 'CHAIN_ID', + vaultRegistryContracts: [{ + address: 'ADDRESS_1', + codeHash: 'CODE_HASH_1', + vaultVersion: VaultVersion.V1, + }, + { + address: 'ADDRESS_2', + codeHash: 'CODE_HASH_2', + vaultVersion: VaultVersion.V2, + }, + { + address: 'ADDRESS_3', + codeHash: 'CODE_HASH_3', + vaultVersion: VaultVersion.V3, + }], + }; + // observables function + batchQuery$.mockReturnValueOnce(of(batchVaultsResponseUnparsed)); + let output; + queryVaults$(input).subscribe({ + next: (response) => { + output = response; + }, + }); + + expect(batchQuery$).toHaveBeenCalledWith({ + contractAddress: input.queryRouterContractAddress, + codeHash: input.queryRouterCodeHash, + lcdEndpoint: input.lcdEndpoint, + chainId: input.chainId, + queries: [{ + id: input.vaultRegistryContracts[0].address, + contract: { + address: input.vaultRegistryContracts[0].address, + codeHash: input.vaultRegistryContracts[0].codeHash, + }, + queryMsg: 'GET_VAULTS_MSG', + }, + { + id: input.vaultRegistryContracts[1].address, + contract: { + address: input.vaultRegistryContracts[1].address, + codeHash: input.vaultRegistryContracts[1].codeHash, + }, + queryMsg: 'GET_VAULTS_MSG', + }, + { + id: input.vaultRegistryContracts[2].address, + contract: { + address: input.vaultRegistryContracts[2].address, + codeHash: input.vaultRegistryContracts[2].codeHash, + }, + queryMsg: 'GET_VAULTS_MSG', + }], + }); + + expect(output).toStrictEqual(batchVaultsParsed); + + // async/await function + batchQuery$.mockReturnValueOnce(of(batchVaultsResponseUnparsed)); + const response = await queryVaults(input); + expect(batchQuery$).toHaveBeenCalledWith({ + contractAddress: input.queryRouterContractAddress, + codeHash: input.queryRouterCodeHash, + lcdEndpoint: input.lcdEndpoint, + chainId: input.chainId, + queries: [{ + id: input.vaultRegistryContracts[0].address, + contract: { + address: input.vaultRegistryContracts[0].address, + codeHash: input.vaultRegistryContracts[0].codeHash, + }, + queryMsg: 'GET_VAULTS_MSG', + }, + { + id: input.vaultRegistryContracts[1].address, + contract: { + address: input.vaultRegistryContracts[1].address, + codeHash: input.vaultRegistryContracts[1].codeHash, + }, + queryMsg: 'GET_VAULTS_MSG', + }, + { + id: input.vaultRegistryContracts[2].address, + contract: { + address: input.vaultRegistryContracts[2].address, + codeHash: input.vaultRegistryContracts[2].codeHash, + }, + queryMsg: 'GET_VAULTS_MSG', + }], + }); + expect(response).toStrictEqual(batchVaultsParsed); +}); + +test('it can call single vault query service', async () => { + const input = { + vaultRegistryContractAddress: 'VAULT_CONTRACT_ADDRESS', + vaultRegistryCodeHash: 'VAULT_CODE_HASH', + vaultVersion: VaultVersion.V1, + vaultId: '1', + lcdEndpoint: 'LCD_ENDPOINT', + chainId: 'CHAIN_ID', + }; + // observables function + sendSecretClientContractQuery$.mockReturnValueOnce(of(vaultV1Response)); + let output; + queryVault$(input).subscribe({ + next: (response) => { + output = response; + }, + }); + + expect(sendSecretClientContractQuery$).toHaveBeenCalledWith({ + queryMsg: 'GET_VAULT_MSG', + client: 'CLIENT', + contractAddress: input.vaultRegistryContractAddress, + codeHash: input.vaultRegistryCodeHash, + }); + + expect(output).toStrictEqual(vaultV1Parsed); + + // async/await function + sendSecretClientContractQuery$.mockReturnValueOnce(of(vaultV1Response)); + const response = await queryVault(input); + expect(sendSecretClientContractQuery$).toHaveBeenCalledWith({ + queryMsg: 'GET_VAULT_MSG', + client: 'CLIENT', + contractAddress: input.vaultRegistryContractAddress, + codeHash: input.vaultRegistryCodeHash, + }); + expect(response).toStrictEqual(vaultV1Parsed); +}); diff --git a/src/contracts/services/lend.ts b/src/contracts/services/lend.ts new file mode 100644 index 0000000..e8bdeae --- /dev/null +++ b/src/contracts/services/lend.ts @@ -0,0 +1,288 @@ +import { + BatchQueryParams, + BatchQueryParsedResponse, + MinBlockHeightValidationOptions, +} from '~/types'; +import { batchQuery$ } from '~/contracts/services/batchQuery'; +import { + map, + first, + switchMap, + lastValueFrom, +} from 'rxjs'; +import { + VaultResponse, + VaultsResponse, + NormalizationFactor, +} from '~/types/contracts/lend/response'; +import { + convertCoinFromUDenom, + getActiveQueryClient$, +} from '~/index'; +import { + Vaults, + Vault, + BatchVaults, VaultVersion, + LendVaultRegistryContract, +} from '~/types/contracts/lend/model'; +import { + msgGetVault, + msgGetVaults, +} from '~/contracts/definitions/lend'; +import { sendSecretClientContractQuery$ } from '~/client/services/clientServices'; +import BigNumber from 'bignumber.js'; + +/** +* Parse lend vault response +*/ +function parseLendVault(vault: VaultResponse, vaultVersion: VaultVersion) { + const { + id, + allowance, + collateral: { + elastic: elasticCollateral, + base: baseCollateral, + last_accrued: collateralLastAccrued, + }, + safe_collateral: safeCollateral, + config: { + max_ltv: maxLtv, + collateral_oracle_delay: collateralOracleDelay, + fees: { + interest_rate: interestRate, + borrow_fee: borrowFee, + liquidation_fee: liquidationFee, + }, + }, + debt, + collateral_addr: collateralAddress, + is_protocol: isProtocolOnly, + name, + open_positions: openPositions, + position_id_counter: positionIdCounter, + } = vault.vault; + + return { + id, + vaultVersion, + name, + collateralAddress, + silkMaxAllowance: convertCoinFromUDenom(allowance.max, NormalizationFactor.LEND).toString(), + silkAllowanceUsed: convertCoinFromUDenom(allowance.used, NormalizationFactor.LEND).toString(), + maxLtv: Number(maxLtv), + // Collateral is expressed differently depending on vault type + collateral: { + total: + (vaultVersion === VaultVersion.V1 || vaultVersion === VaultVersion.V2) + ? convertCoinFromUDenom(elasticCollateral, NormalizationFactor.LEND).toString() + : convertCoinFromUDenom( + BigNumber(elasticCollateral).plus(safeCollateral), + NormalizationFactor.LEND, + ).toString(), + elastic: convertCoinFromUDenom(elasticCollateral, NormalizationFactor.LEND).toString(), + base: convertCoinFromUDenom(baseCollateral, NormalizationFactor.LEND).toString(), + safe: convertCoinFromUDenom(safeCollateral, NormalizationFactor.LEND).toString(), + lastAccruedAt: new Date(Number(collateralLastAccrued) * 1000), + oracleDelay: Number(collateralOracleDelay), + }, + debt: { + total: convertCoinFromUDenom(debt.elastic, NormalizationFactor.LEND).toString(), + base: convertCoinFromUDenom(debt.base, NormalizationFactor.LEND).toString(), + lastAccruedAt: new Date(Number(debt.last_accrued) * 1000), + }, + interestRate: { + current: Number(interestRate.current), + target: Number(interestRate.target), + delta: Number(interestRate.delta), + ratePerSecond: Number(interestRate.rate_per_second), + lastUpdatedAt: new Date( + Number(interestRate.last_changed) * 1000, + ), + }, + borrowFee: { + current: Number(borrowFee.current), + target: Number(borrowFee.target), + delta: Number(borrowFee.delta), + ratePerSecond: Number(borrowFee.rate_per_second), + lastUpdatedAt: new Date(Number(borrowFee.last_changed) * 1000), + }, + liquidationFee: { + discount: Number(liquidationFee.discount), + minimumDebt: convertCoinFromUDenom( + liquidationFee.min_debt, + NormalizationFactor.LEND, + ).toString(), + daoShare: Number(liquidationFee.treasury_share), + callerShare: Number(liquidationFee.caller_share), + }, + isProtocolOnly, + status: vault.status, + openPositions: Number(openPositions.value), + totalPositions: Number(positionIdCounter.value), + whitelist: vault.whitelist, + } as Vault; +} + +/** +* Parse lend vaults response +*/ +function parseLendVaults(vaults: VaultsResponse, vaultVersion: VaultVersion): Vaults { + return vaults.vaults.reduce((prev: Vaults, vault: VaultResponse) => { + const { + id: vaultId, + } = vault.vault; + return { + ...prev, + [vaultId]: parseLendVault(vault, vaultVersion), + }; + }, {}); +} + +/** + * parses the vaults reponse from a batch query of + * multiple vaults contracts + */ +const parseBatchQueryVaultsInfo = ( + response: BatchQueryParsedResponse, + vaultVersions: VaultVersion[], +): BatchVaults => response.map((item, index) => ({ + vaultRegistryContractAddress: item.id as string, + vaults: parseLendVaults(item.response, vaultVersions[index]), + blockHeight: item.blockHeight, +})); + +/** + * query the info for multiple lend vaults contracts + */ +function queryVaults$({ + queryRouterContractAddress, + queryRouterCodeHash, + lcdEndpoint, + chainId, + vaultRegistryContracts, + minBlockHeightValidationOptions, +}:{ + queryRouterContractAddress: string, + queryRouterCodeHash?: string, + lcdEndpoint?: string, + chainId?: string, + vaultRegistryContracts: LendVaultRegistryContract[], + minBlockHeightValidationOptions?: MinBlockHeightValidationOptions, +}) { + const queries:BatchQueryParams[] = vaultRegistryContracts.map((contract) => ({ + id: contract.address, + contract: { + address: contract.address, + codeHash: contract.codeHash, + }, + queryMsg: msgGetVaults('1'), // starting page of 1, meaning that we will query all vaults + })); + + const vaultVersions = vaultRegistryContracts.map((contract) => contract.vaultVersion); + + return batchQuery$({ + contractAddress: queryRouterContractAddress, + codeHash: queryRouterCodeHash, + lcdEndpoint, + chainId, + queries, + minBlockHeightValidationOptions, + }).pipe( + map((response) => parseBatchQueryVaultsInfo(response, vaultVersions)), + first(), + ); +} + +/** + * query the info for multiple lend vault contracts + */ +async function queryVaults({ + queryRouterContractAddress, + queryRouterCodeHash, + lcdEndpoint, + chainId, + vaultRegistryContracts, + minBlockHeightValidationOptions, +}:{ + queryRouterContractAddress: string, + queryRouterCodeHash?: string, + lcdEndpoint?: string, + chainId?: string, + vaultRegistryContracts: LendVaultRegistryContract[] + minBlockHeightValidationOptions?: MinBlockHeightValidationOptions, +}) { + return lastValueFrom(queryVaults$({ + queryRouterContractAddress, + queryRouterCodeHash, + lcdEndpoint, + chainId, + vaultRegistryContracts, + minBlockHeightValidationOptions, + })); +} + +/** + * Observable for querying a single vault + */ +const queryVault$ = ({ + vaultRegistryContractAddress, + vaultRegistryCodeHash, + vaultVersion, + vaultId, + lcdEndpoint, + chainId, +}:{ + vaultRegistryContractAddress: string, + vaultRegistryCodeHash?: string, + vaultVersion: VaultVersion, + vaultId: string, + lcdEndpoint?: string, + chainId?: string, +}) => getActiveQueryClient$(lcdEndpoint, chainId).pipe( + switchMap(({ client }) => sendSecretClientContractQuery$({ + queryMsg: msgGetVault(vaultId), + client, + contractAddress: vaultRegistryContractAddress, + codeHash: vaultRegistryCodeHash, + })), + map((response) => parseLendVault(response as VaultResponse, vaultVersion)), + first(), +); + +/** + * query a single vault + */ +async function queryVault({ + vaultRegistryContractAddress, + vaultRegistryCodeHash, + vaultVersion, + vaultId, + lcdEndpoint, + chainId, +}:{ + vaultRegistryContractAddress: string, + vaultRegistryCodeHash?: string, + vaultVersion: VaultVersion, + vaultId: string, + lcdEndpoint?: string, + chainId?: string, +}) { + return lastValueFrom(queryVault$({ + vaultRegistryContractAddress, + vaultRegistryCodeHash, + vaultVersion, + vaultId, + lcdEndpoint, + chainId, + })); +} + +export { + parseLendVault, + parseLendVaults, + parseBatchQueryVaultsInfo, + queryVaults$, + queryVaults, + queryVault$, + queryVault, +}; diff --git a/src/test/mocks/lend/batchVaultsParsed.ts b/src/test/mocks/lend/batchVaultsParsed.ts new file mode 100644 index 0000000..51f39de --- /dev/null +++ b/src/test/mocks/lend/batchVaultsParsed.ts @@ -0,0 +1,312 @@ +import { + BatchVaults, + VaultVersion, +} from '~/types/contracts/lend/model'; +import { LendContractStatus } from '~/types/contracts/lend/response'; + +const batchVaultsParsed: BatchVaults = [ + { + vaultRegistryContractAddress: 'secret18y86hldtdp9ndj0jekcch49kwr0gwy7upe3ffw', + vaults: { + 1: { + id: '1', + vaultVersion: VaultVersion.V1, + name: 'stkd-SCRT Vault', + collateralAddress: 'secret1k6u0cy4feepm6pehnz804zmwakuwdapm69tuc4', + silkMaxAllowance: '0', + silkAllowanceUsed: '11825.976211616265357496', + maxLtv: 0.45, + collateral: { + total: '69822.082224544587516946', + elastic: '69822.082224544587516946', + base: '69822.082224544587516946', + safe: '3076.606761056046617547', + lastAccruedAt: new Date(1681764653000), + oracleDelay: 600, + }, + debt: { + total: '12734.302492560037164766', + base: '12734.302492560037164766', + lastAccruedAt: new Date(1710953012000), + }, + interestRate: { + current: 0, + target: 0, + delta: 0.01, + ratePerSecond: 0, + lastUpdatedAt: new Date(1681764653000), + }, + borrowFee: { + current: 0, + target: 0, + delta: 0.01, + ratePerSecond: 0, + lastUpdatedAt: new Date(1681764653000), + }, + liquidationFee: { + discount: 0.1, + minimumDebt: '100', + daoShare: 0.2, + callerShare: 0.1, + }, + isProtocolOnly: false, + status: LendContractStatus.DEPRECATED, + openPositions: 32, + totalPositions: 73, + whitelist: [], + }, + 2: { + id: '2', + vaultVersion: VaultVersion.V1, + name: 'USDT Vault', + collateralAddress: 'secret1wk5j2cntwg2fgklf0uta3tlkvt87alfj7kepuw', + silkMaxAllowance: '0', + silkAllowanceUsed: '0', + maxLtv: 0.85, + collateral: { + total: '0', + elastic: '0', + base: '0', + safe: '0.000004653229977094', + lastAccruedAt: new Date(1681764653000), + oracleDelay: 600, + }, + debt: { + total: '0', + base: '0', + lastAccruedAt: new Date(1710953012000), + }, + interestRate: { + current: 0, + target: 0, + delta: 0.01, + ratePerSecond: 0, + lastUpdatedAt: new Date(1681764653000), + }, + borrowFee: { + current: 0, + target: 0, + delta: 0.01, + ratePerSecond: 0, + lastUpdatedAt: new Date(1681764653000), + }, + liquidationFee: { + discount: 0.05, + minimumDebt: '100', + daoShare: 0.2, + callerShare: 0.1, + }, + isProtocolOnly: false, + status: LendContractStatus.DEPRECATED, + openPositions: 3, + totalPositions: 9, + whitelist: [], + }, + }, + blockHeight: 1, + }, + { + vaultRegistryContractAddress: 'secret1qxk2scacpgj2mmm0af60674afl9e6qneg7yuny', + vaults: { + 1: { + id: '1', + vaultVersion: VaultVersion.V2, + name: 'stkd-SCRT Vault', + collateralAddress: 'secret1k6u0cy4feepm6pehnz804zmwakuwdapm69tuc4', + silkMaxAllowance: '750000', + silkAllowanceUsed: '700859.978232', + maxLtv: 0.5, + collateral: { + total: '3740763.561877', + elastic: '3740763.561877', + base: '3740763.561877', + safe: '31445.759105', + lastAccruedAt: new Date(1682191940000), + oracleDelay: 600, + }, + debt: { + total: '700859.978232', + base: '700859.978232', + lastAccruedAt: new Date(1710952834000), + }, + interestRate: { + current: 0, + target: 0, + delta: 0.01, + ratePerSecond: 0, + lastUpdatedAt: new Date(1682191940000), + }, + borrowFee: { + current: 0, + target: 0, + delta: 0.01, + ratePerSecond: 0, + lastUpdatedAt: new Date(1682191940000), + }, + liquidationFee: { + discount: 0.1, + minimumDebt: '100', + daoShare: 0.2, + callerShare: 0.1, + }, + isProtocolOnly: false, + status: LendContractStatus.NORMAL, + openPositions: 182, + totalPositions: 389, + whitelist: [], + }, + 2: { + id: '2', + vaultVersion: VaultVersion.V2, + name: 'USDT Vault', + collateralAddress: 'secret1wk5j2cntwg2fgklf0uta3tlkvt87alfj7kepuw', + silkMaxAllowance: '700000', + silkAllowanceUsed: '226463.25657', + maxLtv: 0.85, + collateral: { + total: '350148.899892', + elastic: '350148.899892', + base: '350148.899892', + safe: '73.431644', + lastAccruedAt: new Date(1682191940000), + oracleDelay: 600, + }, + debt: { + total: '227873.904431360577633957', + base: '226847.073546658394171419', + lastAccruedAt: new Date(1710952834000), + }, + interestRate: { + current: 0.01, + target: 0.01, + delta: 0.01, + ratePerSecond: 0.000000000316887385, + lastUpdatedAt: new Date(1696699251000), + }, + borrowFee: { + current: 0, + target: 0, + delta: 0.01, + ratePerSecond: 0, + lastUpdatedAt: new Date(1682191940000), + }, + liquidationFee: { + discount: 0.05, + minimumDebt: '100', + daoShare: 0.2, + callerShare: 0.1, + }, + isProtocolOnly: false, + status: LendContractStatus.NORMAL, + openPositions: 15, + totalPositions: 60, + whitelist: [], + }, + }, + blockHeight: 1, + }, + { + vaultRegistryContractAddress: 'secret1wj2czeeknya2n6jag7kpfxlm28dw7q96dgqmfs', + vaults: { + 1: { + id: '1', + vaultVersion: VaultVersion.V3, + name: 'WBTC Vault', + collateralAddress: 'secret1guyayjwg5f84daaxl7w84skd8naxvq8vz9upqx', + silkMaxAllowance: '150000', + silkAllowanceUsed: '121848.577218', + maxLtv: 0.8, + collateral: { + total: '6.14146888', + elastic: '2.114626673839308796', + base: '2.114626673839308796', + safe: '4.026842206160691204', + lastAccruedAt: new Date(1710183488000), + oracleDelay: 600, + }, + debt: { + total: '121848.577218', + base: '121848.577218', + lastAccruedAt: new Date(1710953123000), + }, + interestRate: { + current: 0, + target: 0, + delta: 0.01, + ratePerSecond: 0, + lastUpdatedAt: new Date(1710183488000), + }, + borrowFee: { + current: 0, + target: 0, + delta: 0.01, + ratePerSecond: 0, + lastUpdatedAt: new Date(1710183488000), + }, + liquidationFee: { + discount: 0.1, + minimumDebt: '100', + daoShare: 0.2, + callerShare: 0.1, + }, + isProtocolOnly: false, + status: LendContractStatus.NORMAL, + openPositions: 21, + totalPositions: 23, + whitelist: [], + }, + 2: { + id: '2', + vaultVersion: VaultVersion.V3, + name: 'TIA Vault', + collateralAddress: 'secret1s9h6mrp4k9gll4zfv5h78ll68hdq8ml7jrnn20', + silkMaxAllowance: '50000', + silkAllowanceUsed: '64.898575', + maxLtv: 0.55, + collateral: { + total: '15.060663', + elastic: '5.699935097070694443', + base: '5.699935097070694443', + safe: '9.360727902929305557', + lastAccruedAt: new Date(1710183538000), + oracleDelay: 600, + }, + debt: { + total: '64.898575', + base: '64.898575', + lastAccruedAt: new Date(1710953123000), + }, + interestRate: { + current: 0, + target: 0, + delta: 0.01, + ratePerSecond: 0, + lastUpdatedAt: new Date(1710183538000), + }, + borrowFee: { + current: 0, + target: 0, + delta: 0.01, + ratePerSecond: 0, + lastUpdatedAt: new Date(1710183538000), + }, + liquidationFee: { + discount: 0.1, + minimumDebt: '100', + daoShare: 0.2, + callerShare: 0.1, + }, + isProtocolOnly: false, + status: LendContractStatus.NORMAL, + openPositions: 2, + totalPositions: 2, + whitelist: [], + }, + }, + blockHeight: 1, + }, +]; + +export { + batchVaultsParsed, +}; diff --git a/src/test/mocks/lend/batchVaultsUnparsed.ts b/src/test/mocks/lend/batchVaultsUnparsed.ts new file mode 100644 index 0000000..939001f --- /dev/null +++ b/src/test/mocks/lend/batchVaultsUnparsed.ts @@ -0,0 +1,401 @@ +import { BatchQueryParsedResponse } from '~/types'; + +const batchVaultsResponseUnparsed: BatchQueryParsedResponse = [ + { + id: 'secret18y86hldtdp9ndj0jekcch49kwr0gwy7upe3ffw', + response: { + vaults: [ + { + vault: { + id: '1', + epoch: '0', + name: 'stkd-SCRT Vault', + collateral_addr: 'secret1k6u0cy4feepm6pehnz804zmwakuwdapm69tuc4', + safe_collateral: '3076606761056046617547', + collateral: { + elastic: '69822082224544587516946', + base: '69822082224544587516946', + last_accrued: '1681764653', + }, + debt: { + elastic: '12734302492560037164766', + base: '12734302492560037164766', + last_accrued: '1710953012', + }, + config: { + max_ltv: '0.45', + collateral_oracle_delay: '600', + fees: { + interest_rate: { + last_changed: '1681764653', + current: '0', + target: '0', + minimum_fee_update_interval: '1681764653', + delta: '0.01', + rate_per_second: '0', + }, + borrow_fee: { + last_changed: '1681764653', + current: '0', + target: '0', + minimum_fee_update_interval: '1681764653', + delta: '0.01', + rate_per_second: '0', + }, + liquidation_fee: { + discount: '0.1', + min_debt: '100000000000000000000', + treasury_share: '0.2', + caller_share: '0.1', + }, + }, + }, + allowance: { + used: '11825976211616265357496', + max: '0', + }, + open_positions: { + value: '32', + }, + is_protocol: false, + position_id_counter: { + value: '73', + }, + }, + status: 'deprecated', + whitelist: [], + }, + { + vault: { + id: '2', + epoch: '0', + name: 'USDT Vault', + collateral_addr: 'secret1wk5j2cntwg2fgklf0uta3tlkvt87alfj7kepuw', + safe_collateral: '4653229977094', + collateral: { + elastic: '0', + base: '0', + last_accrued: '1681764653', + }, + debt: { + elastic: '0', + base: '0', + last_accrued: '1710953012', + }, + config: { + max_ltv: '0.85', + collateral_oracle_delay: '600', + fees: { + interest_rate: { + last_changed: '1681764653', + current: '0', + target: '0', + minimum_fee_update_interval: '1681764653', + delta: '0.01', + rate_per_second: '0', + }, + borrow_fee: { + last_changed: '1681764653', + current: '0', + target: '0', + minimum_fee_update_interval: '1681764653', + delta: '0.01', + rate_per_second: '0', + }, + liquidation_fee: { + discount: '0.05', + min_debt: '100000000000000000000', + treasury_share: '0.2', + caller_share: '0.1', + }, + }, + }, + allowance: { + used: '0', + max: '0', + }, + open_positions: { + value: '3', + }, + is_protocol: false, + position_id_counter: { + value: '9', + }, + }, + status: 'deprecated', + whitelist: [], + }, + ], + page: '0', + total_pages: '1', + total_vaults: '3', + }, + blockHeight: 1, + }, + { + id: 'secret1qxk2scacpgj2mmm0af60674afl9e6qneg7yuny', + response: { + vaults: [ + { + vault: { + id: '1', + epoch: '0', + name: 'stkd-SCRT Vault', + collateral_addr: 'secret1k6u0cy4feepm6pehnz804zmwakuwdapm69tuc4', + safe_collateral: '31445759105000000000000', + collateral: { + elastic: '3740763561877000000000000', + base: '3740763561877000000000000', + last_accrued: '1682191940', + decimals: 6, + }, + debt: { + elastic: '700859978232000000000000', + base: '700859978232000000000000', + last_accrued: '1710952834', + decimals: 6, + }, + config: { + max_ltv: '0.5', + collateral_oracle_delay: '600', + fees: { + interest_rate: { + last_changed: '1682191940', + current: '0', + target: '0', + delta: '0.01', + rate_per_second: '0', + }, + borrow_fee: { + last_changed: '1682191940', + current: '0', + target: '0', + delta: '0.01', + rate_per_second: '0', + }, + liquidation_fee: { + discount: '0.1', + min_debt: '100000000000000000000', + treasury_share: '0.2', + caller_share: '0.1', + }, + }, + }, + allowance: { + used: '700859978232000000000000', + max: '750000000000000000000000', + }, + open_positions: { + value: '182', + }, + is_protocol: false, + position_id_counter: { + value: '389', + }, + }, + status: 'normal', + whitelist: [], + }, + { + vault: { + id: '2', + epoch: '0', + name: 'USDT Vault', + collateral_addr: 'secret1wk5j2cntwg2fgklf0uta3tlkvt87alfj7kepuw', + safe_collateral: '73431644000000000000', + collateral: { + elastic: '350148899892000000000000', + base: '350148899892000000000000', + last_accrued: '1682191940', + decimals: 6, + }, + debt: { + elastic: '227873904431360577633957', + base: '226847073546658394171419', + last_accrued: '1710952834', + decimals: 6, + }, + config: { + max_ltv: '0.85', + collateral_oracle_delay: '600', + fees: { + interest_rate: { + last_changed: '1696699251', + current: '0.01', + target: '0.01', + delta: '0.01', + rate_per_second: '0.000000000316887385', + }, + borrow_fee: { + last_changed: '1682191940', + current: '0', + target: '0', + delta: '0.01', + rate_per_second: '0', + }, + liquidation_fee: { + discount: '0.05', + min_debt: '100000000000000000000', + treasury_share: '0.2', + caller_share: '0.1', + }, + }, + }, + allowance: { + used: '226463256570000000000000', + max: '700000000000000000000000', + }, + open_positions: { + value: '15', + }, + is_protocol: false, + position_id_counter: { + value: '60', + }, + }, + status: 'normal', + whitelist: [], + }, + ], + page: '0', + total_pages: '1', + total_vaults: '3', + }, + blockHeight: 1, + }, + { + id: 'secret1wj2czeeknya2n6jag7kpfxlm28dw7q96dgqmfs', + response: { + vaults: [ + { + vault: { + id: '1', + epoch: '0', + name: 'WBTC Vault', + collateral_addr: 'secret1guyayjwg5f84daaxl7w84skd8naxvq8vz9upqx', + safe_collateral: '4026842206160691204', + collateral: { + elastic: '2114626673839308796', + base: '2114626673839308796', + last_accrued: '1710183488', + decimals: 8, + }, + debt: { + elastic: '121848577218000000000000', + base: '121848577218000000000000', + last_accrued: '1710953123', + decimals: 6, + }, + config: { + max_ltv: '0.8', + collateral_oracle_delay: '600', + fees: { + interest_rate: { + last_changed: '1710183488', + current: '0', + target: '0', + delta: '0.01', + rate_per_second: '0', + }, + borrow_fee: { + last_changed: '1710183488', + current: '0', + target: '0', + delta: '0.01', + rate_per_second: '0', + }, + liquidation_fee: { + discount: '0.1', + min_debt: '100000000000000000000', + treasury_share: '0.2', + caller_share: '0.1', + }, + }, + }, + allowance: { + used: '121848577218000000000000', + max: '150000000000000000000000', + }, + open_positions: { + value: '21', + }, + is_protocol: false, + position_id_counter: { + value: '23', + }, + }, + status: 'normal', + whitelist: [], + }, + { + vault: { + id: '2', + epoch: '0', + name: 'TIA Vault', + collateral_addr: 'secret1s9h6mrp4k9gll4zfv5h78ll68hdq8ml7jrnn20', + safe_collateral: '9360727902929305557', + collateral: { + elastic: '5699935097070694443', + base: '5699935097070694443', + last_accrued: '1710183538', + decimals: 6, + }, + debt: { + elastic: '64898575000000000000', + base: '64898575000000000000', + last_accrued: '1710953123', + decimals: 6, + }, + config: { + max_ltv: '0.55', + collateral_oracle_delay: '600', + fees: { + interest_rate: { + last_changed: '1710183538', + current: '0', + target: '0', + delta: '0.01', + rate_per_second: '0', + }, + borrow_fee: { + last_changed: '1710183538', + current: '0', + target: '0', + delta: '0.01', + rate_per_second: '0', + }, + liquidation_fee: { + discount: '0.1', + min_debt: '100000000000000000000', + treasury_share: '0.2', + caller_share: '0.1', + }, + }, + }, + allowance: { + used: '64898575000000000000', + max: '50000000000000000000000', + }, + open_positions: { + value: '2', + }, + is_protocol: false, + position_id_counter: { + value: '2', + }, + }, + status: 'normal', + whitelist: [], + }, + ], + page: '0', + total_pages: '1', + total_vaults: '3', + }, + blockHeight: 1, + }, +]; + +export { + batchVaultsResponseUnparsed, +}; diff --git a/src/test/mocks/lend/vaultV1Parsed.ts b/src/test/mocks/lend/vaultV1Parsed.ts new file mode 100644 index 0000000..e7bc166 --- /dev/null +++ b/src/test/mocks/lend/vaultV1Parsed.ts @@ -0,0 +1,156 @@ +import { + Vault, + VaultVersion, + Vaults, +} from '~/types/contracts/lend/model'; +import { LendContractStatus } from '~/types/contracts/lend/response'; + +const vaultV1Parsed: Vault = { + id: '1', + vaultVersion: VaultVersion.V1, + name: 'stkd-SCRT Vault', + collateralAddress: 'secret1k6u0cy4feepm6pehnz804zmwakuwdapm69tuc4', + silkMaxAllowance: '0', + silkAllowanceUsed: '11825.976211616265357496', + maxLtv: 0.45, + collateral: { + total: '69822.082224544587516946', + elastic: '69822.082224544587516946', + base: '69822.082224544587516946', + safe: '3076.606761056046617547', + lastAccruedAt: new Date(1681764653000), + oracleDelay: 600, + }, + debt: { + total: '12734.302492560037164766', + base: '12734.302492560037164766', + lastAccruedAt: new Date(1712346110000), + }, + interestRate: { + current: 0, + target: 0, + delta: 0.01, + ratePerSecond: 0, + lastUpdatedAt: new Date(1681764653000), + }, + borrowFee: { + current: 0, + target: 0, + delta: 0.01, + ratePerSecond: 0, + lastUpdatedAt: new Date(1681764653000), + }, + liquidationFee: { + discount: 0.1, + minimumDebt: '100', + daoShare: 0.2, + callerShare: 0.1, + }, + isProtocolOnly: false, + status: LendContractStatus.DEPRECATED, + openPositions: 32, + totalPositions: 73, + whitelist: [], +}; + +const vaultsV1Parsed: Vaults = { + 1: { + id: '1', + vaultVersion: VaultVersion.V1, + name: 'stkd-SCRT Vault', + collateralAddress: 'secret1k6u0cy4feepm6pehnz804zmwakuwdapm69tuc4', + silkMaxAllowance: '0', + silkAllowanceUsed: '11825.976211616265357496', + maxLtv: 0.45, + collateral: { + total: '69822.082224544587516946', + elastic: '69822.082224544587516946', + base: '69822.082224544587516946', + safe: '3076.606761056046617547', + lastAccruedAt: new Date(1681764653000), + oracleDelay: 600, + }, + debt: { + total: '12734.302492560037164766', + base: '12734.302492560037164766', + lastAccruedAt: new Date(1710953012000), + }, + interestRate: { + current: 0, + target: 0, + delta: 0.01, + ratePerSecond: 0, + lastUpdatedAt: new Date(1681764653000), + }, + borrowFee: { + current: 0, + target: 0, + delta: 0.01, + ratePerSecond: 0, + lastUpdatedAt: new Date(1681764653000), + }, + liquidationFee: { + discount: 0.1, + minimumDebt: '100', + daoShare: 0.2, + callerShare: 0.1, + }, + isProtocolOnly: false, + status: LendContractStatus.DEPRECATED, + openPositions: 32, + totalPositions: 73, + whitelist: [], + }, + 2: { + id: '2', + vaultVersion: VaultVersion.V1, + name: 'USDT Vault', + collateralAddress: 'secret1wk5j2cntwg2fgklf0uta3tlkvt87alfj7kepuw', + silkMaxAllowance: '0', + silkAllowanceUsed: '0', + maxLtv: 0.85, + collateral: { + total: '0', + elastic: '0', + base: '0', + safe: '0.000004653229977094', + lastAccruedAt: new Date(1681764653000), + oracleDelay: 600, + }, + debt: { + total: '0', + base: '0', + lastAccruedAt: new Date(1710953012000), + }, + interestRate: { + current: 0, + target: 0, + delta: 0.01, + ratePerSecond: 0, + lastUpdatedAt: new Date(1681764653000), + }, + borrowFee: { + current: 0, + target: 0, + delta: 0.01, + ratePerSecond: 0, + lastUpdatedAt: new Date(1681764653000), + }, + liquidationFee: { + discount: 0.05, + minimumDebt: '100', + daoShare: 0.2, + callerShare: 0.1, + }, + isProtocolOnly: false, + status: LendContractStatus.DEPRECATED, + openPositions: 3, + totalPositions: 9, + whitelist: [], + }, +}; + +export { + vaultV1Parsed, + vaultsV1Parsed, +}; diff --git a/src/test/mocks/lend/vaultV1Response.json b/src/test/mocks/lend/vaultV1Response.json new file mode 100644 index 0000000..bd40051 --- /dev/null +++ b/src/test/mocks/lend/vaultV1Response.json @@ -0,0 +1,60 @@ +{ + "vault": { + "id": "1", + "epoch": "0", + "name": "stkd-SCRT Vault", + "collateral_addr": "secret1k6u0cy4feepm6pehnz804zmwakuwdapm69tuc4", + "safe_collateral": "3076606761056046617547", + "collateral": { + "elastic": "69822082224544587516946", + "base": "69822082224544587516946", + "last_accrued": "1681764653" + }, + "debt": { + "elastic": "12734302492560037164766", + "base": "12734302492560037164766", + "last_accrued": "1712346110" + }, + "config": { + "max_ltv": "0.45", + "collateral_oracle_delay": "600", + "fees": { + "interest_rate": { + "last_changed": "1681764653", + "current": "0", + "target": "0", + "minimum_fee_update_interval": "1681764653", + "delta": "0.01", + "rate_per_second": "0" + }, + "borrow_fee": { + "last_changed": "1681764653", + "current": "0", + "target": "0", + "minimum_fee_update_interval": "1681764653", + "delta": "0.01", + "rate_per_second": "0" + }, + "liquidation_fee": { + "discount": "0.1", + "min_debt": "100000000000000000000", + "treasury_share": "0.2", + "caller_share": "0.1" + } + } + }, + "allowance": { + "used": "11825976211616265357496", + "max": "0" + }, + "open_positions": { + "value": "32" + }, + "is_protocol": false, + "position_id_counter": { + "value": "73" + } + }, + "status": "deprecated", + "whitelist": [] +} diff --git a/src/test/mocks/lend/vaultV2Parsed.ts b/src/test/mocks/lend/vaultV2Parsed.ts new file mode 100644 index 0000000..6d5da1f --- /dev/null +++ b/src/test/mocks/lend/vaultV2Parsed.ts @@ -0,0 +1,156 @@ +import { + Vault, + Vaults, + VaultVersion, +} from '~/types/contracts/lend/model'; +import { LendContractStatus } from '~/types/contracts/lend/response'; + +const vaultV2Parsed: Vault = { + id: '1', + vaultVersion: VaultVersion.V2, + name: 'stkd-SCRT Vault', + collateralAddress: 'secret1k6u0cy4feepm6pehnz804zmwakuwdapm69tuc4', + silkMaxAllowance: '850000', + silkAllowanceUsed: '696262.021091', + maxLtv: 0.5, + collateral: { + total: '3689766.59451', + elastic: '3689766.59451', + base: '3689766.59451', + safe: '31325.698319', + lastAccruedAt: new Date(1682191940000), + oracleDelay: 600, + }, + debt: { + total: '696262.021091', + base: '696262.021091', + lastAccruedAt: new Date(1712343614000), + }, + interestRate: { + current: 0, + target: 0, + delta: 0.01, + ratePerSecond: 0, + lastUpdatedAt: new Date(1682191940000), + }, + borrowFee: { + current: 0, + target: 0, + delta: 0.01, + ratePerSecond: 0, + lastUpdatedAt: new Date(1682191940000), + }, + liquidationFee: { + discount: 0.1, + minimumDebt: '100', + daoShare: 0.2, + callerShare: 0.1, + }, + isProtocolOnly: false, + status: LendContractStatus.NORMAL, + openPositions: 183, + totalPositions: 403, + whitelist: [], +}; + +const vaultsV2Parsed: Vaults = { + 1: { + id: '1', + vaultVersion: VaultVersion.V2, + name: 'stkd-SCRT Vault', + collateralAddress: 'secret1k6u0cy4feepm6pehnz804zmwakuwdapm69tuc4', + silkMaxAllowance: '750000', + silkAllowanceUsed: '700859.978232', + maxLtv: 0.5, + collateral: { + total: '3740763.561877', + elastic: '3740763.561877', + base: '3740763.561877', + safe: '31445.759105', + lastAccruedAt: new Date(1682191940000), + oracleDelay: 600, + }, + debt: { + total: '700859.978232', + base: '700859.978232', + lastAccruedAt: new Date(1710952834000), + }, + interestRate: { + current: 0, + target: 0, + delta: 0.01, + ratePerSecond: 0, + lastUpdatedAt: new Date(1682191940000), + }, + borrowFee: { + current: 0, + target: 0, + delta: 0.01, + ratePerSecond: 0, + lastUpdatedAt: new Date(1682191940000), + }, + liquidationFee: { + discount: 0.1, + minimumDebt: '100', + daoShare: 0.2, + callerShare: 0.1, + }, + isProtocolOnly: false, + status: LendContractStatus.NORMAL, + openPositions: 182, + totalPositions: 389, + whitelist: [], + }, + 2: { + id: '2', + vaultVersion: VaultVersion.V2, + name: 'USDT Vault', + collateralAddress: 'secret1wk5j2cntwg2fgklf0uta3tlkvt87alfj7kepuw', + silkMaxAllowance: '700000', + silkAllowanceUsed: '226463.25657', + maxLtv: 0.85, + collateral: { + total: '350148.899892', + elastic: '350148.899892', + base: '350148.899892', + safe: '73.431644', + lastAccruedAt: new Date(1682191940000), + oracleDelay: 600, + }, + debt: { + total: '227873.904431360577633957', + base: '226847.073546658394171419', + lastAccruedAt: new Date(1710952834000), + }, + interestRate: { + current: 0.01, + target: 0.01, + delta: 0.01, + ratePerSecond: 0.000000000316887385, + lastUpdatedAt: new Date(1696699251000), + }, + borrowFee: { + current: 0, + target: 0, + delta: 0.01, + ratePerSecond: 0, + lastUpdatedAt: new Date(1682191940000), + }, + liquidationFee: { + discount: 0.05, + minimumDebt: '100', + daoShare: 0.2, + callerShare: 0.1, + }, + isProtocolOnly: false, + status: LendContractStatus.NORMAL, + openPositions: 15, + totalPositions: 60, + whitelist: [], + }, +}; + +export { + vaultV2Parsed, + vaultsV2Parsed, +}; diff --git a/src/test/mocks/lend/vaultV2Response.json b/src/test/mocks/lend/vaultV2Response.json new file mode 100644 index 0000000..58bf006 --- /dev/null +++ b/src/test/mocks/lend/vaultV2Response.json @@ -0,0 +1,60 @@ +{ + "vault": { + "id": "1", + "epoch": "0", + "name": "stkd-SCRT Vault", + "collateral_addr": "secret1k6u0cy4feepm6pehnz804zmwakuwdapm69tuc4", + "safe_collateral": "31325698319000000000000", + "collateral": { + "elastic": "3689766594510000000000000", + "base": "3689766594510000000000000", + "last_accrued": "1682191940", + "decimals": 6 + }, + "debt": { + "elastic": "696262021091000000000000", + "base": "696262021091000000000000", + "last_accrued": "1712343614", + "decimals": 6 + }, + "config": { + "max_ltv": "0.5", + "collateral_oracle_delay": "600", + "fees": { + "interest_rate": { + "last_changed": "1682191940", + "current": "0", + "target": "0", + "delta": "0.01", + "rate_per_second": "0" + }, + "borrow_fee": { + "last_changed": "1682191940", + "current": "0", + "target": "0", + "delta": "0.01", + "rate_per_second": "0" + }, + "liquidation_fee": { + "discount": "0.1", + "min_debt": "100000000000000000000", + "treasury_share": "0.2", + "caller_share": "0.1" + } + } + }, + "allowance": { + "used": "696262021091000000000000", + "max": "850000000000000000000000" + }, + "open_positions": { + "value": "183" + }, + "is_protocol": false, + "position_id_counter": { + "value": "403" + } + }, + "status": "normal", + "whitelist": [] +} diff --git a/src/test/mocks/lend/vaultV3Parsed.ts b/src/test/mocks/lend/vaultV3Parsed.ts new file mode 100644 index 0000000..33a8e54 --- /dev/null +++ b/src/test/mocks/lend/vaultV3Parsed.ts @@ -0,0 +1,156 @@ +import { + Vault, + Vaults, + VaultVersion, +} from '~/types/contracts/lend/model'; +import { LendContractStatus } from '~/types/contracts/lend/response'; + +const vaultV3Parsed: Vault = { + id: '1', + vaultVersion: VaultVersion.V3, + name: 'WBTC Vault', + collateralAddress: 'secret1guyayjwg5f84daaxl7w84skd8naxvq8vz9upqx', + silkMaxAllowance: '300000', + silkAllowanceUsed: '143845.576549', + maxLtv: 0.8, + collateral: { + total: '6.25687611', + elastic: '2.438346496108978355', + base: '2.438346496108978355', + safe: '3.818529613891021645', + lastAccruedAt: new Date(1710183488000), + oracleDelay: 600, + }, + debt: { + total: '143845.576549', + base: '143845.576549', + lastAccruedAt: new Date(1712343800000), + }, + interestRate: { + current: 0, + target: 0, + delta: 0.01, + ratePerSecond: 0, + lastUpdatedAt: new Date(1710183488000), + }, + borrowFee: { + current: 0, + target: 0, + delta: 0.01, + ratePerSecond: 0, + lastUpdatedAt: new Date(1710183488000), + }, + liquidationFee: { + discount: 0.1, + minimumDebt: '100', + daoShare: 0.2, + callerShare: 0.1, + }, + isProtocolOnly: false, + status: LendContractStatus.NORMAL, + openPositions: 20, + totalPositions: 27, + whitelist: [], +}; + +const vaultsV3Parsed: Vaults = { + 1: { + id: '1', + vaultVersion: VaultVersion.V3, + name: 'WBTC Vault', + collateralAddress: 'secret1guyayjwg5f84daaxl7w84skd8naxvq8vz9upqx', + silkMaxAllowance: '150000', + silkAllowanceUsed: '121848.577218', + maxLtv: 0.8, + collateral: { + total: '6.14146888', + elastic: '2.114626673839308796', + base: '2.114626673839308796', + safe: '4.026842206160691204', + lastAccruedAt: new Date(1710183488000), + oracleDelay: 600, + }, + debt: { + total: '121848.577218', + base: '121848.577218', + lastAccruedAt: new Date(1710953123000), + }, + interestRate: { + current: 0, + target: 0, + delta: 0.01, + ratePerSecond: 0, + lastUpdatedAt: new Date(1710183488000), + }, + borrowFee: { + current: 0, + target: 0, + delta: 0.01, + ratePerSecond: 0, + lastUpdatedAt: new Date(1710183488000), + }, + liquidationFee: { + discount: 0.1, + minimumDebt: '100', + daoShare: 0.2, + callerShare: 0.1, + }, + isProtocolOnly: false, + status: LendContractStatus.NORMAL, + openPositions: 21, + totalPositions: 23, + whitelist: [], + }, + 2: { + id: '2', + vaultVersion: VaultVersion.V3, + name: 'TIA Vault', + collateralAddress: 'secret1s9h6mrp4k9gll4zfv5h78ll68hdq8ml7jrnn20', + silkMaxAllowance: '50000', + silkAllowanceUsed: '64.898575', + maxLtv: 0.55, + collateral: { + total: '15.060663', + elastic: '5.699935097070694443', + base: '5.699935097070694443', + safe: '9.360727902929305557', + lastAccruedAt: new Date(1710183538000), + oracleDelay: 600, + }, + debt: { + total: '64.898575', + base: '64.898575', + lastAccruedAt: new Date(1710953123000), + }, + interestRate: { + current: 0, + target: 0, + delta: 0.01, + ratePerSecond: 0, + lastUpdatedAt: new Date(1710183538000), + }, + borrowFee: { + current: 0, + target: 0, + delta: 0.01, + ratePerSecond: 0, + lastUpdatedAt: new Date(1710183538000), + }, + liquidationFee: { + discount: 0.1, + minimumDebt: '100', + daoShare: 0.2, + callerShare: 0.1, + }, + isProtocolOnly: false, + status: LendContractStatus.NORMAL, + openPositions: 2, + totalPositions: 2, + whitelist: [], + }, +}; + +export { + vaultV3Parsed, + vaultsV3Parsed, +}; diff --git a/src/test/mocks/lend/vaultV3Response.json b/src/test/mocks/lend/vaultV3Response.json new file mode 100644 index 0000000..9a4602a --- /dev/null +++ b/src/test/mocks/lend/vaultV3Response.json @@ -0,0 +1,60 @@ +{ + "vault": { + "id": "1", + "epoch": "0", + "name": "WBTC Vault", + "collateral_addr": "secret1guyayjwg5f84daaxl7w84skd8naxvq8vz9upqx", + "safe_collateral": "3818529613891021645", + "collateral": { + "elastic": "2438346496108978355", + "base": "2438346496108978355", + "last_accrued": "1710183488", + "decimals": 8 + }, + "debt": { + "elastic": "143845576549000000000000", + "base": "143845576549000000000000", + "last_accrued": "1712343800", + "decimals": 6 + }, + "config": { + "max_ltv": "0.8", + "collateral_oracle_delay": "600", + "fees": { + "interest_rate": { + "last_changed": "1710183488", + "current": "0", + "target": "0", + "delta": "0.01", + "rate_per_second": "0" + }, + "borrow_fee": { + "last_changed": "1710183488", + "current": "0", + "target": "0", + "delta": "0.01", + "rate_per_second": "0" + }, + "liquidation_fee": { + "discount": "0.1", + "min_debt": "100000000000000000000", + "treasury_share": "0.2", + "caller_share": "0.1" + } + } + }, + "allowance": { + "used": "143845576549000000000000", + "max": "300000000000000000000000" + }, + "open_positions": { + "value": "20" + }, + "is_protocol": false, + "position_id_counter": { + "value": "27" + } + }, + "status": "normal", + "whitelist": [] +} diff --git a/src/test/mocks/lend/vaultsV1Response.json b/src/test/mocks/lend/vaultsV1Response.json new file mode 100644 index 0000000..75e88a8 --- /dev/null +++ b/src/test/mocks/lend/vaultsV1Response.json @@ -0,0 +1,127 @@ +{ + "vaults": [ + { + "vault": { + "id": "1", + "epoch": "0", + "name": "stkd-SCRT Vault", + "collateral_addr": "secret1k6u0cy4feepm6pehnz804zmwakuwdapm69tuc4", + "safe_collateral": "3076606761056046617547", + "collateral": { + "elastic": "69822082224544587516946", + "base": "69822082224544587516946", + "last_accrued": "1681764653" + }, + "debt": { + "elastic": "12734302492560037164766", + "base": "12734302492560037164766", + "last_accrued": "1710953012" + }, + "config": { + "max_ltv": "0.45", + "collateral_oracle_delay": "600", + "fees": { + "interest_rate": { + "last_changed": "1681764653", + "current": "0", + "target": "0", + "minimum_fee_update_interval": "1681764653", + "delta": "0.01", + "rate_per_second": "0" + }, + "borrow_fee": { + "last_changed": "1681764653", + "current": "0", + "target": "0", + "minimum_fee_update_interval": "1681764653", + "delta": "0.01", + "rate_per_second": "0" + }, + "liquidation_fee": { + "discount": "0.1", + "min_debt": "100000000000000000000", + "treasury_share": "0.2", + "caller_share": "0.1" + } + } + }, + "allowance": { + "used": "11825976211616265357496", + "max": "0" + }, + "open_positions": { + "value": "32" + }, + "is_protocol": false, + "position_id_counter": { + "value": "73" + } + }, + "status": "deprecated", + "whitelist": [] + }, + { + "vault": { + "id": "2", + "epoch": "0", + "name": "USDT Vault", + "collateral_addr": "secret1wk5j2cntwg2fgklf0uta3tlkvt87alfj7kepuw", + "safe_collateral": "4653229977094", + "collateral": { + "elastic": "0", + "base": "0", + "last_accrued": "1681764653" + }, + "debt": { + "elastic": "0", + "base": "0", + "last_accrued": "1710953012" + }, + "config": { + "max_ltv": "0.85", + "collateral_oracle_delay": "600", + "fees": { + "interest_rate": { + "last_changed": "1681764653", + "current": "0", + "target": "0", + "minimum_fee_update_interval": "1681764653", + "delta": "0.01", + "rate_per_second": "0" + }, + "borrow_fee": { + "last_changed": "1681764653", + "current": "0", + "target": "0", + "minimum_fee_update_interval": "1681764653", + "delta": "0.01", + "rate_per_second": "0" + }, + "liquidation_fee": { + "discount": "0.05", + "min_debt": "100000000000000000000", + "treasury_share": "0.2", + "caller_share": "0.1" + } + } + }, + "allowance": { + "used": "0", + "max": "0" + }, + "open_positions": { + "value": "3" + }, + "is_protocol": false, + "position_id_counter": { + "value": "9" + } + }, + "status": "deprecated", + "whitelist": [] + } + ], + "page": "0", + "total_pages": "1", + "total_vaults": "3" +} diff --git a/src/test/mocks/lend/vaultsV2Response.json b/src/test/mocks/lend/vaultsV2Response.json new file mode 100644 index 0000000..d451b19 --- /dev/null +++ b/src/test/mocks/lend/vaultsV2Response.json @@ -0,0 +1,127 @@ +{ + "vaults": [ + { + "vault": { + "id": "1", + "epoch": "0", + "name": "stkd-SCRT Vault", + "collateral_addr": "secret1k6u0cy4feepm6pehnz804zmwakuwdapm69tuc4", + "safe_collateral": "31445759105000000000000", + "collateral": { + "elastic": "3740763561877000000000000", + "base": "3740763561877000000000000", + "last_accrued": "1682191940", + "decimals": 6 + }, + "debt": { + "elastic": "700859978232000000000000", + "base": "700859978232000000000000", + "last_accrued": "1710952834", + "decimals": 6 + }, + "config": { + "max_ltv": "0.5", + "collateral_oracle_delay": "600", + "fees": { + "interest_rate": { + "last_changed": "1682191940", + "current": "0", + "target": "0", + "delta": "0.01", + "rate_per_second": "0" + }, + "borrow_fee": { + "last_changed": "1682191940", + "current": "0", + "target": "0", + "delta": "0.01", + "rate_per_second": "0" + }, + "liquidation_fee": { + "discount": "0.1", + "min_debt": "100000000000000000000", + "treasury_share": "0.2", + "caller_share": "0.1" + } + } + }, + "allowance": { + "used": "700859978232000000000000", + "max": "750000000000000000000000" + }, + "open_positions": { + "value": "182" + }, + "is_protocol": false, + "position_id_counter": { + "value": "389" + } + }, + "status": "normal", + "whitelist": [] + }, + { + "vault": { + "id": "2", + "epoch": "0", + "name": "USDT Vault", + "collateral_addr": "secret1wk5j2cntwg2fgklf0uta3tlkvt87alfj7kepuw", + "safe_collateral": "73431644000000000000", + "collateral": { + "elastic": "350148899892000000000000", + "base": "350148899892000000000000", + "last_accrued": "1682191940", + "decimals": 6 + }, + "debt": { + "elastic": "227873904431360577633957", + "base": "226847073546658394171419", + "last_accrued": "1710952834", + "decimals": 6 + }, + "config": { + "max_ltv": "0.85", + "collateral_oracle_delay": "600", + "fees": { + "interest_rate": { + "last_changed": "1696699251", + "current": "0.01", + "target": "0.01", + "delta": "0.01", + "rate_per_second": "0.000000000316887385" + }, + "borrow_fee": { + "last_changed": "1682191940", + "current": "0", + "target": "0", + "delta": "0.01", + "rate_per_second": "0" + }, + "liquidation_fee": { + "discount": "0.05", + "min_debt": "100000000000000000000", + "treasury_share": "0.2", + "caller_share": "0.1" + } + } + }, + "allowance": { + "used": "226463256570000000000000", + "max": "700000000000000000000000" + }, + "open_positions": { + "value": "15" + }, + "is_protocol": false, + "position_id_counter": { + "value": "60" + } + }, + "status": "normal", + "whitelist": [] + } + ], + "page": "0", + "total_pages": "1", + "total_vaults": "3" +} diff --git a/src/test/mocks/lend/vaultsV3Response.json b/src/test/mocks/lend/vaultsV3Response.json new file mode 100644 index 0000000..07f5480 --- /dev/null +++ b/src/test/mocks/lend/vaultsV3Response.json @@ -0,0 +1,127 @@ +{ + "vaults": [ + { + "vault": { + "id": "1", + "epoch": "0", + "name": "WBTC Vault", + "collateral_addr": "secret1guyayjwg5f84daaxl7w84skd8naxvq8vz9upqx", + "safe_collateral": "4026842206160691204", + "collateral": { + "elastic": "2114626673839308796", + "base": "2114626673839308796", + "last_accrued": "1710183488", + "decimals": 8 + }, + "debt": { + "elastic": "121848577218000000000000", + "base": "121848577218000000000000", + "last_accrued": "1710953123", + "decimals": 6 + }, + "config": { + "max_ltv": "0.8", + "collateral_oracle_delay": "600", + "fees": { + "interest_rate": { + "last_changed": "1710183488", + "current": "0", + "target": "0", + "delta": "0.01", + "rate_per_second": "0" + }, + "borrow_fee": { + "last_changed": "1710183488", + "current": "0", + "target": "0", + "delta": "0.01", + "rate_per_second": "0" + }, + "liquidation_fee": { + "discount": "0.1", + "min_debt": "100000000000000000000", + "treasury_share": "0.2", + "caller_share": "0.1" + } + } + }, + "allowance": { + "used": "121848577218000000000000", + "max": "150000000000000000000000" + }, + "open_positions": { + "value": "21" + }, + "is_protocol": false, + "position_id_counter": { + "value": "23" + } + }, + "status": "normal", + "whitelist": [] + }, + { + "vault": { + "id": "2", + "epoch": "0", + "name": "TIA Vault", + "collateral_addr": "secret1s9h6mrp4k9gll4zfv5h78ll68hdq8ml7jrnn20", + "safe_collateral": "9360727902929305557", + "collateral": { + "elastic": "5699935097070694443", + "base": "5699935097070694443", + "last_accrued": "1710183538", + "decimals": 6 + }, + "debt": { + "elastic": "64898575000000000000", + "base": "64898575000000000000", + "last_accrued": "1710953123", + "decimals": 6 + }, + "config": { + "max_ltv": "0.55", + "collateral_oracle_delay": "600", + "fees": { + "interest_rate": { + "last_changed": "1710183538", + "current": "0", + "target": "0", + "delta": "0.01", + "rate_per_second": "0" + }, + "borrow_fee": { + "last_changed": "1710183538", + "current": "0", + "target": "0", + "delta": "0.01", + "rate_per_second": "0" + }, + "liquidation_fee": { + "discount": "0.1", + "min_debt": "100000000000000000000", + "treasury_share": "0.2", + "caller_share": "0.1" + } + } + }, + "allowance": { + "used": "64898575000000000000", + "max": "50000000000000000000000" + }, + "open_positions": { + "value": "2" + }, + "is_protocol": false, + "position_id_counter": { + "value": "2" + } + }, + "status": "normal", + "whitelist": [] + } + ], + "page": "0", + "total_pages": "1", + "total_vaults": "3" +} diff --git a/src/types/contracts/index.ts b/src/types/contracts/index.ts index e57606d..420c06d 100644 --- a/src/types/contracts/index.ts +++ b/src/types/contracts/index.ts @@ -6,3 +6,4 @@ export * from './swap'; export * from './derivativeScrt'; export * from './derivativeShd'; export * from './shadeStaking'; +export * from './lend'; diff --git a/src/types/contracts/lend/index.ts b/src/types/contracts/lend/index.ts new file mode 100644 index 0000000..ed9aa71 --- /dev/null +++ b/src/types/contracts/lend/index.ts @@ -0,0 +1,2 @@ +export * from './model'; +export * from './response'; diff --git a/src/types/contracts/lend/model.ts b/src/types/contracts/lend/model.ts new file mode 100644 index 0000000..654639a --- /dev/null +++ b/src/types/contracts/lend/model.ts @@ -0,0 +1,84 @@ +import { LendContractStatus } from './response'; + +enum VaultVersion { + V1 = 'v1', + V2 = 'v2', + V3 = 'v3', +} + +type Vault = { + id: string, + vaultVersion: VaultVersion, + name: string, + collateralAddress: string, + silkMaxAllowance: string, + silkAllowanceUsed: string, + maxLtv: number, + collateral: { + total: string, + elastic: string, + base: string, + safe: string, + lastAccruedAt: Date, + oracleDelay: number, + }, + debt: { + total: string, // aka "elastic" + base: string, + lastAccruedAt: Date, + } + interestRate: { + current: number, + target: number, + delta: number, + ratePerSecond: number, + lastUpdatedAt: Date, + }, + borrowFee: { + current: number, + target: number, + delta: number, + ratePerSecond: number, + lastUpdatedAt: Date, + }, + liquidationFee: { + discount: number, + minimumDebt: string, + daoShare: number, + callerShare: number + } + isProtocolOnly: boolean, + status: LendContractStatus, + openPositions: number, + totalPositions: number, + whitelist: string[], +} + +type Vaults = { + [id: string]: Vault, +} + +type BatchVaultsItem = { + vaultRegistryContractAddress: string, + vaults: Vaults, + blockHeight: number, +} + +type BatchVaults = BatchVaultsItem[] + +type LendVaultRegistryContract = { + address: string, + codeHash: string, + vaultVersion: VaultVersion, +}; + +export type { + BatchVaults, + Vault, + Vaults, + LendVaultRegistryContract, +}; + +export { + VaultVersion, +}; diff --git a/src/types/contracts/lend/response.ts b/src/types/contracts/lend/response.ts new file mode 100644 index 0000000..563416b --- /dev/null +++ b/src/types/contracts/lend/response.ts @@ -0,0 +1,88 @@ +enum NormalizationFactor { + LEND = 18, + LEND_BORROW_FEE = 16, +} + +type Counter = { + value: string, +} + +enum LendContractStatus { + NORMAL = 'normal', + DEPRECATED = 'deprecated', + FROZEN = 'frozen' +} + +type VaultResponse = { + vault: { + id: string, + name: string, + collateral_addr: string, + safe_collateral: string, + collateral: { + elastic: string, + base: string, + last_accrued: string, + decimals?: number, // not included in Vault V1 + }, + debt: { + elastic: string, + base: string, + last_accrued: string, + decimals?: number, // not included in Vault V1 + }, + config: { + max_ltv: string, + collateral_oracle_delay: string, + fees: { + interest_rate: { + last_changed: string, + current: string, + target: string, + delta: string, + rate_per_second: string, + minimum_fee_update_interval?: string // V1 only + }, + borrow_fee: { + last_changed: string, + current: string, + target: string, + delta: string, + rate_per_second: string, + minimum_fee_update_interval?: string // V1 only + }, + liquidation_fee: { + discount: string, + min_debt: string, + treasury_share: string, + caller_share: string, + }, + }, + }, + allowance: { + used: string, + max: string, + }, + position_id_counter: Counter, + open_positions: Counter, + is_protocol: boolean, + }, + status: LendContractStatus, + whitelist: string[], +} + +type VaultsResponse = { + vaults: VaultResponse[], + page: string, + total_pages: string, + total_vaults: string, +} + +export type { + VaultsResponse, + VaultResponse, +}; +export { + NormalizationFactor, + LendContractStatus, +};