diff --git a/.env.example b/.env.example index 381e757c..33138989 100644 --- a/.env.example +++ b/.env.example @@ -42,5 +42,5 @@ NEXT_PUBLIC_MAINNET_REST=https://osmosis-node.marsprotocol.io/GGSFGSFGFG34/osmos # CHARTING_LIBRARY_USERNAME="username_with_access_to_charting_library" # CHARTING_LIBRARY_ACCESS_TOKEN="access_token_with_access_to_charting_library" # CHARTING_LIBRARY_REPOSITORY="username/charting_library" -# NEXT_PUBLIC_PYTH_ENDPOINT=https://xc-mainnet.pyth.network/api/ +# NEXT_PUBLIC_PYTH_ENDPOINT=https://xc-mainnet.pyth.network/api # NEXT_PUBLIC_MAINNET_REST=https://osmosis-node.marsprotocol.io/GGSFGSFGFG34/osmosis-lcd-front/ diff --git a/src/api/cosmwasm-client.ts b/src/api/cosmwasm-client.ts index 52ce9f42..1880dac5 100644 --- a/src/api/cosmwasm-client.ts +++ b/src/api/cosmwasm-client.ts @@ -4,7 +4,7 @@ import { ENV } from 'constants/env' import { MarsAccountNftQueryClient } from 'types/generated/mars-account-nft/MarsAccountNft.client' import { MarsCreditManagerQueryClient } from 'types/generated/mars-credit-manager/MarsCreditManager.client' import { MarsIncentivesQueryClient } from 'types/generated/mars-incentives/MarsIncentives.client' -import { MarsMockOracleQueryClient } from 'types/generated/mars-mock-oracle/MarsMockOracle.client' +import { MarsOracleOsmosisQueryClient } from 'types/generated/mars-oracle-osmosis/MarsOracleOsmosis.client' import { MarsMockRedBankQueryClient } from 'types/generated/mars-mock-red-bank/MarsMockRedBank.client' import { MarsMockVaultQueryClient } from 'types/generated/mars-mock-vault/MarsMockVault.client' import { MarsParamsQueryClient } from 'types/generated/mars-params/MarsParams.client' @@ -12,7 +12,7 @@ import { MarsParamsQueryClient } from 'types/generated/mars-params/MarsParams.cl let _cosmWasmClient: CosmWasmClient let _accountNftQueryClient: MarsAccountNftQueryClient let _creditManagerQueryClient: MarsCreditManagerQueryClient -let _oracleQueryClient: MarsMockOracleQueryClient +let _oracleQueryClient: MarsOracleOsmosisQueryClient let _redBankQueryClient: MarsMockRedBankQueryClient let _paramsQueryClient: MarsParamsQueryClient let _incentivesQueryClient: MarsIncentivesQueryClient @@ -75,7 +75,7 @@ const getOracleQueryClient = async () => { try { if (!_oracleQueryClient) { const client = await getClient() - _oracleQueryClient = new MarsMockOracleQueryClient(client, ENV.ADDRESS_ORACLE) + _oracleQueryClient = new MarsOracleOsmosisQueryClient(client, ENV.ADDRESS_ORACLE) } return _oracleQueryClient diff --git a/src/api/incentives/calculateAssetIncentivesApy.ts b/src/api/incentives/calculateAssetIncentivesApy.ts index f4fdda46..a4adfcf2 100644 --- a/src/api/incentives/calculateAssetIncentivesApy.ts +++ b/src/api/incentives/calculateAssetIncentivesApy.ts @@ -6,7 +6,7 @@ import { SECONDS_IN_A_YEAR } from 'utils/constants' import getPrice from 'api/prices/getPrice' import getMarsPrice from 'api/prices/getMarsPrice' import { ASSETS } from 'constants/assets' -import { byDenom } from 'utils/array' +import { byDenom, bySymbol } from 'utils/array' export default async function calculateAssetIncentivesApy( denom: string, @@ -16,17 +16,15 @@ export default async function calculateAssetIncentivesApy( if (!assetIncentive) return null - const [marketLiquidityAmount, assetPriceResponse, marsPrice] = await Promise.all([ + const [marketLiquidityAmount, assetPrice, marsPrice] = await Promise.all([ getUnderlyingLiquidityAmount(market), getPrice(denom), getMarsPrice(), ]) const assetDecimals = (ASSETS.find(byDenom(denom)) as Asset).decimals - const marsDecimals = 6, - priceFeedDecimals = 6 + const marsDecimals = (ASSETS.find(bySymbol('MARS')) as Asset).decimals - const assetPrice = BN(assetPriceResponse).shiftedBy(assetDecimals - priceFeedDecimals) const marketLiquidityValue = BN(marketLiquidityAmount) .shiftedBy(-assetDecimals) .multipliedBy(assetPrice) diff --git a/src/api/markets/getMarket.ts b/src/api/markets/getMarket.ts index eddbcd93..cab1e272 100644 --- a/src/api/markets/getMarket.ts +++ b/src/api/markets/getMarket.ts @@ -1,6 +1,5 @@ -import { ENV } from 'constants/env' import { resolveMarketResponse } from 'utils/resolvers' -import { getClient, getRedBankQueryClient } from 'api/cosmwasm-client' +import { getRedBankQueryClient } from 'api/cosmwasm-client' export default async function getMarket(denom: string): Promise { try { diff --git a/src/api/markets/getMarkets.ts b/src/api/markets/getMarkets.ts index f22b1d8c..50105408 100644 --- a/src/api/markets/getMarkets.ts +++ b/src/api/markets/getMarkets.ts @@ -1,12 +1,20 @@ import { getEnabledMarketAssets } from 'utils/assets' -import getMarket from 'api/markets/getMarket' +import { getRedBankQueryClient } from 'api/cosmwasm-client' +import iterateContractQuery from 'utils/iterateContractQuery' +import { byDenom } from 'utils/array' +import { resolveMarketResponse } from 'utils/resolvers' +import { Market as RedBankMarket } from 'types/generated/mars-mock-red-bank/MarsMockRedBank.types' export default async function getMarkets(): Promise { try { + const client = await getRedBankQueryClient() const enabledAssets = getEnabledMarketAssets() - const marketQueries = enabledAssets.map((asset) => getMarket(asset.denom)) - return await Promise.all(marketQueries) + const markets = await iterateContractQuery(client.markets) + + return enabledAssets.map((asset) => + resolveMarketResponse(markets.find(byDenom(asset.denom)) as RedBankMarket), + ) } catch (ex) { throw ex } diff --git a/src/api/prices/getOraclePrices.ts b/src/api/prices/getOraclePrices.ts index 81c605d7..ef6529b2 100644 --- a/src/api/prices/getOraclePrices.ts +++ b/src/api/prices/getOraclePrices.ts @@ -1,22 +1,26 @@ import { getOracleQueryClient } from 'api/cosmwasm-client' +import { PRICE_ORACLE_DECIMALS } from 'constants/query' import { BNCoin } from 'types/classes/BNCoin' +import { PriceResponse } from 'types/generated/mars-oracle-osmosis/MarsOracleOsmosis.types' +import { byDenom } from 'utils/array' import { BN } from 'utils/helpers' +import iterateContractQuery from 'utils/iterateContractQuery' export default async function getOraclePrices(...assets: Asset[]): Promise { try { - const baseDecimals = 6 + if (!assets.length) return [] + const oracleQueryClient = await getOracleQueryClient() + const priceResults = await iterateContractQuery(oracleQueryClient.prices) - const priceQueries = assets.map((asset) => - oracleQueryClient.price({ - denom: asset.denom, - }), - ) - const priceResults = await Promise.all(priceQueries) + return assets.map((asset) => { + const priceResponse = priceResults.find(byDenom(asset.denom)) as PriceResponse + const decimalDiff = asset.decimals - PRICE_ORACLE_DECIMALS - return priceResults.map(({ denom, price }, index) => { - const decimalDiff = assets[index].decimals - baseDecimals - return BNCoin.fromDenomAndBigNumber(denom, BN(price).shiftedBy(decimalDiff)) + return BNCoin.fromDenomAndBigNumber( + asset.denom, + BN(priceResponse.price).shiftedBy(decimalDiff), + ) }) } catch (ex) { throw ex diff --git a/src/api/prices/getPrice.ts b/src/api/prices/getPrice.ts index 9da888b2..599f5c39 100644 --- a/src/api/prices/getPrice.ts +++ b/src/api/prices/getPrice.ts @@ -4,6 +4,7 @@ import { byDenom } from 'utils/array' import getPythPrice from 'api/prices/getPythPrices' import getPoolPrice from 'api/prices/getPoolPrice' import { BN } from 'utils/helpers' +import { PRICE_ORACLE_DECIMALS } from 'constants/query' export default async function getPrice(denom: string): Promise { try { @@ -16,8 +17,9 @@ export default async function getPrice(denom: string): Promise { if (asset.hasOraclePrice) { const oracleQueryClient = await getOracleQueryClient() const priceResponse = await oracleQueryClient.price({ denom: asset.denom }) + const decimalDiff = asset.decimals - PRICE_ORACLE_DECIMALS - return BN(priceResponse.price) + return BN(priceResponse.price).shiftedBy(decimalDiff) } if (asset.poolId) { diff --git a/src/api/vaults/getVaultConfigs.ts b/src/api/vaults/getVaultConfigs.ts index 62946b14..2604b372 100644 --- a/src/api/vaults/getVaultConfigs.ts +++ b/src/api/vaults/getVaultConfigs.ts @@ -1,27 +1,13 @@ import { getParamsQueryClient } from 'api/cosmwasm-client' -import { ENV } from 'constants/env' -import { VaultConfigBaseForString } from 'types/generated/mars-params/MarsParams.types' +import { VaultConfigBaseForAddr } from 'types/generated/mars-params/MarsParams.types' +import iterateContractQuery from 'utils/iterateContractQuery' -export const getVaultConfigs = async ( - vaultConfigs: VaultConfigBaseForString[], - startAfter?: string, -): Promise => { - if (!ENV.ADDRESS_PARAMS) return [] - const paramsQueryClient = await getParamsQueryClient() +export const getVaultConfigs = async (): Promise => { try { - const batch = await paramsQueryClient.allVaultConfigs({ - limit: 4, - startAfter, - }) - - vaultConfigs.push(...batch) - - if (batch.length === 4) { - return await getVaultConfigs(vaultConfigs, batch[batch.length - 1].addr) - } - - return vaultConfigs - } catch { - return vaultConfigs + const paramsQueryClient = await getParamsQueryClient() + return await iterateContractQuery(paramsQueryClient.allVaultConfigs, 'addr') + } catch (ex) { + console.error(ex) + throw ex } } diff --git a/src/api/vaults/getVaults.ts b/src/api/vaults/getVaults.ts index 4e4814ed..ea03d5ca 100644 --- a/src/api/vaults/getVaults.ts +++ b/src/api/vaults/getVaults.ts @@ -7,7 +7,7 @@ import { TESTNET_VAULTS_META_DATA, VAULTS_META_DATA } from 'constants/vaults' import { BN } from 'utils/helpers' export default async function getVaults(): Promise { - const vaultConfigs = await getVaultConfigs([]) + const vaultConfigs = await getVaultConfigs() const $vaultUtilizations = getVaultUtilizations(vaultConfigs) const $aprs = getAprs() const vaultMetaDatas = ENV.NETWORK === 'testnet' ? TESTNET_VAULTS_META_DATA : VAULTS_META_DATA diff --git a/src/components/TermsOfService.tsx b/src/components/TermsOfService.tsx index 0678d38e..56ad0816 100644 --- a/src/components/TermsOfService.tsx +++ b/src/components/TermsOfService.tsx @@ -37,13 +37,13 @@ function Benefits({ benefits }: BenefitsProps) { export default function TermsOfService() { const { connect } = useWalletManager() - const [hasAgreedToTerms, setHasAgreedToTerms] = useLocalStorage(TERMS_OF_SERVICE_KEY, false) + const [_, setHasAgreedToTerms] = useLocalStorage(TERMS_OF_SERVICE_KEY, false) const handleAgreeTermsOfService = useCallback(() => { useStore.setState({ showTermsOfService: false, isFocusMode: false }) setHasAgreedToTerms(true) connect() - }, [connect, hasAgreedToTerms, setHasAgreedToTerms]) + }, [connect, setHasAgreedToTerms]) return (
diff --git a/src/constants/query.ts b/src/constants/query.ts new file mode 100644 index 00000000..fdae4c13 --- /dev/null +++ b/src/constants/query.ts @@ -0,0 +1,2 @@ +export const ITEM_LIMIT_PER_QUERY = 10 +export const PRICE_ORACLE_DECIMALS = 6 diff --git a/src/types/generated/mars-mock-oracle/MarsMockOracle.client.ts b/src/types/generated/mars-mock-oracle/MarsMockOracle.client.ts deleted file mode 100644 index eb5a55e8..00000000 --- a/src/types/generated/mars-mock-oracle/MarsMockOracle.client.ts +++ /dev/null @@ -1,99 +0,0 @@ -// @ts-nocheck -/** - * This file was automatically generated by @cosmwasm/ts-codegen@0.30.1. - * DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file, - * and run the @cosmwasm/ts-codegen generate command to regenerate this file. - */ - -import { CosmWasmClient, ExecuteResult, SigningCosmWasmClient } from '@cosmjs/cosmwasm-stargate' -import { Coin, StdFee } from '@cosmjs/amino' - -import { - CoinPrice, - Decimal, - ExecuteMsg, - InstantiateMsg, - PriceResponse, - QueryMsg, -} from './MarsMockOracle.types' -export interface MarsMockOracleReadOnlyInterface { - contractAddress: string - price: ({ denom }: { denom: string }) => Promise -} -export class MarsMockOracleQueryClient implements MarsMockOracleReadOnlyInterface { - client: CosmWasmClient - contractAddress: string - - constructor(client: CosmWasmClient, contractAddress: string) { - this.client = client - this.contractAddress = contractAddress - this.price = this.price.bind(this) - } - - price = async ({ denom }: { denom: string }): Promise => { - return this.client.queryContractSmart(this.contractAddress, { - price: { - denom, - }, - }) - } -} -export interface MarsMockOracleInterface extends MarsMockOracleReadOnlyInterface { - contractAddress: string - sender: string - changePrice: ( - { - denom, - price, - }: { - denom: string - price: Decimal - }, - fee?: number | StdFee | 'auto', - memo?: string, - _funds?: Coin[], - ) => Promise -} -export class MarsMockOracleClient - extends MarsMockOracleQueryClient - implements MarsMockOracleInterface -{ - client: SigningCosmWasmClient - sender: string - contractAddress: string - - constructor(client: SigningCosmWasmClient, sender: string, contractAddress: string) { - super(client, contractAddress) - this.client = client - this.sender = sender - this.contractAddress = contractAddress - this.changePrice = this.changePrice.bind(this) - } - - changePrice = async ( - { - denom, - price, - }: { - denom: string - price: Decimal - }, - fee: number | StdFee | 'auto' = 'auto', - memo?: string, - _funds?: Coin[], - ): Promise => { - return await this.client.execute( - this.sender, - this.contractAddress, - { - change_price: { - denom, - price, - }, - }, - fee, - memo, - _funds, - ) - } -} diff --git a/src/types/generated/mars-mock-oracle/MarsMockOracle.message-composer.ts b/src/types/generated/mars-mock-oracle/MarsMockOracle.message-composer.ts deleted file mode 100644 index 541d5220..00000000 --- a/src/types/generated/mars-mock-oracle/MarsMockOracle.message-composer.ts +++ /dev/null @@ -1,72 +0,0 @@ -// @ts-nocheck -/** - * This file was automatically generated by @cosmwasm/ts-codegen@0.30.1. - * DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file, - * and run the @cosmwasm/ts-codegen generate command to regenerate this file. - */ - -import { Coin } from '@cosmjs/amino' -import { MsgExecuteContractEncodeObject } from '@cosmjs/cosmwasm-stargate' -import { MsgExecuteContract } from 'cosmjs-types/cosmwasm/wasm/v1/tx' -import { toUtf8 } from '@cosmjs/encoding' - -import { - CoinPrice, - Decimal, - ExecuteMsg, - InstantiateMsg, - PriceResponse, - QueryMsg, -} from './MarsMockOracle.types' -export interface MarsMockOracleMessage { - contractAddress: string - sender: string - changePrice: ( - { - denom, - price, - }: { - denom: string - price: Decimal - }, - _funds?: Coin[], - ) => MsgExecuteContractEncodeObject -} -export class MarsMockOracleMessageComposer implements MarsMockOracleMessage { - sender: string - contractAddress: string - - constructor(sender: string, contractAddress: string) { - this.sender = sender - this.contractAddress = contractAddress - this.changePrice = this.changePrice.bind(this) - } - - changePrice = ( - { - denom, - price, - }: { - denom: string - price: Decimal - }, - _funds?: Coin[], - ): MsgExecuteContractEncodeObject => { - return { - typeUrl: '/cosmwasm.wasm.v1.MsgExecuteContract', - value: MsgExecuteContract.fromPartial({ - sender: this.sender, - contract: this.contractAddress, - msg: toUtf8( - JSON.stringify({ - change_price: { - denom, - price, - }, - }), - ), - funds: _funds, - }), - } - } -} diff --git a/src/types/generated/mars-mock-oracle/MarsMockOracle.react-query.ts b/src/types/generated/mars-mock-oracle/MarsMockOracle.react-query.ts deleted file mode 100644 index 00293578..00000000 --- a/src/types/generated/mars-mock-oracle/MarsMockOracle.react-query.ts +++ /dev/null @@ -1,85 +0,0 @@ -// @ts-nocheck -/** - * This file was automatically generated by @cosmwasm/ts-codegen@0.30.1. - * DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file, - * and run the @cosmwasm/ts-codegen generate command to regenerate this file. - */ - -import { useMutation, UseMutationOptions, useQuery, UseQueryOptions } from '@tanstack/react-query' -import { ExecuteResult } from '@cosmjs/cosmwasm-stargate' -import { Coin, StdFee } from '@cosmjs/amino' - -import { - CoinPrice, - Decimal, - ExecuteMsg, - InstantiateMsg, - PriceResponse, - QueryMsg, -} from './MarsMockOracle.types' -import { MarsMockOracleClient, MarsMockOracleQueryClient } from './MarsMockOracle.client' -export const marsMockOracleQueryKeys = { - contract: [ - { - contract: 'marsMockOracle', - }, - ] as const, - address: (contractAddress: string | undefined) => - [{ ...marsMockOracleQueryKeys.contract[0], address: contractAddress }] as const, - price: (contractAddress: string | undefined, args?: Record) => - [{ ...marsMockOracleQueryKeys.address(contractAddress)[0], method: 'price', args }] as const, -} -export interface MarsMockOracleReactQuery { - client: MarsMockOracleQueryClient | undefined - options?: Omit< - UseQueryOptions, - "'queryKey' | 'queryFn' | 'initialData'" - > & { - initialData?: undefined - } -} -export interface MarsMockOraclePriceQuery - extends MarsMockOracleReactQuery { - args: { - denom: string - } -} -export function useMarsMockOraclePriceQuery({ - client, - args, - options, -}: MarsMockOraclePriceQuery) { - return useQuery( - marsMockOracleQueryKeys.price(client?.contractAddress, args), - () => - client - ? client.price({ - denom: args.denom, - }) - : Promise.reject(new Error('Invalid client')), - { ...options, enabled: !!client && (options?.enabled != undefined ? options.enabled : true) }, - ) -} -export interface MarsMockOracleChangePriceMutation { - client: MarsMockOracleClient - msg: { - denom: string - price: Decimal - } - args?: { - fee?: number | StdFee | 'auto' - memo?: string - funds?: Coin[] - } -} -export function useMarsMockOracleChangePriceMutation( - options?: Omit< - UseMutationOptions, - 'mutationFn' - >, -) { - return useMutation( - ({ client, msg, args: { fee, memo, funds } = {} }) => client.changePrice(msg, fee, memo, funds), - options, - ) -} diff --git a/src/types/generated/mars-mock-oracle/MarsMockOracle.types.ts b/src/types/generated/mars-mock-oracle/MarsMockOracle.types.ts deleted file mode 100644 index 23861945..00000000 --- a/src/types/generated/mars-mock-oracle/MarsMockOracle.types.ts +++ /dev/null @@ -1,27 +0,0 @@ -// @ts-nocheck -/** - * This file was automatically generated by @cosmwasm/ts-codegen@0.30.1. - * DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file, - * and run the @cosmwasm/ts-codegen generate command to regenerate this file. - */ - -export type Decimal = string -export interface InstantiateMsg { - prices: CoinPrice[] -} -export interface CoinPrice { - denom: string - price: Decimal -} -export type ExecuteMsg = { - change_price: CoinPrice -} -export type QueryMsg = { - price: { - denom: string - } -} -export interface PriceResponse { - denom: string - price: Decimal -} diff --git a/src/types/generated/mars-mock-oracle/bundle.ts b/src/types/generated/mars-mock-oracle/bundle.ts deleted file mode 100644 index 5c78f5e2..00000000 --- a/src/types/generated/mars-mock-oracle/bundle.ts +++ /dev/null @@ -1,14 +0,0 @@ -// @ts-nocheck -/** - * This file was automatically generated by @cosmwasm/ts-codegen@0.30.1. - * DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file, - * and run the @cosmwasm/ts-codegen generate command to regenerate this file. - */ - -import * as _12 from './MarsMockOracle.types' -import * as _13 from './MarsMockOracle.client' -import * as _14 from './MarsMockOracle.message-composer' -import * as _15 from './MarsMockOracle.react-query' -export namespace contracts { - export const MarsMockOracle = { ..._12, ..._13, ..._14, ..._15 } -} diff --git a/src/types/generated/mars-oracle-osmosis/MarsOracleOsmosis.client.ts b/src/types/generated/mars-oracle-osmosis/MarsOracleOsmosis.client.ts new file mode 100644 index 00000000..6f775dea --- /dev/null +++ b/src/types/generated/mars-oracle-osmosis/MarsOracleOsmosis.client.ts @@ -0,0 +1,260 @@ +// @ts-nocheck +/** + * This file was automatically generated by @cosmwasm/ts-codegen@0.30.0. + * DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file, + * and run the @cosmwasm/ts-codegen generate command to regenerate this file. + */ + +import { CosmWasmClient, SigningCosmWasmClient, ExecuteResult } from '@cosmjs/cosmwasm-stargate' +import { Coin, StdFee } from '@cosmjs/amino' +import { + InstantiateMsg, + ExecuteMsg, + OsmosisPriceSourceForString, + Decimal, + Downtime, + Identifier, + OwnerUpdate, + DowntimeDetector, + GeometricTwap, + RedemptionRateForString, + QueryMsg, + ConfigResponse, + PriceResponse, + PriceSourceResponseForString, + ArrayOfPriceSourceResponseForString, + ArrayOfPriceResponse, +} from './MarsOracleOsmosis.types' +export interface MarsOracleOsmosisReadOnlyInterface { + contractAddress: string + config: () => Promise + priceSource: ({ denom }: { denom: string }) => Promise + priceSources: ({ + limit, + startAfter, + }: { + limit?: number + startAfter?: string + }) => Promise + price: ({ denom }: { denom: string }) => Promise + prices: ({ + limit, + startAfter, + }: { + limit?: number + startAfter?: string + }) => Promise +} +export class MarsOracleOsmosisQueryClient implements MarsOracleOsmosisReadOnlyInterface { + client: CosmWasmClient + contractAddress: string + + constructor(client: CosmWasmClient, contractAddress: string) { + this.client = client + this.contractAddress = contractAddress + this.config = this.config.bind(this) + this.priceSource = this.priceSource.bind(this) + this.priceSources = this.priceSources.bind(this) + this.price = this.price.bind(this) + this.prices = this.prices.bind(this) + } + + config = async (): Promise => { + return this.client.queryContractSmart(this.contractAddress, { + config: {}, + }) + } + priceSource = async ({ denom }: { denom: string }): Promise => { + return this.client.queryContractSmart(this.contractAddress, { + price_source: { + denom, + }, + }) + } + priceSources = async ({ + limit, + startAfter, + }: { + limit?: number + startAfter?: string + }): Promise => { + return this.client.queryContractSmart(this.contractAddress, { + price_sources: { + limit, + start_after: startAfter, + }, + }) + } + price = async ({ denom }: { denom: string }): Promise => { + return this.client.queryContractSmart(this.contractAddress, { + price: { + denom, + }, + }) + } + prices = async ({ + limit, + startAfter, + }: { + limit?: number + startAfter?: string + }): Promise => { + return this.client.queryContractSmart(this.contractAddress, { + prices: { + limit, + start_after: startAfter, + }, + }) + } +} +export interface MarsOracleOsmosisInterface extends MarsOracleOsmosisReadOnlyInterface { + contractAddress: string + sender: string + setPriceSource: ( + { + denom, + priceSource, + }: { + denom: string + priceSource: OsmosisPriceSourceForString + }, + fee?: number | StdFee | 'auto', + memo?: string, + _funds?: Coin[], + ) => Promise + removePriceSource: ( + { + denom, + }: { + denom: string + }, + fee?: number | StdFee | 'auto', + memo?: string, + _funds?: Coin[], + ) => Promise + updateOwner: ( + ownerUpdate: OwnerUpdate, + fee?: number | StdFee | 'auto', + memo?: string, + _funds?: Coin[], + ) => Promise + updateConfig: ( + { + baseDenom, + }: { + baseDenom?: string + }, + fee?: number | StdFee | 'auto', + memo?: string, + _funds?: Coin[], + ) => Promise +} +export class MarsOracleOsmosisClient + extends MarsOracleOsmosisQueryClient + implements MarsOracleOsmosisInterface +{ + client: SigningCosmWasmClient + sender: string + contractAddress: string + + constructor(client: SigningCosmWasmClient, sender: string, contractAddress: string) { + super(client, contractAddress) + this.client = client + this.sender = sender + this.contractAddress = contractAddress + this.setPriceSource = this.setPriceSource.bind(this) + this.removePriceSource = this.removePriceSource.bind(this) + this.updateOwner = this.updateOwner.bind(this) + this.updateConfig = this.updateConfig.bind(this) + } + + setPriceSource = async ( + { + denom, + priceSource, + }: { + denom: string + priceSource: OsmosisPriceSourceForString + }, + fee: number | StdFee | 'auto' = 'auto', + memo?: string, + _funds?: Coin[], + ): Promise => { + return await this.client.execute( + this.sender, + this.contractAddress, + { + set_price_source: { + denom, + price_source: priceSource, + }, + }, + fee, + memo, + _funds, + ) + } + removePriceSource = async ( + { + denom, + }: { + denom: string + }, + fee: number | StdFee | 'auto' = 'auto', + memo?: string, + _funds?: Coin[], + ): Promise => { + return await this.client.execute( + this.sender, + this.contractAddress, + { + remove_price_source: { + denom, + }, + }, + fee, + memo, + _funds, + ) + } + updateOwner = async ( + ownerUpdate: OwnerUpdate, + fee: number | StdFee | 'auto' = 'auto', + memo?: string, + _funds?: Coin[], + ): Promise => { + return await this.client.execute( + this.sender, + this.contractAddress, + { + update_owner: ownerUpdate, + }, + fee, + memo, + _funds, + ) + } + updateConfig = async ( + { + baseDenom, + }: { + baseDenom?: string + }, + fee: number | StdFee | 'auto' = 'auto', + memo?: string, + _funds?: Coin[], + ): Promise => { + return await this.client.execute( + this.sender, + this.contractAddress, + { + update_config: { + base_denom: baseDenom, + }, + }, + fee, + memo, + _funds, + ) + } +} diff --git a/src/types/generated/mars-oracle-osmosis/MarsOracleOsmosis.react-query.ts b/src/types/generated/mars-oracle-osmosis/MarsOracleOsmosis.react-query.ts new file mode 100644 index 00000000..9af54f39 --- /dev/null +++ b/src/types/generated/mars-oracle-osmosis/MarsOracleOsmosis.react-query.ts @@ -0,0 +1,259 @@ +// @ts-nocheck +/** + * This file was automatically generated by @cosmwasm/ts-codegen@0.30.0. + * DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file, + * and run the @cosmwasm/ts-codegen generate command to regenerate this file. + */ + +import { UseQueryOptions, useQuery, useMutation, UseMutationOptions } from '@tanstack/react-query' +import { ExecuteResult } from '@cosmjs/cosmwasm-stargate' +import { StdFee, Coin } from '@cosmjs/amino' +import { + InstantiateMsg, + ExecuteMsg, + OsmosisPriceSourceForString, + Decimal, + Downtime, + Identifier, + OwnerUpdate, + DowntimeDetector, + GeometricTwap, + RedemptionRateForString, + QueryMsg, + ConfigResponse, + PriceResponse, + PriceSourceResponseForString, + ArrayOfPriceSourceResponseForString, + ArrayOfPriceResponse, +} from './MarsOracleOsmosis.types' +import { MarsOracleOsmosisQueryClient, MarsOracleOsmosisClient } from './MarsOracleOsmosis.client' +export const marsOracleOsmosisQueryKeys = { + contract: [ + { + contract: 'marsOracleOsmosis', + }, + ] as const, + address: (contractAddress: string | undefined) => + [{ ...marsOracleOsmosisQueryKeys.contract[0], address: contractAddress }] as const, + config: (contractAddress: string | undefined, args?: Record) => + [ + { ...marsOracleOsmosisQueryKeys.address(contractAddress)[0], method: 'config', args }, + ] as const, + priceSource: (contractAddress: string | undefined, args?: Record) => + [ + { ...marsOracleOsmosisQueryKeys.address(contractAddress)[0], method: 'price_source', args }, + ] as const, + priceSources: (contractAddress: string | undefined, args?: Record) => + [ + { ...marsOracleOsmosisQueryKeys.address(contractAddress)[0], method: 'price_sources', args }, + ] as const, + price: (contractAddress: string | undefined, args?: Record) => + [{ ...marsOracleOsmosisQueryKeys.address(contractAddress)[0], method: 'price', args }] as const, + prices: (contractAddress: string | undefined, args?: Record) => + [ + { ...marsOracleOsmosisQueryKeys.address(contractAddress)[0], method: 'prices', args }, + ] as const, +} +export interface MarsOracleOsmosisReactQuery { + client: MarsOracleOsmosisQueryClient | undefined + options?: Omit< + UseQueryOptions, + "'queryKey' | 'queryFn' | 'initialData'" + > & { + initialData?: undefined + } +} +export interface MarsOracleOsmosisPricesQuery + extends MarsOracleOsmosisReactQuery { + args: { + limit?: number + startAfter?: string + } +} +export function useMarsOracleOsmosisPricesQuery({ + client, + args, + options, +}: MarsOracleOsmosisPricesQuery) { + return useQuery( + marsOracleOsmosisQueryKeys.prices(client?.contractAddress, args), + () => + client + ? client.prices({ + limit: args.limit, + startAfter: args.startAfter, + }) + : Promise.reject(new Error('Invalid client')), + { ...options, enabled: !!client && (options?.enabled != undefined ? options.enabled : true) }, + ) +} +export interface MarsOracleOsmosisPriceQuery + extends MarsOracleOsmosisReactQuery { + args: { + denom: string + } +} +export function useMarsOracleOsmosisPriceQuery({ + client, + args, + options, +}: MarsOracleOsmosisPriceQuery) { + return useQuery( + marsOracleOsmosisQueryKeys.price(client?.contractAddress, args), + () => + client + ? client.price({ + denom: args.denom, + }) + : Promise.reject(new Error('Invalid client')), + { ...options, enabled: !!client && (options?.enabled != undefined ? options.enabled : true) }, + ) +} +export interface MarsOracleOsmosisPriceSourcesQuery + extends MarsOracleOsmosisReactQuery { + args: { + limit?: number + startAfter?: string + } +} +export function useMarsOracleOsmosisPriceSourcesQuery({ + client, + args, + options, +}: MarsOracleOsmosisPriceSourcesQuery) { + return useQuery( + marsOracleOsmosisQueryKeys.priceSources(client?.contractAddress, args), + () => + client + ? client.priceSources({ + limit: args.limit, + startAfter: args.startAfter, + }) + : Promise.reject(new Error('Invalid client')), + { ...options, enabled: !!client && (options?.enabled != undefined ? options.enabled : true) }, + ) +} +export interface MarsOracleOsmosisPriceSourceQuery + extends MarsOracleOsmosisReactQuery { + args: { + denom: string + } +} +export function useMarsOracleOsmosisPriceSourceQuery({ + client, + args, + options, +}: MarsOracleOsmosisPriceSourceQuery) { + return useQuery( + marsOracleOsmosisQueryKeys.priceSource(client?.contractAddress, args), + () => + client + ? client.priceSource({ + denom: args.denom, + }) + : Promise.reject(new Error('Invalid client')), + { ...options, enabled: !!client && (options?.enabled != undefined ? options.enabled : true) }, + ) +} +export interface MarsOracleOsmosisConfigQuery + extends MarsOracleOsmosisReactQuery {} +export function useMarsOracleOsmosisConfigQuery({ + client, + options, +}: MarsOracleOsmosisConfigQuery) { + return useQuery( + marsOracleOsmosisQueryKeys.config(client?.contractAddress), + () => (client ? client.config() : Promise.reject(new Error('Invalid client'))), + { ...options, enabled: !!client && (options?.enabled != undefined ? options.enabled : true) }, + ) +} +export interface MarsOracleOsmosisUpdateConfigMutation { + client: MarsOracleOsmosisClient + msg: { + baseDenom?: string + } + args?: { + fee?: number | StdFee | 'auto' + memo?: string + funds?: Coin[] + } +} +export function useMarsOracleOsmosisUpdateConfigMutation( + options?: Omit< + UseMutationOptions, + 'mutationFn' + >, +) { + return useMutation( + ({ client, msg, args: { fee, memo, funds } = {} }) => + client.updateConfig(msg, fee, memo, funds), + options, + ) +} +export interface MarsOracleOsmosisUpdateOwnerMutation { + client: MarsOracleOsmosisClient + msg: OwnerUpdate + args?: { + fee?: number | StdFee | 'auto' + memo?: string + funds?: Coin[] + } +} +export function useMarsOracleOsmosisUpdateOwnerMutation( + options?: Omit< + UseMutationOptions, + 'mutationFn' + >, +) { + return useMutation( + ({ client, msg, args: { fee, memo, funds } = {} }) => client.updateOwner(msg, fee, memo, funds), + options, + ) +} +export interface MarsOracleOsmosisRemovePriceSourceMutation { + client: MarsOracleOsmosisClient + msg: { + denom: string + } + args?: { + fee?: number | StdFee | 'auto' + memo?: string + funds?: Coin[] + } +} +export function useMarsOracleOsmosisRemovePriceSourceMutation( + options?: Omit< + UseMutationOptions, + 'mutationFn' + >, +) { + return useMutation( + ({ client, msg, args: { fee, memo, funds } = {} }) => + client.removePriceSource(msg, fee, memo, funds), + options, + ) +} +export interface MarsOracleOsmosisSetPriceSourceMutation { + client: MarsOracleOsmosisClient + msg: { + denom: string + priceSource: OsmosisPriceSourceForString + } + args?: { + fee?: number | StdFee | 'auto' + memo?: string + funds?: Coin[] + } +} +export function useMarsOracleOsmosisSetPriceSourceMutation( + options?: Omit< + UseMutationOptions, + 'mutationFn' + >, +) { + return useMutation( + ({ client, msg, args: { fee, memo, funds } = {} }) => + client.setPriceSource(msg, fee, memo, funds), + options, + ) +} diff --git a/src/types/generated/mars-oracle-osmosis/MarsOracleOsmosis.types.ts b/src/types/generated/mars-oracle-osmosis/MarsOracleOsmosis.types.ts new file mode 100644 index 00000000..d5f9b5cb --- /dev/null +++ b/src/types/generated/mars-oracle-osmosis/MarsOracleOsmosis.types.ts @@ -0,0 +1,192 @@ +// @ts-nocheck +/** + * This file was automatically generated by @cosmwasm/ts-codegen@0.30.0. + * DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file, + * and run the @cosmwasm/ts-codegen generate command to regenerate this file. + */ + +export interface InstantiateMsg { + base_denom: string + owner: string +} +export type ExecuteMsg = + | { + set_price_source: { + denom: string + price_source: OsmosisPriceSourceForString + } + } + | { + remove_price_source: { + denom: string + } + } + | { + update_owner: OwnerUpdate + } + | { + update_config: { + base_denom?: string | null + } + } +export type OsmosisPriceSourceForString = + | { + fixed: { + price: Decimal + [k: string]: unknown + } + } + | { + spot: { + pool_id: number + [k: string]: unknown + } + } + | { + arithmetic_twap: { + downtime_detector?: DowntimeDetector | null + pool_id: number + window_size: number + [k: string]: unknown + } + } + | { + geometric_twap: { + downtime_detector?: DowntimeDetector | null + pool_id: number + window_size: number + [k: string]: unknown + } + } + | { + xyk_liquidity_token: { + pool_id: number + [k: string]: unknown + } + } + | { + staked_geometric_twap: { + downtime_detector?: DowntimeDetector | null + pool_id: number + transitive_denom: string + window_size: number + [k: string]: unknown + } + } + | { + pyth: { + contract_addr: string + denom_decimals: number + max_staleness: number + price_feed_id: Identifier + [k: string]: unknown + } + } + | { + lsd: { + geometric_twap: GeometricTwap + redemption_rate: RedemptionRateForString + transitive_denom: string + [k: string]: unknown + } + } +export type Decimal = string +export type Downtime = + | 'duration30s' + | 'duration1m' + | 'duration2m' + | 'duration3m' + | 'duration4m' + | 'duration5m' + | 'duration10m' + | 'duration20m' + | 'duration30m' + | 'duration40m' + | 'duration50m' + | 'duration1h' + | 'duration15h' + | 'duration2h' + | 'duration25h' + | 'duration3h' + | 'duration4h' + | 'duration5h' + | 'duration6h' + | 'duration9h' + | 'duration12h' + | 'duration18h' + | 'duration24h' + | 'duration36h' + | 'duration48h' +export type Identifier = string +export type OwnerUpdate = + | { + propose_new_owner: { + proposed: string + } + } + | 'clear_proposed' + | 'accept_proposed' + | 'abolish_owner_role' + | { + set_emergency_owner: { + emergency_owner: string + } + } + | 'clear_emergency_owner' +export interface DowntimeDetector { + downtime: Downtime + recovery: number + [k: string]: unknown +} +export interface GeometricTwap { + downtime_detector?: DowntimeDetector | null + pool_id: number + window_size: number + [k: string]: unknown +} +export interface RedemptionRateForString { + contract_addr: string + max_staleness: number + [k: string]: unknown +} +export type QueryMsg = + | { + config: {} + } + | { + price_source: { + denom: string + } + } + | { + price_sources: { + limit?: number | null + start_after?: string | null + } + } + | { + price: { + denom: string + } + } + | { + prices: { + limit?: number | null + start_after?: string | null + } + } +export interface ConfigResponse { + base_denom: string + owner?: string | null + proposed_new_owner?: string | null +} +export interface PriceResponse { + denom: string + price: Decimal +} +export interface PriceSourceResponseForString { + denom: string + price_source: string +} +export type ArrayOfPriceSourceResponseForString = PriceSourceResponseForString[] +export type ArrayOfPriceResponse = PriceResponse[] diff --git a/src/types/generated/mars-oracle-osmosis/bundle.ts b/src/types/generated/mars-oracle-osmosis/bundle.ts new file mode 100644 index 00000000..4703314d --- /dev/null +++ b/src/types/generated/mars-oracle-osmosis/bundle.ts @@ -0,0 +1,13 @@ +// @ts-nocheck +/** + * This file was automatically generated by @cosmwasm/ts-codegen@0.30.0. + * DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file, + * and run the @cosmwasm/ts-codegen generate command to regenerate this file. + */ + +import * as _6 from './MarsOracleOsmosis.types' +import * as _7 from './MarsOracleOsmosis.client' +import * as _8 from './MarsOracleOsmosis.react-query' +export namespace contracts { + export const MarsOracleOsmosis = { ..._6, ..._7, ..._8 } +} diff --git a/src/utils/iterateContractQuery.ts b/src/utils/iterateContractQuery.ts new file mode 100644 index 00000000..c7b3b6c5 --- /dev/null +++ b/src/utils/iterateContractQuery.ts @@ -0,0 +1,36 @@ +import { ITEM_LIMIT_PER_QUERY } from 'constants/query' + +interface KeyProperties { + denom?: string + addr?: string +} + +type Query = ({ + limit, + startAfter, +}: { + limit?: number | undefined + startAfter?: string | undefined +}) => Promise + +export default async function iterateContractQuery( + query: Query, + keyProperty: keyof KeyProperties = 'denom', + previousResults?: T[], +): Promise { + const lastItem = previousResults && previousResults.at(-1) + const lastItemKey = lastItem && lastItem[keyProperty] + const params = { + limit: ITEM_LIMIT_PER_QUERY, + startAfter: lastItemKey, + } + + const results = await query(params) + const accumulated = (previousResults ?? []).concat(results) + + if (results.length < ITEM_LIMIT_PER_QUERY) { + return accumulated + } + + return await iterateContractQuery(query, keyProperty, accumulated) +} diff --git a/validate-env.js b/validate-env.js index 6b046227..8172d99f 100644 --- a/validate-env.js +++ b/validate-env.js @@ -33,8 +33,29 @@ if (!process.env.NEXT_PUBLIC_REST) { if (!process.env.NEXT_PUBLIC_APOLLO_APR) { throw 'NEXT_PUBLIC_APOLLO_APR is not defined' } +if (!process.env.NEXT_PUBLIC_PARAMS) { + throw 'NEXT_PUBLIC_PARAMS is not defined' +} +if (!process.env.NEXT_PUBLIC_CANDLES_ENDPOINT) { + throw 'NEXT_PUBLIC_CANDLES_ENDPOINT is not defined' +} +if (!process.env.CHARTING_LIBRARY_USERNAME) { + throw 'CHARTING_LIBRARY_USERNAME is not defined' +} +if (!process.env.CHARTING_LIBRARY_ACCESS_TOKEN) { + throw 'CHARTING_LIBRARY_ACCESS_TOKEN is not defined' +} +if (!process.env.CHARTING_LIBRARY_REPOSITORY) { + throw 'CHARTING_LIBRARY_REPOSITORY is not defined' +} +if (!process.env.NEXT_PUBLIC_PYTH_ENDPOINT) { + throw 'NEXT_PUBLIC_PYTH_ENDPOINT is not defined' +} +if (!process.env.NEXT_PUBLIC_MAINNET_REST) { + throw 'NEXT_PUBLIC_MAINNET_REST is not defined' +} if (!process.env.NEXT_PUBLIC_RPC) { throw 'NEXT_PUBLIC_RPC is not defined' -} else { - console.log('✅ Required env variables set') } + +console.log('✅ Required env variables set')