-
Notifications
You must be signed in to change notification settings - Fork 196
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feat/neptune service #515
Feat/neptune service #515
Changes from 3 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,6 @@ | ||
export * from './swap/index.js' | ||
export * from './types.js' | ||
export * from './swap/index.js' | ||
export * from './neptune/index.js' | ||
export * from './incentives/index.js' | ||
export * from './nameservice/index.js' | ||
export * from './trading_strategies/index.js' |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import { AssetInfo } from './types.js' | ||
|
||
export function getDenom(assetInfo: AssetInfo): string | undefined { | ||
if ('native_token' in assetInfo) { | ||
return assetInfo.native_token.denom | ||
} | ||
|
||
return assetInfo.token.contract_addr | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
export * from './types.js' | ||
export * from './service.js' | ||
export * from './transformer.js' | ||
export * from './queries/index.js' | ||
|
||
export const NEPTUNE_PRICE_CONTRACT = 'inj1u6cclz0qh5tep9m2qayry9k97dm46pnlqf8nre' |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import { BaseWasmQuery } from '../../BaseWasmQuery.js' | ||
import { toBase64 } from '../../../../utils/index.js' | ||
import { AssetInfo } from '../types.js' | ||
|
||
export declare namespace QueryGetPrices { | ||
export interface Params { | ||
assets: AssetInfo[] | ||
} | ||
} | ||
|
||
export class QueryGetPrices extends BaseWasmQuery<QueryGetPrices.Params> { | ||
toPayload() { | ||
return toBase64({ | ||
get_prices: { | ||
assets: this.params.assets, | ||
}, | ||
}) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import { BaseWasmQuery } from '../../BaseWasmQuery.js'; | ||
import { toBase64 } from '../../../../utils/index.js'; | ||
import { AssetInfo } from '../types.js'; | ||
|
||
export declare namespace QueryGetAllLendingRates { | ||
export interface Params { | ||
limit?: number; | ||
startAfter?: AssetInfo; | ||
} | ||
} | ||
|
||
export class QueryGetAllLendingRates extends BaseWasmQuery<QueryGetAllLendingRates.Params> { | ||
toPayload() { | ||
const payload = { | ||
get_all_lending_rates: { | ||
...(this.params.limit !== undefined ? { limit: this.params.limit } : {}), | ||
...(this.params.startAfter ? { start_after: this.params.startAfter } : {}), | ||
}, | ||
}; | ||
|
||
return toBase64(payload); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export { QueryGetPrices } from './QueryGetPrices.js' | ||
export { QueryGetAllLendingRates } from './QueryLendingRates.js' |
Original file line number | Diff line number | Diff line change | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,268 @@ | ||||||||||||||||||
import { | ||||||||||||||||||
Network, | ||||||||||||||||||
isMainnet, | ||||||||||||||||||
NetworkEndpoints, | ||||||||||||||||||
getNetworkEndpoints, | ||||||||||||||||||
} from '@injectivelabs/networks' | ||||||||||||||||||
import { getDenom } from './helper.js' | ||||||||||||||||||
import { ChainGrpcWasmApi } from '../../chain/index.js' | ||||||||||||||||||
import { QueryGetPrices, QueryGetAllLendingRates } from './queries/index.js' | ||||||||||||||||||
import { NeptuneQueryTransformer } from './transformer.js' | ||||||||||||||||||
import ExecArgNeptuneDeposit from '../../../core/modules/wasm/exec-args/ExecArgNeptuneDeposit.js' | ||||||||||||||||||
import ExecArgNeptuneWithdraw from '../../../core/modules/wasm/exec-args/ExecArgNeptuneWithdraw.js' | ||||||||||||||||||
import MsgExecuteContractCompat from '../../../core/modules/wasm/msgs/MsgExecuteContractCompat.js' | ||||||||||||||||||
import { GeneralException } from '@injectivelabs/exceptions' | ||||||||||||||||||
import { NEPTUNE_PRICE_CONTRACT } from './index.js' | ||||||||||||||||||
Comment on lines
+7
to
+15
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Lets sort these by length and move |
||||||||||||||||||
import { | ||||||||||||||||||
AssetInfo, | ||||||||||||||||||
AssetInfoWithPrice, | ||||||||||||||||||
NEPTUNE_USDT_CW20_CONTRACT, | ||||||||||||||||||
} from './types.js' | ||||||||||||||||||
|
||||||||||||||||||
const NEPTUNE_USDT_MARKET_CONTRACT = | ||||||||||||||||||
'inj1nc7gjkf2mhp34a6gquhurg8qahnw5kxs5u3s4u' | ||||||||||||||||||
const NEPTUNE_USDT_INTEREST_CONTRACT = | ||||||||||||||||||
'inj1ftech0pdjrjawltgejlmpx57cyhsz6frdx2dhq' | ||||||||||||||||||
|
||||||||||||||||||
export class NeptuneService { | ||||||||||||||||||
private client: ChainGrpcWasmApi | ||||||||||||||||||
private priceOracleContract: string | ||||||||||||||||||
|
||||||||||||||||||
/** | ||||||||||||||||||
* Constructs a new NeptuneService instan ce. | ||||||||||||||||||
* @param network The network to use (default: Mainnet). | ||||||||||||||||||
* @param endpoints Optional custom network endpoints. | ||||||||||||||||||
*/ | ||||||||||||||||||
constructor( | ||||||||||||||||||
network: Network = Network.MainnetSentry, | ||||||||||||||||||
endpoints?: NetworkEndpoints, | ||||||||||||||||||
) { | ||||||||||||||||||
if (!isMainnet(network)) { | ||||||||||||||||||
throw new GeneralException(new Error('Please switch to mainnet network')) | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
const networkEndpoints = endpoints || getNetworkEndpoints(network) | ||||||||||||||||||
this.client = new ChainGrpcWasmApi(networkEndpoints.grpc) | ||||||||||||||||||
this.priceOracleContract = NEPTUNE_PRICE_CONTRACT | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
/** | ||||||||||||||||||
* Fetch prices for given assets from the Neptune Price Oracle contract. | ||||||||||||||||||
* @param assets Array of AssetInfo objects. | ||||||||||||||||||
* @returns Array of Price objects. | ||||||||||||||||||
*/ | ||||||||||||||||||
async fetchPrices(assets: AssetInfo[]): Promise<AssetInfoWithPrice[]> { | ||||||||||||||||||
const queryGetPricesPayload = new QueryGetPrices({ assets }).toPayload() | ||||||||||||||||||
|
||||||||||||||||||
try { | ||||||||||||||||||
const response = await this.client.fetchSmartContractState( | ||||||||||||||||||
this.priceOracleContract, | ||||||||||||||||||
queryGetPricesPayload, | ||||||||||||||||||
) | ||||||||||||||||||
|
||||||||||||||||||
const prices = | ||||||||||||||||||
NeptuneQueryTransformer.contractPricesResponseToPrices(response) | ||||||||||||||||||
|
||||||||||||||||||
return prices | ||||||||||||||||||
} catch (error) { | ||||||||||||||||||
console.error('Error fetching prices:', error) | ||||||||||||||||||
throw new GeneralException(new Error('Failed to fetch prices')) | ||||||||||||||||||
} | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
/** | ||||||||||||||||||
* Fetch the redemption ratio based on CW20 and native asset prices. | ||||||||||||||||||
* @param cw20Asset AssetInfo for the CW20 token. | ||||||||||||||||||
* @param nativeAsset AssetInfo for the native token. | ||||||||||||||||||
* @returns Redemption ratio as a number. | ||||||||||||||||||
*/ | ||||||||||||||||||
async fetchRedemptionRatio({ | ||||||||||||||||||
cw20Asset, | ||||||||||||||||||
nativeAsset, | ||||||||||||||||||
}: { | ||||||||||||||||||
cw20Asset: AssetInfo | ||||||||||||||||||
nativeAsset: AssetInfo | ||||||||||||||||||
}): Promise<number> { | ||||||||||||||||||
const prices = await this.fetchPrices([cw20Asset, nativeAsset]) | ||||||||||||||||||
|
||||||||||||||||||
const [cw20Price] = prices | ||||||||||||||||||
const [nativePrice] = prices.reverse() | ||||||||||||||||||
Comment on lines
+88
to
+89
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix incorrect extraction of prices due to array mutation Using Apply this diff to correctly extract the prices without mutating the array: - const [cw20Price] = prices
- const [nativePrice] = prices.reverse()
+ const [cw20Price, nativePrice] = prices 📝 Committable suggestion
Suggested change
|
||||||||||||||||||
|
||||||||||||||||||
if (!cw20Price || !nativePrice) { | ||||||||||||||||||
throw new GeneralException( | ||||||||||||||||||
new Error('Failed to compute redemption ratio'), | ||||||||||||||||||
) | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
return Number(cw20Price.price) / Number(nativePrice.price) | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
/** | ||||||||||||||||||
* Convert CW20 nUSDT to bank nUSDT using the redemption ratio. | ||||||||||||||||||
* @param amountCW20 Amount in CW20 nUSDT. | ||||||||||||||||||
* @param redemptionRatio Redemption ratio. | ||||||||||||||||||
* @returns Amount in bank nUSDT. | ||||||||||||||||||
*/ | ||||||||||||||||||
calculateBankAmount(amountCW20: number, redemptionRatio: number): number { | ||||||||||||||||||
return amountCW20 * redemptionRatio | ||||||||||||||||||
} | ||||||||||||||||||
Comment on lines
+107
to
+108
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Validate While multiplying by zero doesn't cause a runtime error, it's prudent to validate that Consider adding a check: calculateBankAmount(amountCW20: number, redemptionRatio: number): number {
+ if (redemptionRatio <= 0) {
+ throw new Error('Redemption ratio must be a positive number')
+ }
return amountCW20 * redemptionRatio
} 📝 Committable suggestion
Suggested change
|
||||||||||||||||||
|
||||||||||||||||||
/** | ||||||||||||||||||
* Convert bank nUSDT to CW20 nUSDT using the redemption ratio. | ||||||||||||||||||
* @param amountBank Amount in bank nUSDT. | ||||||||||||||||||
* @param redemptionRatio Redemption ratio. | ||||||||||||||||||
* @returns Amount in CW20 nUSDT. | ||||||||||||||||||
*/ | ||||||||||||||||||
calculateCw20Amount(amountBank: number, redemptionRatio: number): number { | ||||||||||||||||||
return amountBank / redemptionRatio | ||||||||||||||||||
} | ||||||||||||||||||
Comment on lines
+117
to
+118
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Prevent division by zero in Dividing by zero will cause a runtime error. It's essential to check that Add a validation check for calculateCw20Amount(amountBank: number, redemptionRatio: number): number {
+ if (redemptionRatio === 0) {
+ throw new Error('Redemption ratio cannot be zero')
+ }
return amountBank / redemptionRatio
} 📝 Committable suggestion
Suggested change
|
||||||||||||||||||
|
||||||||||||||||||
/** | ||||||||||||||||||
* Create a deposit message. | ||||||||||||||||||
* @param sender Sender's Injective address. | ||||||||||||||||||
* @param contractAddress USDT market contract address. | ||||||||||||||||||
* @param denom Denomination of the asset. | ||||||||||||||||||
* @param amount Amount to deposit as a string. | ||||||||||||||||||
* @returns MsgExecuteContractCompat message. | ||||||||||||||||||
*/ | ||||||||||||||||||
createDepositMsg({ | ||||||||||||||||||
denom, | ||||||||||||||||||
amount, | ||||||||||||||||||
sender, | ||||||||||||||||||
contractAddress = NEPTUNE_USDT_MARKET_CONTRACT, | ||||||||||||||||||
}: { | ||||||||||||||||||
denom: string | ||||||||||||||||||
amount: string | ||||||||||||||||||
sender: string | ||||||||||||||||||
contractAddress?: string | ||||||||||||||||||
}): MsgExecuteContractCompat { | ||||||||||||||||||
return MsgExecuteContractCompat.fromJSON({ | ||||||||||||||||||
sender, | ||||||||||||||||||
contractAddress, | ||||||||||||||||||
execArgs: ExecArgNeptuneDeposit.fromJSON({}), | ||||||||||||||||||
funds: { | ||||||||||||||||||
denom, | ||||||||||||||||||
amount, | ||||||||||||||||||
}, | ||||||||||||||||||
}) | ||||||||||||||||||
} | ||||||||||||||||||
Comment on lines
+128
to
+148
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Add input validation for message creation methods Both
Example validation: private validateAmount(amount: string): void {
if (!/^\d+$/.test(amount)) {
throw new Error('Amount must be a numeric string')
}
if (BigInt(amount) <= 0n) {
throw new Error('Amount must be positive')
}
} Also applies to: 157-176 |
||||||||||||||||||
|
||||||||||||||||||
/** | ||||||||||||||||||
* Create a withdraw message. | ||||||||||||||||||
* @param sender Sender's Injective address. | ||||||||||||||||||
* @param contractAddress nUSDT contract address. | ||||||||||||||||||
* @param amount Amount to withdraw as a string. | ||||||||||||||||||
* @returns MsgExecuteContractCompat message. | ||||||||||||||||||
*/ | ||||||||||||||||||
createWithdrawMsg({ | ||||||||||||||||||
amount, | ||||||||||||||||||
sender, | ||||||||||||||||||
cw20ContractAddress = NEPTUNE_USDT_CW20_CONTRACT, | ||||||||||||||||||
marketContractAddress = NEPTUNE_USDT_MARKET_CONTRACT, | ||||||||||||||||||
}: { | ||||||||||||||||||
amount: string | ||||||||||||||||||
sender: string | ||||||||||||||||||
cw20ContractAddress?: string | ||||||||||||||||||
marketContractAddress?: string | ||||||||||||||||||
}): MsgExecuteContractCompat { | ||||||||||||||||||
return MsgExecuteContractCompat.fromJSON({ | ||||||||||||||||||
sender, | ||||||||||||||||||
contractAddress: cw20ContractAddress, | ||||||||||||||||||
execArgs: ExecArgNeptuneWithdraw.fromJSON({ | ||||||||||||||||||
amount, | ||||||||||||||||||
contract: marketContractAddress, | ||||||||||||||||||
}), | ||||||||||||||||||
}) | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
/** | ||||||||||||||||||
* Fetch lending rates with optional pagination parameters. | ||||||||||||||||||
* @param limit Maximum number of lending rates to fetch. | ||||||||||||||||||
* @param startAfter AssetInfo to start after for pagination. | ||||||||||||||||||
* @returns Array of [AssetInfo, Decimal256] tuples. | ||||||||||||||||||
*/ | ||||||||||||||||||
async getLendingRates({ | ||||||||||||||||||
limit, | ||||||||||||||||||
startAfter, | ||||||||||||||||||
contractAddress = NEPTUNE_USDT_INTEREST_CONTRACT, | ||||||||||||||||||
}: { | ||||||||||||||||||
limit?: number | ||||||||||||||||||
startAfter?: AssetInfo | ||||||||||||||||||
contractAddress?: string | ||||||||||||||||||
}): Promise<Array<{ assetInfo: AssetInfo; lendingRate: string }>> { | ||||||||||||||||||
const query = new QueryGetAllLendingRates({ limit, startAfter }) | ||||||||||||||||||
const payload = query.toPayload() | ||||||||||||||||||
|
||||||||||||||||||
try { | ||||||||||||||||||
const response = await this.client.fetchSmartContractState( | ||||||||||||||||||
contractAddress, | ||||||||||||||||||
payload, | ||||||||||||||||||
) | ||||||||||||||||||
|
||||||||||||||||||
const lendingRates = | ||||||||||||||||||
NeptuneQueryTransformer.contractLendingRatesResponseToLendingRates( | ||||||||||||||||||
response, | ||||||||||||||||||
) | ||||||||||||||||||
|
||||||||||||||||||
return lendingRates | ||||||||||||||||||
} catch (error) { | ||||||||||||||||||
console.error('Error fetching lending rates:', error) | ||||||||||||||||||
throw new GeneralException(new Error('Failed to fetch lending rates')) | ||||||||||||||||||
} | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
/** | ||||||||||||||||||
* Fetch the lending rate for a specific denom by querying the smart contract with pagination. | ||||||||||||||||||
* @param denom The denomination string of the asset to find the lending rate for. | ||||||||||||||||||
* @returns Lending rate as a string. | ||||||||||||||||||
*/ | ||||||||||||||||||
async getLendingRateByDenom({ | ||||||||||||||||||
denom, | ||||||||||||||||||
contractAddress = NEPTUNE_USDT_INTEREST_CONTRACT, | ||||||||||||||||||
}: { | ||||||||||||||||||
denom: string | ||||||||||||||||||
contractAddress?: string | ||||||||||||||||||
}): Promise<string | undefined> { | ||||||||||||||||||
const limit = 10 | ||||||||||||||||||
let startAfter = undefined | ||||||||||||||||||
|
||||||||||||||||||
while (true) { | ||||||||||||||||||
const lendingRates = await this.getLendingRates({ | ||||||||||||||||||
limit, | ||||||||||||||||||
startAfter, | ||||||||||||||||||
contractAddress, | ||||||||||||||||||
}) | ||||||||||||||||||
|
||||||||||||||||||
if (lendingRates.length === 0) { | ||||||||||||||||||
return | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
for (const { assetInfo, lendingRate } of lendingRates) { | ||||||||||||||||||
const currentDenom = getDenom(assetInfo) | ||||||||||||||||||
|
||||||||||||||||||
if (currentDenom === denom) { | ||||||||||||||||||
return lendingRate | ||||||||||||||||||
} | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
if (lendingRates.length < limit) { | ||||||||||||||||||
return | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
const lastLendingRate = lendingRates[lendingRates.length - 1] | ||||||||||||||||||
|
||||||||||||||||||
startAfter = lastLendingRate.assetInfo | ||||||||||||||||||
} | ||||||||||||||||||
Comment on lines
+229
to
+255
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add safeguards against infinite loops in getLendingRateByDenom The while loop could potentially run indefinitely if the contract consistently returns the same number of results. Consider:
+ const MAX_ITERATIONS = 100
+ let iterations = 0
while (true) {
+ if (iterations++ >= MAX_ITERATIONS) {
+ throw new Error('Maximum iteration limit reached')
+ }
const lendingRates = await this.getLendingRates({
|
||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
/** | ||||||||||||||||||
* Calculates APY from APR and compounding frequency. | ||||||||||||||||||
* | ||||||||||||||||||
* @param apr - The annual percentage rate as a decimal (e.g., 0.10 for 10%) | ||||||||||||||||||
* @param compoundingFrequency - Number of times interest is compounded per year | ||||||||||||||||||
* @returns The annual percentage yield as a decimal | ||||||||||||||||||
*/ | ||||||||||||||||||
calculateAPY(apr: number, compoundingFrequency = 365): number { | ||||||||||||||||||
return Math.pow(1 + apr / compoundingFrequency, compoundingFrequency) - 1 | ||||||||||||||||||
} | ||||||||||||||||||
} |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,27 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { WasmContractQueryResponse } from '../types.js' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { toUtf8 } from '../../../utils/index.js' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { AssetInfo, PriceResponse, LendingRateResponse } from './types.js' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
export class NeptuneQueryTransformer { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
static contractPricesResponseToPrices( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
response: WasmContractQueryResponse, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
): Array<{ assetInfo: AssetInfo; price: string }> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Lets use [] instead of Array, same for the rest:
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const data = JSON.parse(toUtf8(response.data)) as PriceResponse | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return data.map(([assetInfo, priceInfo]) => ({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
assetInfo, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
price: priceInfo.price, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
})) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+6
to
+15
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Add error handling for JSON parsing and data validation. The current implementation could throw errors in several scenarios:
Consider implementing error handling: static contractPricesResponseToPrices(
response: WasmContractQueryResponse,
): Array<{ assetInfo: AssetInfo; price: string }> {
- const data = JSON.parse(toUtf8(response.data)) as PriceResponse
+ try {
+ const data = JSON.parse(toUtf8(response.data)) as PriceResponse
+ if (!Array.isArray(data)) {
+ throw new Error('Invalid price response format')
+ }
- return data.map(([assetInfo, priceInfo]) => ({
- assetInfo,
- price: priceInfo.price,
- }))
+ return data.map(([assetInfo, priceInfo]) => {
+ if (!assetInfo || !priceInfo?.price) {
+ throw new Error('Invalid price data structure')
+ }
+ return {
+ assetInfo,
+ price: priceInfo.price,
+ }
+ })
+ } catch (error) {
+ throw new Error(`Failed to transform price response: ${error.message}`)
+ }
} 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
static contractLendingRatesResponseToLendingRates( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
response: WasmContractQueryResponse, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
): Array<{ assetInfo: AssetInfo; lendingRate: string }> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const data = JSON.parse(toUtf8(response.data)) as LendingRateResponse | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return data.map(([assetInfo, lendingRate]) => ({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
assetInfo, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
lendingRate, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
})) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+17
to
+26
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Add error handling for lending rates transformation. Similar to the prices method, this implementation needs proper error handling. Apply similar error handling improvements: static contractLendingRatesResponseToLendingRates(
response: WasmContractQueryResponse,
): Array<{ assetInfo: AssetInfo; lendingRate: string }> {
- const data = JSON.parse(toUtf8(response.data)) as LendingRateResponse
+ try {
+ const data = JSON.parse(toUtf8(response.data)) as LendingRateResponse
+ if (!Array.isArray(data)) {
+ throw new Error('Invalid lending rate response format')
+ }
- return data.map(([assetInfo, lendingRate]) => ({
- assetInfo,
- lendingRate,
- }))
+ return data.map(([assetInfo, lendingRate]) => {
+ if (!assetInfo || !lendingRate) {
+ throw new Error('Invalid lending rate data structure')
+ }
+ return {
+ assetInfo,
+ lendingRate,
+ }
+ })
+ } catch (error) {
+ throw new Error(`Failed to transform lending rate response: ${error.message}`)
+ }
} 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
export type AssetInfo = | ||
| { | ||
token: { | ||
contract_addr: string | ||
} | ||
} | ||
| { | ||
native_token: { | ||
denom: string | ||
} | ||
} | ||
|
||
export type AssetInfoWithPrice = {assetInfo: AssetInfo, price: string } | ||
|
||
export type PriceResponse = Array<[AssetInfo, { price: string }]> | ||
export type LendingRateResponse = Array<[AssetInfo, string]> | ||
|
||
export const NEPTUNE_USDT_CW20_CONTRACT = | ||
'inj1cy9hes20vww2yr6crvs75gxy5hpycya2hmjg9s' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Lets change this to: