diff --git a/packages/indexer-nibi/src/heart-monitor.test.ts b/packages/indexer-nibi/src/heart-monitor.test.ts index 141d0a0c..68333a62 100644 --- a/packages/indexer-nibi/src/heart-monitor.test.ts +++ b/packages/indexer-nibi/src/heart-monitor.test.ts @@ -320,10 +320,20 @@ const testMarkPriceCandlesSubscription = async ( } test("markPriceCandlesSubscription", async () => { - await testMarkPriceCandlesSubscription({ limit: 1 }) + await testMarkPriceCandlesSubscription({ + limit: 1, + where: { + pairEq: "ubtc:unusd", + periodEq: 100000000, + }, + }) await testMarkPriceCandlesSubscription( { limit: 1, + where: { + pairEq: "ubtc:unusd", + periodEq: 100000000, + }, }, defaultMarkPriceCandles ) diff --git a/packages/nibijs/docs/classes/ErrorTxBroadcast.md b/packages/nibijs/docs/classes/ErrorTxBroadcast.md deleted file mode 100644 index bf1c954e..00000000 --- a/packages/nibijs/docs/classes/ErrorTxBroadcast.md +++ /dev/null @@ -1,36 +0,0 @@ -[NibiJS Documentation - v0.21.35](../intro.md) / [Exports](../modules.md) / ErrorTxBroadcast - -# Class: ErrorTxBroadcast - -## Hierarchy - -- `Error` - - ↳ **`ErrorTxBroadcast`** - -## Table of contents - -### Constructors - -- [constructor](ErrorTxBroadcast.md#constructor) - -## Constructors - -### constructor - -• **new ErrorTxBroadcast**(`message`, `stack?`) - -#### Parameters - -| Name | Type | -| :-------- | :------- | -| `message` | `string` | -| `stack?` | `string` | - -#### Overrides - -Error.constructor - -#### Defined in - -[chain/error.ts:33](https://github.com/NibiruChain/ts-sdk/blob/1da2942/packages/nibijs/src/chain/error.ts#L33) diff --git a/packages/nibijs/docs/classes/ErrorTxSimulation.md b/packages/nibijs/docs/classes/ErrorTxSimulation.md deleted file mode 100644 index ec1f7b99..00000000 --- a/packages/nibijs/docs/classes/ErrorTxSimulation.md +++ /dev/null @@ -1,36 +0,0 @@ -[NibiJS Documentation - v0.21.35](../intro.md) / [Exports](../modules.md) / ErrorTxSimulation - -# Class: ErrorTxSimulation - -## Hierarchy - -- `Error` - - ↳ **`ErrorTxSimulation`** - -## Table of contents - -### Constructors - -- [constructor](ErrorTxSimulation.md#constructor) - -## Constructors - -### constructor - -• **new ErrorTxSimulation**(`message`, `stack?`) - -#### Parameters - -| Name | Type | -| :-------- | :------- | -| `message` | `string` | -| `stack?` | `string` | - -#### Overrides - -Error.constructor - -#### Defined in - -[chain/error.ts:25](https://github.com/NibiruChain/ts-sdk/blob/1da2942/packages/nibijs/src/chain/error.ts#L25) diff --git a/packages/nibijs/docs/classes/StableSwap.md b/packages/nibijs/docs/classes/StableSwap.md index 51d172b3..0f435eba 100644 --- a/packages/nibijs/docs/classes/StableSwap.md +++ b/packages/nibijs/docs/classes/StableSwap.md @@ -178,7 +178,7 @@ y() Calculate x[j] if one makes x[i] = x Done by solving quadratic equation iteratively. -x*1**2 + x1 * (sum' - (A*n**n - 1) * D / (A _ n**n)) = D ** (n+1)/(n \*\* (2 _ n) \_ prod' \* A) +x*1\*\*2 + x1 * (sum' - (A*n\*\*n - 1) * D / (A _ n**n)) = D ** (n+1)/(n \*\* (2 _ n) \_ prod' \* A) x_1\*\*2 + b\*x_1 = c x_1 = (x_1\**2 + c) / (2*x_1 + b) diff --git a/packages/nibijs/docs/modules.md b/packages/nibijs/docs/modules.md index e89ed591..de3e8996 100644 --- a/packages/nibijs/docs/modules.md +++ b/packages/nibijs/docs/modules.md @@ -12,8 +12,6 @@ ### Classes - [CustomChain](classes/CustomChain.md) -- [ErrorTxBroadcast](classes/ErrorTxBroadcast.md) -- [ErrorTxSimulation](classes/ErrorTxSimulation.md) - [MsgFactory](classes/MsgFactory.md) - [NibiruQueryClient](classes/NibiruQueryClient.md) - [NibiruSigningClient](classes/NibiruSigningClient.md) @@ -60,7 +58,6 @@ - [Localnet](modules.md#localnet) - [Msg](modules.md#msg) - [PERP_MSG_TYPE_URLS](modules.md#perp_msg_type_urls) -- [PerpErrors](modules.md#perperrors) - [SPOT_MSG_TYPE_URLS](modules.md#spot_msg_type_urls) - [nibiruRegistryTypes](modules.md#nibiruregistrytypes) - [perpTypes](modules.md#perptypes) @@ -74,11 +71,9 @@ - [chainToParts](modules.md#chaintoparts) - [faucetUrlFromChain](modules.md#fauceturlfromchain) - [fromSdkDec](modules.md#fromsdkdec) -- [fromSdkDecSafe](modules.md#fromsdkdecsafe) - [fromSdkInt](modules.md#fromsdkint) - [getRegistry](modules.md#getregistry) - [go](modules.md#go) -- [instanceOfError](modules.md#instanceoferror) - [isMsgAddMarginEncodeObject](modules.md#ismsgaddmarginencodeobject) - [isMsgClosePositionEncodeObject](modules.md#ismsgclosepositionencodeobject) - [isMsgCreatePoolEncodeObject](modules.md#ismsgcreatepoolencodeobject) @@ -95,7 +90,6 @@ - [newRandomWallet](modules.md#newrandomwallet) - [newSignerFromMnemonic](modules.md#newsignerfrommnemonic) - [queryChainIdWithRest](modules.md#querychainidwithrest) -- [raises](modules.md#raises) - [setupEpochsExtension](modules.md#setupepochsextension) - [setupInflationExtension](modules.md#setupinflationextension) - [setupOracleExtension](modules.md#setuporacleextension) @@ -170,20 +164,6 @@ --- -### PerpErrors - -• `Const` **PerpErrors**: `Object` - -#### Index signature - -▪ [key: `string`]: `string` - -#### Defined in - -[chain/error.ts:40](https://github.com/NibiruChain/ts-sdk/blob/1da2942/packages/nibijs/src/chain/error.ts#L40) - ---- - ### SPOT_MSG_TYPE_URLS • `Const` **SPOT_MSG_TYPE_URLS**: `Object` @@ -360,26 +340,6 @@ Constructs a faucet URL from a Chain object. --- -### fromSdkDecSafe - -▸ **fromSdkDecSafe**(`inStr`): `number` - -#### Parameters - -| Name | Type | -| :------ | :------- | -| `inStr` | `string` | - -#### Returns - -`number` - -#### Defined in - -[chain/parse.ts:154](https://github.com/NibiruChain/ts-sdk/blob/1da2942/packages/nibijs/src/chain/parse.ts#L154) - ---- - ### fromSdkInt ▸ **fromSdkInt**(`intStr`): `number` @@ -440,45 +400,6 @@ Constructs a faucet URL from a Chain object. --- -### instanceOfError - -▸ **instanceOfError**(`obj`): obj is Error - -A function for strongly typing errors. The errors given in -catch blocks are not typed by default. This means they may not -have the message and name attributes. - -#### Parameters - -| Name | Type | -| :---- | :---- | -| `obj` | `any` | - -#### Returns - -obj is Error - -**`Example`** - -```js -try { - functionThatThrowsError() -} catch (err) { - if (!instanceOfError(err)) { - throw err - } - alert(err.message) -} -``` - -**`Export`** - -#### Defined in - -[chain/error.ts:21](https://github.com/NibiruChain/ts-sdk/blob/1da2942/packages/nibijs/src/chain/error.ts#L21) - ---- - ### isMsgAddMarginEncodeObject ▸ **isMsgAddMarginEncodeObject**(`encodeObject`): `boolean` @@ -813,30 +734,6 @@ A wallet for protobuf based signing using SIGN_MODE_DIRECT --- -### raises - -▸ **raises**(`errs`, `err`): `boolean` - -Makes sure one of the errors in 'errs' is contained in 'err'. If none of the -given exceptions are raised, it returns false. - -#### Parameters - -| Name | Type | -| :----- | :--------- | -| `errs` | `string`[] | -| `err` | `Error` | - -#### Returns - -`boolean` - -#### Defined in - -[chain/error.ts:53](https://github.com/NibiruChain/ts-sdk/blob/1da2942/packages/nibijs/src/chain/error.ts#L53) - ---- - ### setupEpochsExtension ▸ **setupEpochsExtension**(`base`): [`EpochsExtension`](interfaces/EpochsExtension.md) diff --git a/packages/nibijs/src/chain/error.ts b/packages/nibijs/src/chain/error.ts deleted file mode 100644 index 58af7955..00000000 --- a/packages/nibijs/src/chain/error.ts +++ /dev/null @@ -1,54 +0,0 @@ -// throw new Error() -// this.time = unixTs as UTCTimestamp - -/** - * A function for strongly typing errors. The errors given in - * catch blocks are not typed by default. This means they may not - * have the message and name attributes. - * - * @example - * ```js - * try { functionThatThrowsError() } - * catch (err) { - * if (!instanceOfError(err)) {throw err}; - * alert(err.message) - * } - * ``` - * @export - * @param {*} obj - * @returns {obj is Error} - */ -export const instanceOfError = (obj: any): obj is Error => - ["message", "name"].every((attr) => attr in obj) - -export class ErrorTxSimulation extends Error { - constructor(message: string, stack?: string) { - super(message) - this.name = "ErrorTxSimulation" - this.stack = stack ?? undefined - } -} - -export class ErrorTxBroadcast extends Error { - constructor(message: string, stack?: string) { - super(message) - this.name = "ErrorTxBroadcast" - this.stack = stack ?? undefined - } -} - -export const PerpErrors: { [key: string]: string } = { - positionNotFound: "collections: not found: 'nibiru.perp.v1.Position'", - badDebt: "bad debt", - underwaterPosition: "underwater position", -} - -/** - * Makes sure one of the errors in 'errs' is contained in 'err'. If none of the - * given exceptions are raised, it returns false. - * - * @param {string[]} errs - * @param {Error} err - */ -export const raises = (errs: string[], err: Error) => - errs.some((e) => err.message.includes(e)) diff --git a/packages/nibijs/src/chain/index.ts b/packages/nibijs/src/chain/index.ts index 7ce25777..4f85b81b 100644 --- a/packages/nibijs/src/chain/index.ts +++ b/packages/nibijs/src/chain/index.ts @@ -1,5 +1,4 @@ export * from "./chain" -export * from "./error" export * from "./parse" export * from "./types" export * from "./useFaucet" diff --git a/packages/nibijs/src/chain/parse.ts b/packages/nibijs/src/chain/parse.ts index e53a67b6..d6cb51a1 100644 --- a/packages/nibijs/src/chain/parse.ts +++ b/packages/nibijs/src/chain/parse.ts @@ -1,13 +1,6 @@ const PRECISION = 18 // number of decimal places export const INT_MULT = 1_000_000 -class ErrorParseNumber extends Error { - constructor(message: string) { - super(message) - this.name = "ErrorParseNumber" - } -} - /** * toSdkDec converts the input float string to an sdk.Dec. * The maximum number of decimal places for an sdk.Dec is 18. @@ -39,7 +32,8 @@ export const toSdkDec = (dec: string) => { let decStr = dec.toString() if (decStr.length === 0) { - throw new ErrorParseNumber(`Expected decimal string but got: ${decStr}`) + console.error(`Expected decimal string but got: ${decStr}`) + return "0" } // first extract any negative symbol @@ -50,7 +44,8 @@ export const toSdkDec = (dec: string) => { } if (decStr.length === 0) { - throw new ErrorParseNumber(`Expected decimal string but got: ${decStr}`) + console.error(`Expected decimal string but got: ${decStr}`) + return "0" } const digitBlocks = decStr.split(".") @@ -61,21 +56,22 @@ export const toSdkDec = (dec: string) => { // has a decimal place lenDigitBlock = digitBlocks[1].length if (lenDigitBlock === 0 || sdkDec.length === 0) { - throw new ErrorParseNumber(`Expected decimal string but got: ${decStr}`) + console.error(`Expected decimal string but got: ${decStr}`) + return "0" } sdkDec += digitBlocks[1] } else if (digitBlocks.length > 2) { - throw new ErrorParseNumber( - `Invalid input has more than one decimal point: ${decStr}` - ) + console.error(`Invalid input has more than one decimal point: ${decStr}`) + return "0" } if (lenDigitBlock > PRECISION) { - throw new ErrorParseNumber( + console.error( `value \${decStr}' exceeds max precision by ${ PRECISION - lenDigitBlock } decimal places: max precision ${PRECISION}` ) + return "0" } // An sdk.Dec must take up 18 (PRECISION) digits. @@ -85,9 +81,8 @@ export const toSdkDec = (dec: string) => { sdkDec += zeros if (Number.isNaN(parseInt(sdkDec, 10))) { - throw new ErrorParseNumber( - `failed to set decimal string with base 10: ${sdkDec}` - ) + console.error(`failed to set decimal string with base 10: ${sdkDec}`) + return "0" } if (neg) { @@ -102,13 +97,13 @@ export const fromSdkDec = (sdkDec: string) => { } if (sdkDec.indexOf(".") !== -1) { - throw new ErrorParseNumber( - `expected a decimal string but got ${sdkDec} containing '.'` - ) + console.error(`expected a decimal string but got ${sdkDec} containing '.'`) + return 0 } if (Number.isNaN(parseInt(sdkDec, 10))) { - throw new ErrorParseNumber(`failed to convert ${sdkDec} to a number`) + console.error(`failed to convert ${sdkDec} to a number`) + return 0 } // Check if the sdkDec is negative. @@ -148,23 +143,3 @@ export const fromSdkDec = (sdkDec: string) => { export const toSdkInt = (i: number) => Math.round(i).toString() export const fromSdkInt = (intStr: string) => parseInt(intStr) - -// TODO docs -// TODO test -export const fromSdkDecSafe = (inStr: string) => { - let sdkDec: number - try { - sdkDec = fromSdkDec(inStr) - return sdkDec - } catch (err: any) { - if (!(err instanceof ErrorParseNumber)) { - if (err.message) { - throw new Error(err.message) - } else { - throw err - } - } - } - sdkDec = parseFloat(inStr) - return sdkDec -} diff --git a/packages/nibijs/src/query/spot.ts b/packages/nibijs/src/query/spot.ts index f9ff7258..39b8a968 100644 --- a/packages/nibijs/src/query/spot.ts +++ b/packages/nibijs/src/query/spot.ts @@ -38,15 +38,15 @@ import { } from "@nibiruchain/protojs/dist/nibiru/spot/v1/query" import { fromSdkDec } from "../chain" -function transformPoolParams(pp?: PoolParams): PoolParams | undefined { +export const transformPoolParams = (pp?: PoolParams) => { if (pp) { - pp.swapFee = fromSdkDec(pp?.swapFee).toString() - pp.exitFee = fromSdkDec(pp?.exitFee).toString() + pp.swapFee = fromSdkDec(pp.swapFee).toString() + pp.exitFee = fromSdkDec(pp.exitFee).toString() } return pp } -function transformPool(p?: Pool): Pool | undefined { +export const transformPool = (p?: Pool) => { if (!p) { return p } @@ -74,7 +74,7 @@ export interface SpotExtension { ) => Promise estimateSwapExactAmountIn: ( poolId: number, - tokeOutDenom: string, + tokenOutDenom: string, tokenIn?: Coin ) => Promise estimateSwapExactAmountOut: ( diff --git a/packages/nibijs/src/test/balancer.test.ts b/packages/nibijs/src/test/balancer.test.ts index 5f6f44ff..9d18a2a5 100644 --- a/packages/nibijs/src/test/balancer.test.ts +++ b/packages/nibijs/src/test/balancer.test.ts @@ -105,4 +105,44 @@ describe("balancer tests", () => { priceImpact: BigNumber("-0.83333333333333333334"), } as Swap) }) + + test("swapX returns undefined if not positive", () => { + const balancerPool = new BalancerPool( + BigNumber(-100), + BigNumber(100), + BigNumber(0.5) // 50% fee + ) + + expect(balancerPool.swapX(BigNumber(-1))).toBeUndefined() + }) + + test("swapX returns undefined if poolEnd x and y are zero", () => { + const balancerPool = new BalancerPool( + BigNumber(0), + BigNumber(0), + BigNumber(0.5) // 50% fee + ) + + expect(balancerPool.swapX(BigNumber(0))).toBeUndefined() + }) + + test("swapY returns undefined if not positive", () => { + const balancerPool = new BalancerPool( + BigNumber(100), + BigNumber(-100), + BigNumber(0.5) // 50% fee + ) + + expect(balancerPool.swapY(BigNumber(-1))).toBeUndefined() + }) + + test("swapY returns undefined if poolEnd x and y are zero", () => { + const balancerPool = new BalancerPool( + BigNumber(0), + BigNumber(0), + BigNumber(0.5) // 50% fee + ) + + expect(balancerPool.swapY(BigNumber(0))).toBeUndefined() + }) }) diff --git a/packages/nibijs/src/test/chain.test.ts b/packages/nibijs/src/test/chain.test.ts index e0b62819..a02f9d9f 100644 --- a/packages/nibijs/src/test/chain.test.ts +++ b/packages/nibijs/src/test/chain.test.ts @@ -3,17 +3,22 @@ import { Coin, coin } from "@cosmjs/proto-signing" import { assert, Chain, + chainToParts, CoinMap, CustomChain, + Devnet, + fromSdkDec, fromSdkInt, go, + IncentivizedTestnet, isRestEndptLive, newCoinMapFromCoins, queryChainIdWithRest, + toSdkDec, } from "../chain" import { TEST_CHAIN } from "./helpers" -describe("chain connections", () => { +describe("chain/chain", () => { test("testnet rpc", async () => { const sgClient = await SigningStargateClient.connect(TEST_CHAIN.endptTm) const blockHeight = await sgClient.getHeight() @@ -26,6 +31,31 @@ describe("chain connections", () => { expect(chain.chainId).toEqual(TEST_CHAIN.chainId) }) + const expectCreatedChain = (result: CustomChain, prefix: string) => { + expect(result.chainId).toEqual(`nibiru-${prefix}-1`) + expect(result.chainName).toEqual(`nibiru-${prefix}-1`) + expect(result.endptGrpc).toEqual(`grpc.${prefix}-1.nibiru.fi`) + expect(result.endptRest).toEqual(`https://lcd.${prefix}-1.nibiru.fi`) + expect(result.endptTm).toEqual(`https://rpc.${prefix}-1.nibiru.fi`) + expect(result.feeDenom).toEqual(`unibi`) + } + + test("IncentivizedTestnet", async () => { + const result = IncentivizedTestnet(1) + expectCreatedChain(result, "itn") + }) + + test("Devnet", async () => { + const result = Devnet(1) + expectCreatedChain(result, "devnet") + }) + + test("queryChainIdWithRest", async () => { + const chain = Devnet(2) + const result = await queryChainIdWithRest(chain) + expect(result).toEqual(["nibiru-devnet-2", undefined]) + }) + test("inactive chain validation cases", async () => { const inactiveChain: Chain = { endptTm: "", @@ -40,6 +70,12 @@ describe("chain connections", () => { expect(chainId).toEqual("") await expect(isRestEndptLive(inactiveChain)).resolves.toBeFalsy() }) + + test("chainToParts", () => { + const chain = Devnet(2) + const result = chainToParts(chain) + expect(result).toEqual({ prefix: "nibiru", shortName: "devnet", number: 2 }) + }) }) describe("chain/parse", () => { @@ -48,6 +84,83 @@ describe("chain/parse", () => { expect(result).toEqual(123456789) }) + + const fromSdkDecTests = () => { + interface TestCase { + name: string + in: string + } + + const tests: TestCase[] = [ + { + name: "fromSdkDec number with decimal", + in: "12345678.9987654321", + }, + { + name: "fromSdkDec NaN", + in: "$$$", + }, + ] + + test.each(tests)("%o", (tt) => { + const res = fromSdkDec(tt.in) + expect(res).toBe(0) + }) + } + + const toSdkDecTests = () => { + interface TestCase { + name: string + in: string + expected: string + } + + const tests: TestCase[] = [ + { + name: "toSdkDec empty string", + in: "", + expected: "0", + }, + { + name: "toSdkDec negative zero", + in: "-0", + expected: "-0000000000000000000", + }, + { + name: "toSdkDec negative", + in: "-", + expected: "0", + }, + { + name: "toSdkDec NaN", + in: "$$$", + expected: "0", + }, + { + name: "toSdkDec multi-decimal", + in: "1.1.1", + expected: "0", + }, + { + name: "toSdkDec no leading zero", + in: ".1", + expected: "0", + }, + { + name: "toSdkDec why handling with bignumber is better", + in: "0.232423423423423423434234234234234234234234234234234234234234231", + expected: "0", + }, + ] + + test.each(tests)("%o", (tt) => { + const res = toSdkDec(tt.in) + expect(res).toBe(tt.expected) + }) + } + + toSdkDecTests() + fromSdkDecTests() }) describe("chain/types", () => { diff --git a/packages/nibijs/src/test/query.tests/oracle.test.ts b/packages/nibijs/src/test/query.tests/oracle.test.ts index 8bebde85..aeba0ae6 100644 --- a/packages/nibijs/src/test/query.tests/oracle.test.ts +++ b/packages/nibijs/src/test/query.tests/oracle.test.ts @@ -14,6 +14,20 @@ describe("setupOracleExtension", () => { submitBlock: Long.fromNumber(100000), }, } + const mockAggregateVoteResponse: query.QueryAggregateVoteResponse = { + aggregateVote: { + exchangeRateTuples: [{ pair: "USD", exchangeRate: "132" }], + voter: "VOTER", + }, + } + const mockAggregateVotesResponse: query.QueryAggregateVotesResponse = { + aggregateVotes: [ + { + exchangeRateTuples: [{ pair: "USD", exchangeRate: "132" }], + voter: "VOTER", + }, + ], + } const mockAggregatePrevotesResponse: query.QueryAggregatePrevotesResponse = { aggregatePrevotes: [ { @@ -64,6 +78,8 @@ describe("setupOracleExtension", () => { AggregatePrevotes: jest .fn() .mockResolvedValue(mockAggregatePrevotesResponse), + AggregateVote: jest.fn().mockResolvedValue(mockAggregateVoteResponse), + AggregateVotes: jest.fn().mockResolvedValue(mockAggregateVotesResponse), ExchangeRate: jest.fn().mockResolvedValue(mockExchangeRateResponse), ExchangeRates: jest.fn().mockResolvedValue(mockExchangeRatesResponse), FeederDelegation: jest.fn().mockResolvedValue(mockFeederDelegationResponse), @@ -116,6 +132,36 @@ describe("setupOracleExtension", () => { }) }) + describe("oracle.aggregateVote", () => { + test("should call QueryAggregatePrevoteRequest and return the response", async () => { + const queryAggregateVoteRequest = jest + .spyOn(query.QueryAggregateVoteRequest, "fromPartial") + .mockReturnValue({} as query.QueryAggregateVoteRequest) + + const extension = setupOracleExtension(mockBaseQueryClient) + const result = await extension.oracle.aggregateVote("1234567") + + expect(queryAggregateVoteRequest).toHaveBeenCalledWith({ + validatorAddr: "1234567", + }) + expect(result).toEqual(mockAggregateVoteResponse.aggregateVote) + }) + }) + + describe("oracle.aggregateVotes", () => { + test("should call QueryAggregatePrevoteRequest and return the response", async () => { + const queryAggregateVotesRequest = jest + .spyOn(query.QueryAggregateVotesRequest, "fromPartial") + .mockReturnValue({} as query.QueryAggregateVotesRequest) + + const extension = setupOracleExtension(mockBaseQueryClient) + const result = await extension.oracle.aggregateVotes() + + expect(queryAggregateVotesRequest).toHaveBeenCalledWith({}) + expect(result).toEqual(mockAggregateVotesResponse.aggregateVotes) + }) + }) + describe("oracle.exchangeRate", () => { test("should call QueryExchangeRateRequest and return the response", async () => { const queryExchangeRateRequest = jest diff --git a/packages/nibijs/src/test/query.tests/spot.test.ts b/packages/nibijs/src/test/query.tests/spot.test.ts new file mode 100644 index 00000000..8dce13cb --- /dev/null +++ b/packages/nibijs/src/test/query.tests/spot.test.ts @@ -0,0 +1,402 @@ +import { QueryClient } from "@cosmjs/stargate" +import * as query from "@nibiruchain/protojs/dist/nibiru/spot/v1/query" +import { setupSpotExtension, transformPool } from "../../query" + +describe("setupSpotExtension", () => { + const mockBaseQueryClient = {} as QueryClient + + jest.spyOn(query, "QueryClientImpl").mockReturnValue({ + EstimateExitExactAmountIn: jest.fn().mockResolvedValue({ + tokensOut: [], + fees: [], + }), + EstimateExitExactAmountOut: jest.fn().mockResolvedValue({ + estimateExitExactAmountOut: {}, + }), + EstimateJoinExactAmountIn: jest.fn().mockResolvedValue({ + poolSharesOut: "", + remCoins: [], + }), + EstimateJoinExactAmountOut: jest.fn().mockResolvedValue({ + estimateJoinExactAmountOut: {}, + }), + EstimateSwapExactAmountIn: jest.fn().mockResolvedValue({ + tokenOut: {}, + fee: {}, + }), + EstimateSwapExactAmountOut: jest.fn().mockResolvedValue({ + tokenIn: {}, + }), + NumPools: jest.fn().mockResolvedValue({ + numPools: 0, + }), + Params: jest.fn().mockResolvedValue({ + params: { + startingPoolNumber: 0, + poolCreationFee: [], + whitelistedAsset: [], + }, + }), + Pool: jest.fn().mockResolvedValue({ + pool: { + id: 0, + address: "", + poolParams: {}, + poolAssets: [], + totalWeight: "", + totalShares: {}, + }, + }), + PoolNumber: jest.fn().mockResolvedValue({ + poolId: 0, + }), + PoolParams: jest.fn().mockResolvedValue({ + poolParams: { + swapFee: "", + exitFee: "", + A: "", + poolType: {}, + }, + }), + Pools: jest.fn().mockResolvedValue({ + pools: [ + { + id: 0, + address: "", + poolParams: {}, + poolAssets: [], + totalWeight: "", + totalShares: {}, + }, + ], + pagination: {}, + }), + SpotPrice: jest.fn().mockResolvedValue({ + spotPrice: "", + }), + TotalLiquidity: jest.fn().mockResolvedValue({ + liquidity: [], + }), + TotalPoolLiquidity: jest.fn().mockResolvedValue({ + liquidity: [], + }), + TotalShares: jest.fn().mockResolvedValue({ + totalShares: {}, + }), + } as unknown as query.QueryClientImpl) + + test("transformPool undefined", () => { + const result = transformPool() + expect(result).toBeUndefined() + }) + + test("should setup spot extension correctly", () => { + const extension = setupSpotExtension(mockBaseQueryClient) + + expect(extension.spot).toBeDefined() + expect(extension.spot.estimateExitExactAmountIn).toBeInstanceOf(Function) + expect(extension.spot.estimateExitExactAmountOut).toBeInstanceOf(Function) + expect(extension.spot.estimateJoinExactAmountIn).toBeInstanceOf(Function) + expect(extension.spot.estimateJoinExactAmountOut).toBeInstanceOf(Function) + expect(extension.spot.estimateSwapExactAmountIn).toBeInstanceOf(Function) + expect(extension.spot.estimateSwapExactAmountOut).toBeInstanceOf(Function) + expect(extension.spot.numPools).toBeInstanceOf(Function) + expect(extension.spot.params).toBeInstanceOf(Function) + expect(extension.spot.pool).toBeInstanceOf(Function) + expect(extension.spot.poolNumber).toBeInstanceOf(Function) + expect(extension.spot.poolParams).toBeInstanceOf(Function) + expect(extension.spot.pools).toBeInstanceOf(Function) + expect(extension.spot.spotPrice).toBeInstanceOf(Function) + expect(extension.spot.totalLiquidity).toBeInstanceOf(Function) + expect(extension.spot.totalPoolLiquidity).toBeInstanceOf(Function) + expect(extension.spot.totalShares).toBeInstanceOf(Function) + }) + + test("estimateExitExactAmountIn should call and return the response", async () => { + const queryRequest = jest + .spyOn(query.QueryExitExactAmountInRequest, "fromPartial") + .mockReturnValue({} as query.QueryExitExactAmountInRequest) + + const extension = setupSpotExtension(mockBaseQueryClient) + const result = await extension.spot.estimateExitExactAmountIn(0, 1) + + expect(queryRequest).toHaveBeenCalledWith({ + poolId: 0, + poolSharesIn: "1", + }) + expect(result).toEqual({ + tokensOut: [], + fees: [], + }) + }) + + test("estimateExitExactAmountOut should call and return the response", async () => { + const queryRequest = jest + .spyOn(query.QueryExitExactAmountOutRequest, "fromPartial") + .mockReturnValue({} as query.QueryExitExactAmountOutRequest) + + const extension = setupSpotExtension(mockBaseQueryClient) + const result = await extension.spot.estimateExitExactAmountOut(0) + + expect(queryRequest).toHaveBeenCalledWith({ + poolId: 0, + }) + expect(result).toEqual({ + estimateExitExactAmountOut: {}, + }) + }) + + test("estimateJoinExactAmountIn should call and return the response", async () => { + const queryRequest = jest + .spyOn(query.QueryJoinExactAmountInRequest, "fromPartial") + .mockReturnValue({} as query.QueryJoinExactAmountInRequest) + + const extension = setupSpotExtension(mockBaseQueryClient) + const result = await extension.spot.estimateJoinExactAmountIn(0, []) + + expect(queryRequest).toHaveBeenCalledWith({ + poolId: 0, + tokensIn: [], + }) + expect(result).toEqual({ + poolSharesOut: "", + remCoins: [], + }) + }) + + test("estimateJoinExactAmountOut should call and return the response", async () => { + const queryRequest = jest + .spyOn(query.QueryJoinExactAmountOutRequest, "fromPartial") + .mockReturnValue({} as query.QueryJoinExactAmountOutRequest) + + const extension = setupSpotExtension(mockBaseQueryClient) + const result = await extension.spot.estimateJoinExactAmountOut(0) + + expect(queryRequest).toHaveBeenCalledWith({ + poolId: 0, + }) + expect(result).toEqual({ + estimateJoinExactAmountOut: {}, + }) + }) + + test("estimateSwapExactAmountIn should call and return the response", async () => { + const queryRequest = jest + .spyOn(query.QuerySwapExactAmountInRequest, "fromPartial") + .mockReturnValue({} as query.QuerySwapExactAmountInRequest) + + const extension = setupSpotExtension(mockBaseQueryClient) + const result = await extension.spot.estimateSwapExactAmountIn(0, "") + + expect(queryRequest).toHaveBeenCalledWith({ + poolId: 0, + tokenIn: undefined, + tokenOutDenom: "", + }) + expect(result).toEqual({ + tokenOut: {}, + fee: {}, + }) + }) + + test("estimateSwapExactAmountOut should call and return the response", async () => { + const queryRequest = jest + .spyOn(query.QuerySwapExactAmountOutRequest, "fromPartial") + .mockReturnValue({} as query.QuerySwapExactAmountOutRequest) + + const extension = setupSpotExtension(mockBaseQueryClient) + const result = await extension.spot.estimateSwapExactAmountOut(0, "") + + expect(queryRequest).toHaveBeenCalledWith({ + poolId: 0, + tokenInDenom: "", + }) + expect(result).toEqual({ + tokenIn: {}, + }) + }) + + test("numPools should call and return the response", async () => { + const queryParamsRequest = jest + .spyOn(query.QueryNumPoolsRequest, "fromPartial") + .mockReturnValue({} as query.QueryNumPoolsRequest) + + const extension = setupSpotExtension(mockBaseQueryClient) + const result = await extension.spot.numPools() + + expect(queryParamsRequest).toHaveBeenCalledWith({}) + expect(result).toEqual({ + numPools: 0, + }) + }) + + test("params should call and return the response", async () => { + const queryParamsRequest = jest + .spyOn(query.QueryParamsRequest, "fromPartial") + .mockReturnValue({} as query.QueryParamsRequest) + + const extension = setupSpotExtension(mockBaseQueryClient) + const result = await extension.spot.params() + + expect(queryParamsRequest).toHaveBeenCalledWith({}) + expect(result).toEqual({ + params: { + startingPoolNumber: 0, + poolCreationFee: [], + whitelistedAsset: [], + }, + }) + }) + + test("pool should call and return the response", async () => { + const queryParamsRequest = jest + .spyOn(query.QueryPoolRequest, "fromPartial") + .mockReturnValue({} as query.QueryPoolRequest) + + const extension = setupSpotExtension(mockBaseQueryClient) + const result = await extension.spot.pool(0) + + expect(queryParamsRequest).toHaveBeenCalledWith({ poolId: 0 }) + expect(result).toEqual({ + pool: { + id: 0, + address: "", + poolParams: { + exitFee: "0", + swapFee: "0", + }, + poolAssets: [], + totalWeight: "", + totalShares: {}, + }, + }) + }) + + test("poolNumber should call and return the response", async () => { + const queryParamsRequest = jest + .spyOn(query.QueryPoolNumberRequest, "fromPartial") + .mockReturnValue({} as query.QueryPoolNumberRequest) + + const extension = setupSpotExtension(mockBaseQueryClient) + const result = await extension.spot.poolNumber() + + expect(queryParamsRequest).toHaveBeenCalledWith({}) + expect(result).toEqual({ + poolId: 0, + }) + }) + + test("poolParams should call and return the response", async () => { + const queryParamsRequest = jest + .spyOn(query.QueryPoolParamsRequest, "fromPartial") + .mockReturnValue({} as query.QueryPoolParamsRequest) + + const extension = setupSpotExtension(mockBaseQueryClient) + const result = await extension.spot.poolParams(0) + + expect(queryParamsRequest).toHaveBeenCalledWith({ poolId: 0 }) + expect(result).toEqual({ + poolParams: { + swapFee: "0", + exitFee: "0", + A: "", + poolType: {}, + }, + }) + }) + + test("pools should call and return the response", async () => { + const queryParamsRequest = jest + .spyOn(query.QueryPoolsRequest, "fromPartial") + .mockReturnValue({} as query.QueryPoolsRequest) + + const extension = setupSpotExtension(mockBaseQueryClient) + const result = await extension.spot.pools() + + expect(queryParamsRequest).toHaveBeenCalledWith({ pagination: undefined }) + expect(result).toEqual({ + pools: [ + { + id: 0, + address: "", + poolParams: { + exitFee: "0", + swapFee: "0", + }, + poolAssets: [], + totalWeight: "", + totalShares: {}, + }, + ], + pagination: {}, + }) + }) + + test("spotPrice should call and return the response", async () => { + const queryParamsRequest = jest + .spyOn(query.QuerySpotPriceRequest, "fromPartial") + .mockReturnValue({} as query.QuerySpotPriceRequest) + + const extension = setupSpotExtension(mockBaseQueryClient) + const result = await extension.spot.spotPrice(0, "", "") + + expect(queryParamsRequest).toHaveBeenCalledWith({ + poolId: 0, + tokenInDenom: "", + tokenOutDenom: "", + }) + expect(result).toEqual({ + spotPrice: "", + }) + }) + + test("totalLiquidity should call and return the response", async () => { + const queryParamsRequest = jest + .spyOn(query.QuerySpotPriceRequest, "fromPartial") + .mockReturnValue({} as query.QuerySpotPriceRequest) + + const extension = setupSpotExtension(mockBaseQueryClient) + const result = await extension.spot.totalLiquidity() + + expect(queryParamsRequest).toHaveBeenCalledWith({ + poolId: 0, + tokenInDenom: "", + tokenOutDenom: "", + }) + expect(result).toEqual({ + liquidity: [], + }) + }) + + test("totalPoolLiquidity should call and return the response", async () => { + const queryParamsRequest = jest + .spyOn(query.QueryTotalPoolLiquidityRequest, "fromPartial") + .mockReturnValue({} as query.QueryTotalPoolLiquidityRequest) + + const extension = setupSpotExtension(mockBaseQueryClient) + const result = await extension.spot.totalPoolLiquidity(0) + + expect(queryParamsRequest).toHaveBeenCalledWith({ + poolId: 0, + }) + expect(result).toEqual({ + liquidity: [], + }) + }) + + test("totalShares should call and return the response", async () => { + const queryParamsRequest = jest + .spyOn(query.QueryTotalSharesRequest, "fromPartial") + .mockReturnValue({} as query.QueryTotalSharesRequest) + + const extension = setupSpotExtension(mockBaseQueryClient) + const result = await extension.spot.totalShares(0) + + expect(queryParamsRequest).toHaveBeenCalledWith({ + poolId: 0, + }) + expect(result).toEqual({ + totalShares: {}, + }) + }) +})