diff --git a/.github/workflows/test-ts-sdk.yaml b/.github/workflows/test-ts-sdk.yaml index 2a3890a5..fe82d798 100644 --- a/.github/workflows/test-ts-sdk.yaml +++ b/.github/workflows/test-ts-sdk.yaml @@ -9,7 +9,7 @@ on: paths: ["**.js", "**.ts", "**.tsx", "**.json"] jobs: - test-nibijs: + test-ts-sdk: runs-on: ubuntu-latest env: CHAIN_HOST: ${{ secrets.CHAIN_HOST }} diff --git a/README.md b/README.md index 747e013c..332438fb 100644 --- a/README.md +++ b/README.md @@ -65,7 +65,7 @@ The entrypoint for `nibijs` is the `Sdk` object, which is meant to mimic the roo ```js import { newRandomWallet, WalletHD } from "@nibiruchain/nibijs" -const wallet: WalletHD = await newRandomWallet() +const wallet = await newRandomWallet() const [{ address }] = await wallet.getAccounts() // Save the mnemonic somewhere to re-use the account diff --git a/examples/01_new-wallet-and-faucet.ts b/examples/01_new-wallet-and-faucet.ts index cbda8e78..1169ce83 100644 --- a/examples/01_new-wallet-and-faucet.ts +++ b/examples/01_new-wallet-and-faucet.ts @@ -1,6 +1,5 @@ import { useFaucet, - WalletHD, newRandomWallet, IncentivizedTestnet, } from "@nibiruchain/nibijs" @@ -8,7 +7,7 @@ import { const TEST_CHAIN = IncentivizedTestnet(2) async function runExample() { - const wallet: WalletHD = await newRandomWallet() + const wallet = await newRandomWallet() const [{ address }] = await wallet.getAccounts() // Save the mnemonic somewhere to re-use the account diff --git a/jest.config.js b/jest.config.js index 05054ef1..3055f6e3 100644 --- a/jest.config.js +++ b/jest.config.js @@ -30,6 +30,8 @@ module.exports = function (root = __dirname) { "packages/nibijs/src/**/*.{js,jsx,ts,tsx}", "!**/node_modules/**", "!**/dist/**", + "!**/index.ts", + "!**/nibijs/src/test/helpers.ts", ], // The directory where Jest should output its coverage files @@ -45,10 +47,10 @@ module.exports = function (root = __dirname) { // An object that configures minimum threshold enforcement for coverage results coverageThreshold: { global: { - branches: 50, - functions: 50, - lines: 50, - statements: 50, + branches: 75, + functions: 75, + lines: 75, + statements: 75, }, }, diff --git a/package.json b/package.json index 1f33221b..3a58499d 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "clean": "lerna run --parallel clean", "commit": "cz", "publish:all": "lerna publish from-package", - "test": "jest --verbose", + "test": "jest --verbose --detectOpenHandles", "lint": "eslint -c './.eslintrc.js' './packages/**/*.{ts,js}'", "lint:ci": "yarn lint . --format junit", "lint:md": "markdownlint --ignore node_modules --ignore .git", diff --git a/packages/indexer-nibi/src/graphql-codegen/codegen.ts b/packages/indexer-nibi/codegen.ts similarity index 91% rename from packages/indexer-nibi/src/graphql-codegen/codegen.ts rename to packages/indexer-nibi/codegen.ts index 462f4a95..0d269c92 100644 --- a/packages/indexer-nibi/src/graphql-codegen/codegen.ts +++ b/packages/indexer-nibi/codegen.ts @@ -1,6 +1,6 @@ import type { CodegenConfig } from "@graphql-codegen/cli" -const config: CodegenConfig = { +export default { schema: { "indexer-nibi": { loader: "./src/graphql-codegen/codegen-loader.js", @@ -26,6 +26,4 @@ const config: CodegenConfig = { }, }, }, -} - -export default config +} as CodegenConfig diff --git a/packages/indexer-nibi/package.json b/packages/indexer-nibi/package.json index 91c3f30d..cb0c2f62 100644 --- a/packages/indexer-nibi/package.json +++ b/packages/indexer-nibi/package.json @@ -11,7 +11,7 @@ "scripts": { "build": "tsc --build", "build:watch": "tsc --build --watch", - "gql-generate": "rm -rf src/gql && graphql-code-generator --config ./src/graphql-codegen/codegen.ts", + "gql-generate": "rm -rf src/gql && graphql-code-generator --config codegen.ts", "clean": "tsc --clean", "test": "jest", "test:watch": "jest --watch", diff --git a/packages/indexer-nibi/src/batchHandlers/queryBatchHandler.test.ts b/packages/indexer-nibi/src/batchHandlers/queryBatchHandler.test.ts new file mode 100644 index 00000000..f440f8d4 --- /dev/null +++ b/packages/indexer-nibi/src/batchHandlers/queryBatchHandler.test.ts @@ -0,0 +1,43 @@ +import { queryBatchHandler } from "./queryBatchHandler" +import { communityPoolQueryString } from "../query/communityPool" +import { delegationsQueryString } from "../query" + +const checkFields = (objects: any[], fields: any[]) => { + objects.forEach((obj: any) => { + fields.forEach((field: string | any[]) => { + expect(obj).toHaveProperty(field) + }) + }) +} + +describe("queryBatchHandler tests", () => { + test("queryBatchHandler", async () => { + const resp = await queryBatchHandler( + [ + communityPoolQueryString({}, true), + delegationsQueryString( + { + limit: 1, + }, + true + ), + ], + "https://hm-graphql.itn-3.nibiru.fi/query" + ) + + expect(resp).toHaveProperty("communityPool") + expect(resp).toHaveProperty("delegations") + + if (resp.communityPool?.length) { + const [communityPool] = resp.communityPool + const communityPoolFields = ["amount", "denom"] + checkFields([communityPool], communityPoolFields) + } + + if (resp.delegations?.length) { + const [delegation] = resp.delegations + const delegationFields = ["amount", "delegator", "validator"] + checkFields([delegation], delegationFields) + } + }) +}) diff --git a/packages/indexer-nibi/src/enum.ts b/packages/indexer-nibi/src/enum.ts deleted file mode 100644 index d6bb1d4a..00000000 --- a/packages/indexer-nibi/src/enum.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** CandlePeriod: Each value in the `enum` describes a time window in units of - * seconds. A value of 3600 corresponds to a candle that occurs over one hour. - */ -export enum CandlePeriod { - MIN_1 = 60, - MIN_5 = 300, - MIN_15 = 900, - HOUR_1 = 3600, - HOUR_6 = 21600, - DAY_1 = 86400, - WEEK_1 = 604800, -} - -export enum StatsPeriod { - HOUR_1 = 3600, - HOUR_6 = 21600, - DAY_1 = 86400, - WEEK_1 = 604800, -} diff --git a/packages/indexer-nibi/src/gql.ts b/packages/indexer-nibi/src/gql.ts index f963fa57..30884feb 100644 --- a/packages/indexer-nibi/src/gql.ts +++ b/packages/indexer-nibi/src/gql.ts @@ -66,44 +66,17 @@ export const gqlQuery = ( properties: string, excludeParentObject?: boolean ) => { - let queryArgList = [] - - if ( - typedQueryArgs.where !== undefined || - typedQueryArgs.limit !== undefined || - typedQueryArgs.order_by !== undefined || - typedQueryArgs.order_desc !== undefined || - typedQueryArgs.order !== undefined || - typedQueryArgs.orderDesc !== undefined - ) { - if (typedQueryArgs.where !== undefined) { - queryArgList.push(getWhereArgArr(typedQueryArgs.where)) - } - - if (typedQueryArgs.limit !== undefined) { - queryArgList.push(arg("limit", typedQueryArgs.limit)) - } + const queryArgList = [] - if (typedQueryArgs.order_by !== undefined) { - queryArgList.push(arg("order_by", typedQueryArgs.order_by, true)) - } - - if (typedQueryArgs.order !== undefined) { - queryArgList.push(arg("order", typedQueryArgs.order, true)) - } + if (typedQueryArgs.where !== undefined) { + queryArgList.push(getWhereArgArr(typedQueryArgs.where)) + } - if (typedQueryArgs.order_desc !== undefined) { - queryArgList.push(arg("order_desc", typedQueryArgs.order_desc)) - } + delete typedQueryArgs.where - if (typedQueryArgs.orderDesc !== undefined) { - queryArgList.push(arg("orderDesc", typedQueryArgs.orderDesc)) - } - } else { - queryArgList = Object.keys(typedQueryArgs).map((key) => - arg(key, typedQueryArgs[key]) - ) - } + Object.keys(typedQueryArgs).forEach((key) => + queryArgList.push(arg(key, typedQueryArgs[key], true)) + ) const hasQueryList = (char: string) => (queryArgList.length > 0 ? char : "") diff --git a/packages/indexer-nibi/src/graphql-codegen/codegen-loader.js b/packages/indexer-nibi/src/graphql-codegen/codegen-loader.js index fbae80b2..b403d9dd 100644 --- a/packages/indexer-nibi/src/graphql-codegen/codegen-loader.js +++ b/packages/indexer-nibi/src/graphql-codegen/codegen-loader.js @@ -19,6 +19,6 @@ module.exports = async () => { return buildClientSchema(data) } catch (error) { console.error(error) - throw error + return undefined } } diff --git a/packages/indexer-nibi/src/graphql-codegen/codegen-loader.test.ts b/packages/indexer-nibi/src/graphql-codegen/codegen-loader.test.ts new file mode 100644 index 00000000..03376272 --- /dev/null +++ b/packages/indexer-nibi/src/graphql-codegen/codegen-loader.test.ts @@ -0,0 +1,10 @@ +import { GraphQLSchema } from "graphql" + +const loader = require("./codegen-loader") + +describe("codegen-loader tests", () => { + test("codegen-loader", async () => { + const testResult = await loader() + expect(testResult).toBeInstanceOf(GraphQLSchema) + }) +}) diff --git a/packages/indexer-nibi/src/heart-monitor.test.ts b/packages/indexer-nibi/src/heart-monitor.test.ts index 8fdce4b2..141d0a0c 100644 --- a/packages/indexer-nibi/src/heart-monitor.test.ts +++ b/packages/indexer-nibi/src/heart-monitor.test.ts @@ -1,26 +1,111 @@ +import { WebSocket } from "ws" import { HeartMonitor } from "./heart-monitor" import { cleanResponse, gqlEndptFromTmRpc } from "./gql" -import { communityPoolQueryString, delegationsQueryString } from "./query" import { + GovernanceFields, + OracleFields, + PerpFields, + QueryGovernanceArgs, + QueryOracleArgs, + QueryPerpArgs, + QueryStatsArgs, + StatsFields, + communityPoolQueryString, + delegationsQueryString, +} from "./query" +import { + defaultDelegations, + defaultDistributionCommission, + defaultGovDeposit, + defaultGovProposal, + defaultGovVote, defaultMarkPriceCandles, + defaultOracleEntry, defaultOraclePrice, + defaultPerpLeaderboard, defaultPerpMarket, + defaultPerpOpenInterest, + defaultPerpPnl, defaultPerpPosition, + defaultPerpPositionChanges, + defaultPool, + defaultRedelegations, + defaultSpotLpPosition, + defaultSpotPool, + defaultSpotPoolSwap, + defaultStatsFees, + defaultToken, + defaultTotals, + defaultTvl, + defaultUnbondings, + defaultUser, + defaultUsers, + defaultValidator, + defaultVolume, } from "./defaultObjects" +import { + Delegation, + DistributionCommission, + GovDepositsOrder, + MarkPriceCandle, + OraclePrice, + PerpMarket, + PerpPosition, + QueryCommunityPoolArgs, + QueryDelegationsArgs, + QueryDistributionCommissionsArgs, + QueryMarkPriceCandlesArgs, + QueryRedelegationsArgs, + QuerySpotLpPositionsArgs, + QuerySpotPoolCreatedArgs, + QuerySpotPoolExitedArgs, + QuerySpotPoolJoinedArgs, + QuerySpotPoolSwapArgs, + QuerySpotPoolsArgs, + QueryUnbondingsArgs, + QueryUsersArgs, + QueryValidatorsArgs, + Redelegation, + SpotLpPosition, + SpotPool, + SpotPoolCreated, + SpotPoolExited, + SpotPoolJoined, + SpotPoolSwap, + SubscriptionMarkPriceCandlesArgs, + SubscriptionOraclePricesArgs, + SubscriptionPerpMarketArgs, + SubscriptionPerpPositionsArgs, + Token, + Unbonding, + User, + Validator, +} from "./gql/generated" + +const checkFields = (objects: any[], fields: any[]) => { + objects.forEach((obj: any) => { + fields.forEach((field: string | any[]) => { + expect(obj).toHaveProperty(field) + }) + }) +} const nibiruUrl = "itn-3" const heartMonitor = new HeartMonitor( - { - endptTm: `https://hm-graphql.${nibiruUrl}.nibiru.fi/query`, - }, - `wss://hm-graphql.${nibiruUrl}.nibiru.fi/query` + `https://hm-graphql.${nibiruUrl}.nibiru.fi/query`, + `wss://hm-graphql.${nibiruUrl}.nibiru.fi/query`, + WebSocket ) +afterAll(async () => { + await heartMonitor.closeWebSocket() +}) + describe("Heart Monitor constructor", () => { interface TestCase { name: string - in?: string | { endptTm: string } | undefined + in?: string expected: string } @@ -29,25 +114,13 @@ describe("Heart Monitor constructor", () => { const tests: TestCase[] = [ { name: "undefined", in: undefined, expected: defaultGqlEndpt }, { name: "valid string", in: "abc123", expected: "abc123" }, - { - name: "chain", - in: { endptTm: `https://rpc.${nibiruUrl}.nibiru.fi` }, - expected: `https://hm-graphql.${nibiruUrl}.nibiru.fi/graphql`, - }, - { - name: "empty chain string", - in: { endptTm: "" }, - expected: defaultGqlEndpt, - }, - { - name: "undefined as string", - in: { endptTm: undefined as unknown as string }, - expected: defaultGqlEndpt, - }, ] test.each(tests)("$name", (tc) => { - const hm = new HeartMonitor(tc.in) + const hm = new HeartMonitor( + tc.in, + `wss://hm-graphql.${nibiruUrl}.nibiru.fi/query` + ) expect(hm.gqlEndpt).toBe(tc.expected) }) }) @@ -81,53 +154,84 @@ describe("gqlEndptFromTmRpc", () => { }) }) -test("communityPool", async () => { - const resp = await heartMonitor.communityPool({}) +const testCommunityPool = async ( + args: QueryCommunityPoolArgs, + fields?: Token +) => { + const resp = await heartMonitor.communityPool(args, fields) expect(resp).toHaveProperty("communityPool") if ((resp.communityPool?.length ?? 0) > 0) { const [communityPool] = resp.communityPool ?? [] - const fields = ["amount", "denom"] - fields.forEach((field: string) => { - expect(communityPool).toHaveProperty(field) - }) + + checkFields([communityPool], ["amount", "denom"]) } +} + +test("communityPool", async () => { + await testCommunityPool({ limit: 1 }) + await testCommunityPool({}, defaultToken) }) -test("delegations", async () => { - const resp = await heartMonitor.delegations({ - limit: 1, - }) +const testDelegations = async ( + args: QueryDelegationsArgs, + fields?: Delegation +) => { + const resp = await heartMonitor.delegations(args, fields) expect(resp).toHaveProperty("delegations") if ((resp.delegations?.length ?? 0) > 0) { const [delegation] = resp.delegations ?? [] - const fields = ["amount", "delegator", "validator"] - fields.forEach((field: string) => { - expect(delegation).toHaveProperty(field) - }) + + checkFields([delegation], ["amount", "delegator", "validator"]) } +} + +test("delegations", async () => { + await testDelegations({ limit: 1 }) + await testDelegations({}, defaultDelegations) }) -test("distributionCommissions", async () => { - const resp = await heartMonitor.distributionCommissions({ - limit: 1, - }) +const testDistributionCommissions = async ( + args: QueryDistributionCommissionsArgs, + fields?: DistributionCommission +) => { + const resp = await heartMonitor.distributionCommissions(args, fields) expect(resp).toHaveProperty("distributionCommissions") if ((resp.distributionCommissions?.length ?? 0) > 0) { const [distributionCommissions] = resp.distributionCommissions ?? [] - const fields = ["commission", "validator"] - fields.forEach((field: string) => { - expect(distributionCommissions).toHaveProperty(field) - }) + + checkFields([distributionCommissions], ["commission", "validator"]) } +} + +test("distributionCommissions", async () => { + await testDistributionCommissions({ limit: 1 }) + await testDistributionCommissions({}, defaultDistributionCommission) }) +const testGovernance = async ( + args: QueryGovernanceArgs, + fields?: GovernanceFields +) => { + const resp = await heartMonitor.governance(args, fields) + expect(resp).toHaveProperty("governance") + + if (resp.governance) { + const { governance } = resp + + checkFields([governance], ["govDeposits", "govProposals", "govVotes"]) + } +} + test("governance", async () => { - const resp = await heartMonitor.governance({ + await testGovernance({ govDeposits: { limit: 1, + // Covers order and orderDesc, replaced by order_by and order_desc + order: GovDepositsOrder.Block, + orderDesc: true, }, govProposals: { limit: 1, @@ -136,130 +240,204 @@ test("governance", async () => { limit: 1, }, }) - expect(resp).toHaveProperty("governance") - - if (resp.governance) { - const { governance } = resp - const fields = ["govDeposits", "govProposals", "govVotes"] - fields.forEach((field: string) => { - expect(governance).toHaveProperty(field) - }) - } + await testGovernance( + { + govDeposits: { + limit: 1, + }, + govProposals: { + limit: 1, + }, + govVotes: { + limit: 1, + }, + }, + { + govDeposits: defaultGovDeposit, + govProposals: defaultGovProposal, + govVotes: defaultGovVote, + } + ) + await testGovernance( + {}, + { + govDeposits: defaultGovDeposit, + govProposals: defaultGovProposal, + govVotes: defaultGovVote, + } + ) }) -test("markPriceCandles", async () => { - const resp = await heartMonitor.markPriceCandles({ - limit: 1, - }) +const testMarkPriceCandles = async ( + args: QueryMarkPriceCandlesArgs, + fields?: MarkPriceCandle +) => { + const resp = await heartMonitor.markPriceCandles(args, fields) expect(resp).toHaveProperty("markPriceCandles") if ((resp.markPriceCandles?.length ?? 0) > 0) { const [markPriceCandle] = resp.markPriceCandles ?? [] - const fields = [ - "close", - "high", - "low", - "open", - "pair", - "period", - "periodStartTs", - ] - fields.forEach((field: string) => { - expect(markPriceCandle).toHaveProperty(field) - }) - } -}) -test("markPriceCandlesSubscription", async () => { - const hm = { - markPriceCandlesSubscription: jest.fn().mockResolvedValue({ - next: async () => ({ - value: { - data: { - markPriceCandles: defaultMarkPriceCandles, - }, - }, - }), - }), + checkFields( + [markPriceCandle], + ["close", "high", "low", "open", "pair", "period", "periodStartTs"] + ) } +} + +test("markPriceCandles", async () => { + await testMarkPriceCandles({ limit: 1 }) + await testMarkPriceCandles({}, defaultMarkPriceCandles) +}) +test("markPriceCandlesSubscription undefined client", async () => { + const hm = new HeartMonitor(`https://hm-graphql.${nibiruUrl}.nibiru.fi/query`) const resp = await hm.markPriceCandlesSubscription({ limit: 1, }) - const event = await resp.next() - - expect(event.value.data).toHaveProperty("markPriceCandles") - - if ((event.value.data.markPriceCandles.length ?? 0) > 0) { - const [markPriceCandle] = event.value.data.markPriceCandles ?? [] - const fields = [ - "close", - "high", - "low", - "open", - "pair", - "period", - "periodStartTs", - ] - fields.forEach((field: string) => { - expect(markPriceCandle).toHaveProperty(field) - }) + expect(resp).toBeUndefined() +}) + +const testMarkPriceCandlesSubscription = async ( + args: SubscriptionMarkPriceCandlesArgs, + fields?: MarkPriceCandle +) => { + const resp = await heartMonitor.markPriceCandlesSubscription(args, fields) + + const event = await resp?.next() + + expect(event?.value.data).toHaveProperty("markPriceCandles") + + if ((event?.value.data.markPriceCandles.length ?? 0) > 0) { + const [markPriceCandle] = event?.value.data.markPriceCandles ?? [] + + checkFields( + [markPriceCandle], + ["close", "high", "low", "open", "pair", "period", "periodStartTs"] + ) } +} + +test("markPriceCandlesSubscription", async () => { + await testMarkPriceCandlesSubscription({ limit: 1 }) + await testMarkPriceCandlesSubscription( + { + limit: 1, + }, + defaultMarkPriceCandles + ) }) +const testOracle = async (args: QueryOracleArgs, fields?: OracleFields) => { + const resp = await heartMonitor.oracle(args, fields) + expect(resp).toHaveProperty("oracle") + + if (resp.oracle) { + const { oracle } = resp + + checkFields([oracle], ["oraclePrices", "oracles"]) + } +} + test("oracle", async () => { - const resp = await heartMonitor.oracle({ + await testOracle({ oraclePrices: { limit: 1, + // Covers non-(limit, where, order, orderDesc) + offset: 1, }, oracles: { limit: 1, }, }) - expect(resp).toHaveProperty("oracle") + await testOracle( + { + oraclePrices: { + limit: 1, + }, + oracles: { + limit: 1, + }, + }, + { + oraclePrices: defaultOraclePrice, + oracles: defaultOracleEntry, + } + ) + await testOracle( + {}, + { + oraclePrices: defaultOraclePrice, + oracles: defaultOracleEntry, + } + ) +}) - if (resp.oracle) { - const { oracle } = resp - const fields = ["oraclePrices", "oracles"] - fields.forEach((field: string) => { - expect(oracle).toHaveProperty(field) - }) - } +test("oraclePricesSubscription undefined client", async () => { + const hm = new HeartMonitor(`https://hm-graphql.${nibiruUrl}.nibiru.fi/query`) + const resp = await hm.oraclePricesSubscription({ + where: { pair: "ubtc:unusd" }, + }) + + expect(resp).toBeUndefined() }) -test("oraclePricesSubscription", async () => { - const hm = { - oraclePricesSubscription: jest.fn().mockResolvedValue({ - next: async () => ({ - value: { - data: { - oraclePrices: [defaultOraclePrice], - }, - }, - }), - }), +const testOraclePricesSubscription = async ( + args: SubscriptionOraclePricesArgs, + fields?: OraclePrice +) => { + const resp = await heartMonitor.oraclePricesSubscription(args, fields) + + const event = await resp?.next() + + expect(event?.value.data).toHaveProperty("oraclePrices") + + if ((event?.value.data.oraclePrices.length ?? 0) > 0) { + const [oraclePrices] = event?.value.data.oraclePrices ?? [] + + checkFields( + [oraclePrices], + ["block", "eventSeqNo", "pair", "price", "txSeqNo"] + ) } +} - const resp = await hm.oraclePricesSubscription({ +test("oraclePricesSubscription", async () => { + await testOraclePricesSubscription({ where: { pair: "ubtc:unusd" }, }) + await testOraclePricesSubscription( + { + where: { pair: "ubtc:unusd" }, + }, + defaultOraclePrice + ) +}) - const event = await resp.next() +const testPerp = async (args: QueryPerpArgs, fields?: PerpFields) => { + const resp = await heartMonitor.perp(args, fields) + expect(resp).toHaveProperty("perp") - expect(event.value.data).toHaveProperty("oraclePrices") + if (resp.perp) { + const { perp } = resp - if ((event.value.data.oraclePrices.length ?? 0) > 0) { - const [oraclePrices] = event.value.data.oraclePrices ?? [] - const fields = ["block", "eventSeqNo", "pair", "price", "txSeqNo"] - fields.forEach((field: string) => { - expect(oraclePrices).toHaveProperty(field) - }) + checkFields( + [perp], + [ + "leaderboard", + "market", + "markets", + "position", + "positionChanges", + "positions", + ] + ) } -}) +} test("perp", async () => { - const resp = await heartMonitor.perp({ + await testPerp({ leaderboard: { limit: 1, }, @@ -277,98 +455,139 @@ test("perp", async () => { trader_address: "nibi1judn9xtel563nmq0ghpvmkqvyd5wnkm30mvkk3", }, }, - positionChanges: { + positions: { limit: 1, - where: { traderAddressEq: "nibi1judn9xtel563nmq0ghpvmkqvyd5wnkm30mvkk3" }, }, - positions: { + positionChanges: { limit: 1, + where: { traderAddressEq: "nibi1judn9xtel563nmq0ghpvmkqvyd5wnkm30mvkk3" }, }, }) + + await testPerp( + { + leaderboard: { + limit: 1, + }, + market: { + where: { + pair: "ubtc:unusd", + }, + }, + markets: { + limit: 1, + }, + position: { + where: { + pair: "ubtc:unusd", + trader_address: "nibi1judn9xtel563nmq0ghpvmkqvyd5wnkm30mvkk3", + }, + }, + positions: { + limit: 1, + }, + positionChanges: { + limit: 1, + where: { + traderAddressEq: "nibi1judn9xtel563nmq0ghpvmkqvyd5wnkm30mvkk3", + }, + }, + }, + { + leaderboard: defaultPerpLeaderboard, + market: defaultPerpMarket, + markets: defaultPerpMarket, + position: defaultPerpPosition, + positions: defaultPerpPosition, + positionChanges: defaultPerpPositionChanges, + } + ) + + // Note: This is because market and position do not exist + const resp = await heartMonitor.perp( + {}, + { + leaderboard: defaultPerpLeaderboard, + markets: defaultPerpMarket, + positions: defaultPerpPosition, + } + ) expect(resp).toHaveProperty("perp") if (resp.perp) { const { perp } = resp - const fields = [ - "leaderboard", - "market", - "markets", - "position", - "positionChanges", - "positions", - ] - fields.forEach((field: string) => { - expect(perp).toHaveProperty(field) - }) - } -}) -test("perpMarketSubscription", async () => { - const hm = { - perpMarketSubscription: jest.fn().mockResolvedValue({ - next: async () => ({ - value: { - data: { - perpMarket: defaultPerpMarket, - }, - }, - }), - }), + checkFields([perp], ["leaderboard", "markets", "positions"]) } +}) +test("perpMarketSubscription undefined client", async () => { + const hm = new HeartMonitor(`https://hm-graphql.${nibiruUrl}.nibiru.fi/query`) const resp = await hm.perpMarketSubscription({ where: { pair: "ubtc:unusd" }, }) - const event = await resp.next() + expect(resp).toBeUndefined() +}) + +const testPerpMarketSubscription = async ( + args: SubscriptionPerpMarketArgs, + fields?: PerpMarket +) => { + const resp = await heartMonitor.perpMarketSubscription(args, fields) + + const event = await resp?.next() - expect(event.value.data).toHaveProperty("perpMarket") - if (event.value.data.perpMarket) { + expect(event?.value.data).toHaveProperty("perpMarket") + if (event?.value.data.perpMarket) { const { perpMarket } = event.value.data - const fields = [ - "pair", - "enabled", - "maintenance_margin_ratio", - "max_leverage", - "latest_cumulative_premium_fraction", - "exchange_fee_ratio", - "ecosystem_fund_fee_ratio", - "max_funding_rate", - "liquidation_fee_ratio", - "partial_liquidation_ratio", - "funding_rate_epoch_id", - "twap_lookback_window", - "prepaid_bad_debt", - "base_reserve", - "quote_reserve", - "sqrt_depth", - "price_multiplier", - "total_long", - "total_short", - "mark_price", - "mark_price_twap", - "index_price_twap", - "is_deleted", - ] - fields.forEach((field: string) => { - expect(perpMarket).toHaveProperty(field) - }) - } -}) -test("perpPositionsSubscription", async () => { - const hm = { - perpPositionsSubscription: jest.fn().mockResolvedValue({ - next: async () => ({ - value: { - data: { - perpPositions: defaultPerpPosition, - }, - }, - }), - }), + checkFields( + [perpMarket], + [ + "pair", + "enabled", + "maintenance_margin_ratio", + "max_leverage", + "latest_cumulative_premium_fraction", + "exchange_fee_ratio", + "ecosystem_fund_fee_ratio", + "max_funding_rate", + "liquidation_fee_ratio", + "partial_liquidation_ratio", + "funding_rate_epoch_id", + "twap_lookback_window", + "prepaid_bad_debt", + "base_reserve", + "quote_reserve", + "sqrt_depth", + "price_multiplier", + "total_long", + "total_short", + "mark_price", + "mark_price_twap", + "index_price_twap", + "is_deleted", + ] + ) } +} + +test("perpMarketSubscription", async () => { + await testPerpMarketSubscription({ + where: { pair: "ubtc:unusd" }, + }) + + await testPerpMarketSubscription( + { + where: { pair: "ubtc:unusd" }, + }, + defaultPerpMarket + ) +}) +test("perpPositionsSubscription undefined client", async () => { + const hm = new HeartMonitor(`https://hm-graphql.${nibiruUrl}.nibiru.fi/query`) const resp = await hm.perpPositionsSubscription({ where: { pair: "ubtc:unusd", @@ -376,29 +595,58 @@ test("perpPositionsSubscription", async () => { }, }) - const event = await resp.next() - - expect(event.value.data).toHaveProperty("perpPositions") - if ((event.value.data.perpPositions.length ?? 0) > 0) { - const [perpPositions] = event.value.data.perpPositions ?? [] - const fields = [ - "pair", - "trader_address", - "size", - "margin", - "open_notional", - "position_notional", - "latest_cumulative_premium_fraction", - "unrealized_pnl", - "unrealized_funding_payment", - "margin_ratio", - "bad_debt", - "last_updated_block", - ] - fields.forEach((field: string) => { - expect(perpPositions).toHaveProperty(field) - }) + expect(resp).toBeUndefined() +}) + +const testPerpPositionsSubscription = async ( + args: SubscriptionPerpPositionsArgs, + fields?: PerpPosition +) => { + const resp = await heartMonitor.perpPositionsSubscription(args, fields) + + const event = await resp?.next() + + expect(event?.value.data).toHaveProperty("perpPositions") + if ((event?.value.data.perpPositions.length ?? 0) > 0) { + const [perpPositions] = event?.value.data.perpPositions ?? [] + + checkFields( + [perpPositions], + [ + "pair", + "trader_address", + "size", + "margin", + "open_notional", + "position_notional", + "latest_cumulative_premium_fraction", + "unrealized_pnl", + "unrealized_funding_payment", + "margin_ratio", + "bad_debt", + "last_updated_block", + ] + ) } +} + +test("perpPositionsSubscription", async () => { + await testPerpPositionsSubscription({ + where: { + pair: "ubtc:unusd", + trader_address: "nibi14garegtvsx3zcku4esd30xd2pze7ck44ysxeg3", + }, + }) + + await testPerpPositionsSubscription( + { + where: { + pair: "ubtc:unusd", + trader_address: "nibi14garegtvsx3zcku4esd30xd2pze7ck44ysxeg3", + }, + }, + defaultPerpPosition + ) }) test("queryBatchHandler", async () => { @@ -417,146 +665,213 @@ test("queryBatchHandler", async () => { if ((resp.communityPool?.length ?? 0) > 0) { const [communityPool] = resp.communityPool ?? [] - const fields = ["amount", "denom"] - fields.forEach((field: string) => { - expect(communityPool).toHaveProperty(field) - }) + + checkFields([communityPool], ["amount", "denom"]) } if ((resp.delegations?.length ?? 0) > 0) { const [delegation] = resp.delegations ?? [] - const fields = ["amount", "delegator", "validator"] - fields.forEach((field: string) => { - expect(delegation).toHaveProperty(field) - }) + + checkFields([delegation], ["amount", "delegator", "validator"]) } }) -test("redelegations", async () => { - const resp = await heartMonitor.redelegations({ - limit: 1, - }) +const testRedelegations = async ( + args: QueryRedelegationsArgs, + fields?: Redelegation +) => { + const resp = await heartMonitor.redelegations(args, fields) expect(resp).toHaveProperty("redelegations") if ((resp.redelegations?.length ?? 0) > 0) { const [redelegations] = resp.redelegations ?? [] - const fields = [ - "delegator", - "source_validator", - "destination_validator", - "amount", - "creation_block", - "completion_time", - ] - fields.forEach((field: string) => { - expect(redelegations).toHaveProperty(field) - }) + + checkFields( + [redelegations], + [ + "delegator", + "source_validator", + "destination_validator", + "amount", + "creation_block", + "completion_time", + ] + ) } -}) +} -test("spotLpPositions", async () => { - const resp = await heartMonitor.spotLpPositions({ +test("redelegations", async () => { + await testRedelegations({ limit: 1, }) + await testRedelegations({}, defaultRedelegations) +}) + +const testSpotLpPositions = async ( + args: QuerySpotLpPositionsArgs, + fields?: SpotLpPosition +) => { + const resp = await heartMonitor.spotLpPositions(args, fields) expect(resp).toHaveProperty("spotLpPositions") if ((resp.spotLpPositions?.length ?? 0) > 0) { const [spotLpPositions] = resp.spotLpPositions ?? [] - const fields = ["pool", "user", "pool_shares", "created_block"] - fields.forEach((field: string) => { - expect(spotLpPositions).toHaveProperty(field) - }) + + checkFields( + [spotLpPositions], + ["pool", "user", "pool_shares", "created_block"] + ) } -}) +} -test("spotPoolCreated", async () => { - const resp = await heartMonitor.spotPoolCreated({ +test("spotLpPositions", async () => { + await testSpotLpPositions({ limit: 1, }) + await testSpotLpPositions({}, defaultSpotLpPosition) +}) + +const testSpotPoolCreated = async ( + args: QuerySpotPoolCreatedArgs, + fields?: SpotPoolCreated +) => { + const resp = await heartMonitor.spotPoolCreated(args, fields) expect(resp).toHaveProperty("spotPoolCreated") if ((resp.spotPoolCreated?.length ?? 0) > 0) { const [spotPoolCreated] = resp.spotPoolCreated ?? [] - const fields = ["user", "block", "pool", "pool_shares"] - fields.forEach((field: string) => { - expect(spotPoolCreated).toHaveProperty(field) - }) + + checkFields([spotPoolCreated], ["user", "block", "pool", "pool_shares"]) } -}) +} -test("spotPoolExited", async () => { - const resp = await heartMonitor.spotPoolExited({ +test("spotPoolCreated", async () => { + await testSpotPoolCreated({ limit: 1, }) + await testSpotPoolCreated({}, defaultSpotPool) +}) + +const testSpotPoolExited = async ( + args: QuerySpotPoolExitedArgs, + fields?: SpotPoolExited +) => { + const resp = await heartMonitor.spotPoolExited(args, fields) expect(resp).toHaveProperty("spotPoolExited") if ((resp.spotPoolExited?.length ?? 0) > 0) { const [spotPoolExited] = resp.spotPoolExited ?? [] - const fields = ["user", "block", "pool", "pool_shares"] - fields.forEach((field: string) => { - expect(spotPoolExited).toHaveProperty(field) - }) + + checkFields([spotPoolExited], ["user", "block", "pool", "pool_shares"]) } -}) +} -test("spotPoolJoined", async () => { - const resp = await heartMonitor.spotPoolJoined({ +test("spotPoolExited", async () => { + await testSpotPoolExited({ limit: 1, }) + await testSpotPoolExited({}, defaultSpotPool) +}) + +const testSpotPoolJoined = async ( + args: QuerySpotPoolJoinedArgs, + fields?: SpotPoolJoined +) => { + const resp = await heartMonitor.spotPoolJoined(args, fields) expect(resp).toHaveProperty("spotPoolJoined") if ((resp.spotPoolJoined?.length ?? 0) > 0) { const [spotPoolJoined] = resp.spotPoolJoined ?? [] - const fields = ["user", "block", "pool", "pool_shares"] - fields.forEach((field: string) => { - expect(spotPoolJoined).toHaveProperty(field) - }) + + checkFields([spotPoolJoined], ["user", "block", "pool", "pool_shares"]) } -}) +} -test("spotPools", async () => { - const resp = await heartMonitor.spotPools({ +test("spotPoolJoined", async () => { + await testSpotPoolJoined({ limit: 1, }) + await testSpotPoolJoined({}, defaultSpotPool) +}) + +const testSpotPools = async (args: QuerySpotPoolsArgs, fields?: SpotPool) => { + const resp = await heartMonitor.spotPools(args, fields) expect(resp).toHaveProperty("spotPools") if ((resp.spotPools?.length ?? 0) > 0) { const [spotPools] = resp.spotPools ?? [] - const fields = [ - "pool_id", - "pool_type", - "swap_fee", - "exit_fee", - "amplification", - "tokens", - "weights", - "total_weight", - "total_shares", - "created_block", - ] - fields.forEach((field: string) => { - expect(spotPools).toHaveProperty(field) - }) + + checkFields( + [spotPools], + [ + "pool_id", + "pool_type", + "swap_fee", + "exit_fee", + "amplification", + "tokens", + "weights", + "total_weight", + "total_shares", + "created_block", + ] + ) } -}) +} -test("spotPoolSwap", async () => { - const resp = await heartMonitor.spotPoolSwap({ +test("spotPools", async () => { + await testSpotPools({ limit: 1, }) + await testSpotPools({}, defaultPool) +}) + +const testSpotPoolSwap = async ( + args: QuerySpotPoolSwapArgs, + fields?: SpotPoolSwap +) => { + const resp = await heartMonitor.spotPoolSwap(args, fields) expect(resp).toHaveProperty("spotPoolSwap") if ((resp.spotPoolSwap?.length ?? 0) > 0) { const [spotPoolSwap] = resp.spotPoolSwap ?? [] - const fields = ["user", "block", "token_in", "token_out", "pool"] - fields.forEach((field: string) => { - expect(spotPoolSwap).toHaveProperty(field) - }) + + checkFields( + [spotPoolSwap], + ["user", "block", "token_in", "token_out", "pool"] + ) } +} + +test("spotPoolSwap", async () => { + await testSpotPoolSwap({ limit: 1 }) + await testSpotPoolSwap({}, defaultSpotPoolSwap) }) +const testStats = async (args: QueryStatsArgs, fields?: StatsFields) => { + const resp = await heartMonitor.stats(args, fields) + expect(resp).toHaveProperty("stats") + + if (resp.stats) { + const { stats } = resp + + checkFields( + [stats], + [ + "totals", + "fees", + "perpOpenInterest", + "tvl", + "perpPnl", + "users", + "volume", + ] + ) + } +} + test("stats", async () => { - const resp = await heartMonitor.stats({ + await testStats({ totals: { limit: 1, }, @@ -579,86 +894,126 @@ test("stats", async () => { limit: 1, }, }) - expect(resp).toHaveProperty("stats") - - if (resp.stats) { - const { stats } = resp - const fields = [ - "totals", - "fees", - "perpOpenInterest", - "tvl", - "perpPnl", - "users", - "volume", - ] - fields.forEach((field: string) => { - expect(stats).toHaveProperty(field) - }) - } + await testStats( + { + totals: { + limit: 1, + }, + fees: { + limit: 1, + }, + perpOpenInterest: { + limit: 1, + }, + tvl: { + limit: 1, + }, + perpPnl: { + limit: 1, + }, + users: { + limit: 1, + }, + volume: { + limit: 1, + }, + }, + { + totals: defaultTotals, + fees: defaultStatsFees, + perpOpenInterest: defaultPerpOpenInterest, + tvl: defaultTvl, + perpPnl: defaultPerpPnl, + users: defaultUsers, + volume: defaultVolume, + } + ) + await testStats( + {}, + { + totals: defaultTotals, + fees: defaultStatsFees, + perpOpenInterest: defaultPerpOpenInterest, + tvl: defaultTvl, + perpPnl: defaultPerpPnl, + users: defaultUsers, + volume: defaultVolume, + } + ) }) -test("unbondings", async () => { - const resp = await heartMonitor.unbondings({ - limit: 1, - }) +const testUnbondings = async ( + args: QueryUnbondingsArgs, + fields?: Unbonding +) => { + const resp = await heartMonitor.unbondings(args, fields) expect(resp).toHaveProperty("unbondings") if ((resp.unbondings?.length ?? 0) > 0) { const [unbonding] = resp.unbondings ?? [] - const fields = [ - "delegator", - "validator", - "amount", - "creation_block", - "completion_time", - ] - fields.forEach((field: string) => { - expect(unbonding).toHaveProperty(field) - }) + + checkFields( + [unbonding], + ["delegator", "validator", "amount", "creation_block", "completion_time"] + ) } +} + +test("unbondings", async () => { + await testUnbondings({ limit: 1 }) + await testUnbondings({}, defaultUnbondings) }) -test("users", async () => { - const resp = await heartMonitor.users({ - limit: 1, - }) +const testUsers = async (args: QueryUsersArgs, fields?: User) => { + const resp = await heartMonitor.users(args, fields) + expect(resp).toHaveProperty("users") if ((resp.users?.length ?? 0) > 0) { const [users] = resp.users ?? [] - const fields = ["address", "balances", "created_block"] - fields.forEach((field: string) => { - expect(users).toHaveProperty(field) - }) + + checkFields([users], ["address", "balances", "created_block"]) } +} + +test("users", async () => { + await testUsers({ limit: 1 }) + await testUsers({}, defaultUser) }) -test("validators", async () => { - const resp = await heartMonitor.validators({ - limit: 1, - }) +const testValidators = async ( + args: QueryValidatorsArgs, + fields?: Validator +) => { + const resp = await heartMonitor.validators(args, fields) expect(resp).toHaveProperty("validators") if ((resp.validators?.length ?? 0) > 0) { const [validator] = resp.validators ?? [] - const fields = [ - "commission_rates", - "commission_update_time", - "delegator_shares", - "description", - "jailed", - "min_self_delegation", - "operator_address", - "status", - "tokens", - "unbonding_block", - "unbonding_time", - ] - fields.forEach((field: string) => { - expect(validator).toHaveProperty(field) - }) + + checkFields( + [validator], + [ + "commission_rates", + "commission_update_time", + "delegator_shares", + "description", + "jailed", + "min_self_delegation", + "operator_address", + "status", + "tokens", + "unbonding_block", + "unbonding_time", + ] + ) } +} +test("validators", async () => { + await testValidators({ + limit: 1, + }) + await testValidators({}, defaultValidator) }) describe("gql cleanResponse", () => { diff --git a/packages/indexer-nibi/src/heart-monitor.ts b/packages/indexer-nibi/src/heart-monitor.ts index 066db09e..c0d44264 100644 --- a/packages/indexer-nibi/src/heart-monitor.ts +++ b/packages/indexer-nibi/src/heart-monitor.ts @@ -1,10 +1,8 @@ -import WebSocket from "ws" +import { WebSocket } from "ws" import { Client, ExecutionResult, createClient } from "graphql-ws" -import { gqlEndptFromTmRpc } from "./gql" import { Delegation, DistributionCommission, - Governance, MarkPriceCandle, OraclePrice, PerpMarket, @@ -83,6 +81,7 @@ import { OracleFields, GqlOutOracle, oracle, + GovernanceFields, } from "./query" import { markPriceCandlesSubscription, @@ -98,6 +97,8 @@ import { queryBatchHandler } from "./batchHandlers/queryBatchHandler" /** IHeartMonitor is an interface for a Heart Monitor GraphQL API. * Each of its methods corresponds to a query function. */ export interface IHeartMonitor { + closeWebSocket: () => Promise + readonly communityPool: ( args: QueryCommunityPoolArgs, fields?: Partial @@ -115,7 +116,7 @@ export interface IHeartMonitor { readonly governance: ( args: QueryGovernanceArgs, - fields?: Partial + fields?: GovernanceFields ) => Promise readonly markPriceCandles: ( @@ -228,18 +229,12 @@ export class HeartMonitor implements IHeartMonitor { subscriptionClient: Client | undefined constructor( - gqlEndpt?: string | { endptTm: string }, + gqlEndpt?: string, webSocketUrl?: string, - webSocketImpl?: WebSocket + webSocketImpl?: typeof WebSocket ) { - const chain = gqlEndpt as { endptTm: string } - if (!gqlEndpt) { - this.gqlEndpt = this.defaultGqlEndpt - } else if (typeof gqlEndpt === "string") { + if (typeof gqlEndpt === "string") { this.gqlEndpt = gqlEndpt - } else if (chain?.endptTm) { - const endptFromRpc = gqlEndptFromTmRpc(chain?.endptTm) - this.gqlEndpt = endptFromRpc ?? this.defaultGqlEndpt } else { this.gqlEndpt = this.defaultGqlEndpt } @@ -252,6 +247,8 @@ export class HeartMonitor implements IHeartMonitor { } } + closeWebSocket = async () => this.subscriptionClient?.dispose() + communityPool = async ( args: QueryCommunityPoolArgs, fields?: Partial @@ -267,10 +264,8 @@ export class HeartMonitor implements IHeartMonitor { fields?: Partial ) => distributionCommissions(args, this.gqlEndpt, fields) - governance = async ( - args: QueryGovernanceArgs, - fields?: Partial - ) => governance(args, this.gqlEndpt, fields) + governance = async (args: QueryGovernanceArgs, fields?: GovernanceFields) => + governance(args, this.gqlEndpt, fields) markPriceCandles = async ( args: QueryMarkPriceCandlesArgs, diff --git a/packages/indexer-nibi/src/index.ts b/packages/indexer-nibi/src/index.ts index b7277459..a7715e33 100644 --- a/packages/indexer-nibi/src/index.ts +++ b/packages/indexer-nibi/src/index.ts @@ -1,4 +1,3 @@ -export * from "./enum" export * from "./query" export * from "./gql/generated" export * from "./gql" diff --git a/packages/indexer-nibi/src/query/governance.ts b/packages/indexer-nibi/src/query/governance.ts index 82983c14..93a333dd 100644 --- a/packages/indexer-nibi/src/query/governance.ts +++ b/packages/indexer-nibi/src/query/governance.ts @@ -2,63 +2,73 @@ import { defaultGovernance } from "../defaultObjects" import { convertObjectToPropertiesString, doGqlQuery, gqlQuery } from "../gql" import { Query, - Governance, GovernanceGovDepositsArgs, GovernanceGovProposalsArgs, GovernanceGovVotesArgs, + GovDeposit, + GovProposal, + GovVote, } from "../gql/generated" export type QueryGovernanceArgs = { - govDeposits: GovernanceGovDepositsArgs - govProposals: GovernanceGovProposalsArgs - govVotes: GovernanceGovVotesArgs + govDeposits?: GovernanceGovDepositsArgs + govProposals?: GovernanceGovProposalsArgs + govVotes?: GovernanceGovVotesArgs } export interface GqlOutGovernance { governance?: Query["governance"] } +export type GovernanceFields = Partial<{ + govDeposits?: Partial + govProposals?: Partial + govVotes?: Partial +}> + export const governanceQueryString = ( args: QueryGovernanceArgs, - fields?: Partial + fields?: GovernanceFields ) => { - const goveranceQuery: string[] = [] + const governanceQuery: string[] = [] - if (fields) { - if (fields?.govDeposits) { - goveranceQuery.push( - gqlQuery( - "govDeposits", - args.govDeposits, - convertObjectToPropertiesString(fields.govDeposits), - true - ) + if (fields?.govDeposits) { + governanceQuery.push( + gqlQuery( + "govDeposits", + args.govDeposits ?? {}, + convertObjectToPropertiesString(fields.govDeposits), + true ) - } + ) + } - if (fields?.govProposals) { - goveranceQuery.push( - gqlQuery( - "govProposals", - args.govProposals, - convertObjectToPropertiesString(fields.govProposals), - true - ) + if (fields?.govProposals) { + governanceQuery.push( + gqlQuery( + "govProposals", + args.govProposals ?? {}, + convertObjectToPropertiesString(fields.govProposals), + true ) - } + ) + } - if (fields?.govVotes) { - goveranceQuery.push( - gqlQuery( - "govVotes", - args.govVotes, - convertObjectToPropertiesString(fields.govVotes), - true - ) + if (fields?.govVotes) { + governanceQuery.push( + gqlQuery( + "govVotes", + args.govVotes ?? {}, + convertObjectToPropertiesString(fields.govVotes), + true ) - } - } else { - goveranceQuery.push( + ) + } + + // Default Objects + + if (args.govDeposits && !fields?.govDeposits) { + governanceQuery.push( gqlQuery( "govDeposits", args.govDeposits, @@ -66,8 +76,10 @@ export const governanceQueryString = ( true ) ) + } - goveranceQuery.push( + if (args.govProposals && !fields?.govProposals) { + governanceQuery.push( gqlQuery( "govProposals", args.govProposals, @@ -75,8 +87,10 @@ export const governanceQueryString = ( true ) ) + } - goveranceQuery.push( + if (args.govVotes && !fields?.govVotes) { + governanceQuery.push( gqlQuery( "govVotes", args.govVotes, @@ -88,7 +102,7 @@ export const governanceQueryString = ( return ` governance { - ${goveranceQuery.join("\n")} + ${governanceQuery.join("\n")} } ` } @@ -96,7 +110,7 @@ export const governanceQueryString = ( export const governance = async ( args: QueryGovernanceArgs, endpt: string, - fields?: Partial + fields?: GovernanceFields ): Promise => doGqlQuery( `{ diff --git a/packages/indexer-nibi/src/query/oracle.ts b/packages/indexer-nibi/src/query/oracle.ts index 3ad30248..189a53fb 100644 --- a/packages/indexer-nibi/src/query/oracle.ts +++ b/packages/indexer-nibi/src/query/oracle.ts @@ -56,7 +56,7 @@ export const oracleQueryString = ( oracleQuery.push( gqlQuery( "oraclePrices", - args.oraclePrices ?? {}, + args.oraclePrices, convertObjectToPropertiesString(defaultOraclePrice), true ) @@ -67,7 +67,7 @@ export const oracleQueryString = ( oracleQuery.push( gqlQuery( "oracles", - args.oracles ?? {}, + args.oracles, convertObjectToPropertiesString(defaultOracleEntry), true ) diff --git a/packages/indexer-nibi/src/query/perp.ts b/packages/indexer-nibi/src/query/perp.ts index 4732da28..30fe6e61 100644 --- a/packages/indexer-nibi/src/query/perp.ts +++ b/packages/indexer-nibi/src/query/perp.ts @@ -44,72 +44,73 @@ export type PerpFields = Partial<{ export const perpQueryString = (args: QueryPerpArgs, fields?: PerpFields) => { const perpQuery: string[] = [] - if (fields) { - if (fields?.leaderboard) { - perpQuery.push( - gqlQuery( - "leaderboard", - args?.leaderboard ?? {}, - convertObjectToPropertiesString(fields.leaderboard), - true - ) + if (fields?.leaderboard) { + perpQuery.push( + gqlQuery( + "leaderboard", + args.leaderboard ?? {}, + convertObjectToPropertiesString(fields.leaderboard), + true ) - } - - if (fields?.market) { - perpQuery.push( - gqlQuery( - "market", - args?.market ?? {}, - convertObjectToPropertiesString(fields.market), - true - ) + ) + } + + // Note: args.market must be defined + if (args.market && fields?.market) { + perpQuery.push( + gqlQuery( + "market", + args.market, + convertObjectToPropertiesString(fields.market), + true ) - } - - if (fields?.markets) { - perpQuery.push( - gqlQuery( - "markets", - args?.markets ?? {}, - convertObjectToPropertiesString(fields.markets), - true - ) + ) + } + + if (fields?.markets) { + perpQuery.push( + gqlQuery( + "markets", + args.markets ?? {}, + convertObjectToPropertiesString(fields.markets), + true ) - } - - if (fields?.position) { - perpQuery.push( - gqlQuery( - "position", - args?.position ?? {}, - convertObjectToPropertiesString(fields.position), - true - ) + ) + } + + // Note: args.position must be defined + if (args.position && fields?.position) { + perpQuery.push( + gqlQuery( + "position", + args.position, + convertObjectToPropertiesString(fields.position), + true ) - } - - if (fields?.positionChanges) { - perpQuery.push( - gqlQuery( - "positionChanges", - args?.positionChanges ?? {}, - convertObjectToPropertiesString(fields.positionChanges), - true - ) + ) + } + + // Note: args.positionChanges must be defined + if (args.positionChanges && fields?.positionChanges) { + perpQuery.push( + gqlQuery( + "positionChanges", + args.positionChanges, + convertObjectToPropertiesString(fields.positionChanges), + true ) - } - - if (fields?.positions) { - perpQuery.push( - gqlQuery( - "positions", - args?.positions ?? {}, - convertObjectToPropertiesString(fields.positions), - true - ) + ) + } + + if (fields?.positions) { + perpQuery.push( + gqlQuery( + "positions", + args.positions ?? {}, + convertObjectToPropertiesString(fields.positions), + true ) - } + ) } // Default Objects @@ -118,7 +119,7 @@ export const perpQueryString = (args: QueryPerpArgs, fields?: PerpFields) => { perpQuery.push( gqlQuery( "leaderboard", - args.leaderboard ?? {}, + args.leaderboard, convertObjectToPropertiesString(defaultPerpLeaderboard), true ) @@ -129,7 +130,7 @@ export const perpQueryString = (args: QueryPerpArgs, fields?: PerpFields) => { perpQuery.push( gqlQuery( "market", - args.market ?? {}, + args.market, convertObjectToPropertiesString(defaultPerpMarket), true ) @@ -140,7 +141,7 @@ export const perpQueryString = (args: QueryPerpArgs, fields?: PerpFields) => { perpQuery.push( gqlQuery( "markets", - args.markets ?? {}, + args.markets, convertObjectToPropertiesString(defaultPerpMarket), true ) @@ -151,7 +152,7 @@ export const perpQueryString = (args: QueryPerpArgs, fields?: PerpFields) => { perpQuery.push( gqlQuery( "position", - args.position ?? {}, + args.position, convertObjectToPropertiesString(defaultPerpPosition), true ) @@ -162,18 +163,18 @@ export const perpQueryString = (args: QueryPerpArgs, fields?: PerpFields) => { perpQuery.push( gqlQuery( "positionChanges", - args.positionChanges ?? {}, + args.positionChanges, convertObjectToPropertiesString(defaultPerpPositionChanges), true ) ) } - if (args.position && !fields?.positionChanges) { + if (args.positions && !fields?.positions) { perpQuery.push( gqlQuery( "positions", - args.positions ?? {}, + args.positions, convertObjectToPropertiesString(defaultPerpPosition), true ) diff --git a/packages/indexer-nibi/src/query/stats.ts b/packages/indexer-nibi/src/query/stats.ts index 27580274..e2b83336 100644 --- a/packages/indexer-nibi/src/query/stats.ts +++ b/packages/indexer-nibi/src/query/stats.ts @@ -60,7 +60,7 @@ export const statsQueryString = ( statsQuery.push( gqlQuery( "fees", - args?.fees ?? {}, + args.fees ?? {}, convertObjectToPropertiesString(fields.fees), true ) @@ -71,7 +71,7 @@ export const statsQueryString = ( statsQuery.push( gqlQuery( "perpOpenInterest", - args?.perpOpenInterest ?? {}, + args.perpOpenInterest ?? {}, convertObjectToPropertiesString(fields.perpOpenInterest), true ) @@ -82,7 +82,7 @@ export const statsQueryString = ( statsQuery.push( gqlQuery( "perpPnl", - args?.perpPnl ?? {}, + args.perpPnl ?? {}, convertObjectToPropertiesString(fields.perpPnl), true ) @@ -93,7 +93,7 @@ export const statsQueryString = ( statsQuery.push( gqlQuery( "totals", - args?.totals ?? {}, + args.totals ?? {}, convertObjectToPropertiesString(fields.totals), true ) @@ -104,7 +104,7 @@ export const statsQueryString = ( statsQuery.push( gqlQuery( "tvl", - args?.tvl ?? {}, + args.tvl ?? {}, convertObjectToPropertiesString(fields.tvl), true ) @@ -115,7 +115,7 @@ export const statsQueryString = ( statsQuery.push( gqlQuery( "users", - args?.users ?? {}, + args.users ?? {}, convertObjectToPropertiesString(fields.users), true ) @@ -126,7 +126,7 @@ export const statsQueryString = ( statsQuery.push( gqlQuery( "volume", - args?.volume ?? {}, + args.volume ?? {}, convertObjectToPropertiesString(fields.volume), true ) @@ -139,7 +139,7 @@ export const statsQueryString = ( statsQuery.push( gqlQuery( "fees", - args.fees ?? {}, + args.fees, convertObjectToPropertiesString(defaultStatsFees), true ) @@ -150,7 +150,7 @@ export const statsQueryString = ( statsQuery.push( gqlQuery( "perpOpenInterest", - args.perpOpenInterest ?? {}, + args.perpOpenInterest, convertObjectToPropertiesString(defaultPerpOpenInterest), true ) @@ -161,7 +161,7 @@ export const statsQueryString = ( statsQuery.push( gqlQuery( "perpPnl", - args.perpPnl ?? {}, + args.perpPnl, convertObjectToPropertiesString(defaultPerpPnl), true ) @@ -172,7 +172,7 @@ export const statsQueryString = ( statsQuery.push( gqlQuery( "totals", - args.totals ?? {}, + args.totals, convertObjectToPropertiesString(defaultTotals), true ) @@ -183,7 +183,7 @@ export const statsQueryString = ( statsQuery.push( gqlQuery( "tvl", - args.tvl ?? {}, + args.tvl, convertObjectToPropertiesString(defaultTvl), true ) @@ -194,7 +194,7 @@ export const statsQueryString = ( statsQuery.push( gqlQuery( "users", - args.users ?? {}, + args.users, convertObjectToPropertiesString(defaultUsers), true ) @@ -205,7 +205,7 @@ export const statsQueryString = ( statsQuery.push( gqlQuery( "volume", - args.volume ?? {}, + args.volume, convertObjectToPropertiesString(defaultVolume), true ) diff --git a/packages/indexer-nibi/src/subscription/markPriceCandlesSubscription.ts b/packages/indexer-nibi/src/subscription/markPriceCandlesSubscription.ts index 38e70bf4..d006a888 100644 --- a/packages/indexer-nibi/src/subscription/markPriceCandlesSubscription.ts +++ b/packages/indexer-nibi/src/subscription/markPriceCandlesSubscription.ts @@ -24,7 +24,7 @@ export const markPriceCandlesSubscriptionQueryString = ( export const markPriceCandlesSubscription = async ( args: SubscriptionMarkPriceCandlesArgs, - client: Client | undefined, + client?: Client, fields?: Partial ): Promise< AsyncIterableIterator> | undefined diff --git a/packages/indexer-nibi/src/subscription/oraclePricesSubscription.ts b/packages/indexer-nibi/src/subscription/oraclePricesSubscription.ts index 5055d6de..18fffab5 100644 --- a/packages/indexer-nibi/src/subscription/oraclePricesSubscription.ts +++ b/packages/indexer-nibi/src/subscription/oraclePricesSubscription.ts @@ -28,7 +28,7 @@ export const oraclePricesSubscriptionQueryString = ( export const oraclePricesSubscription = async ( args: SubscriptionOraclePricesArgs, - client: Client | undefined, + client?: Client, fields?: Partial ): Promise< AsyncIterableIterator> | undefined diff --git a/packages/indexer-nibi/src/subscription/perpMarketSubscription.ts b/packages/indexer-nibi/src/subscription/perpMarketSubscription.ts index d15e632b..a05d23e9 100644 --- a/packages/indexer-nibi/src/subscription/perpMarketSubscription.ts +++ b/packages/indexer-nibi/src/subscription/perpMarketSubscription.ts @@ -28,7 +28,7 @@ export const perpMarketSubscriptionQueryString = ( export const perpMarketSubscription = async ( args: SubscriptionPerpMarketArgs, - client: Client | undefined, + client?: Client, fields?: Partial ): Promise< AsyncIterableIterator> | undefined diff --git a/packages/indexer-nibi/src/subscription/perpPositionsSubscription.ts b/packages/indexer-nibi/src/subscription/perpPositionsSubscription.ts index 086a0565..fffe5dfd 100644 --- a/packages/indexer-nibi/src/subscription/perpPositionsSubscription.ts +++ b/packages/indexer-nibi/src/subscription/perpPositionsSubscription.ts @@ -26,7 +26,7 @@ export const perpPositionsSubscriptionQueryString = ( export const perpPositionsSubscription = async ( args: SubscriptionPerpPositionsArgs, - client: Client | undefined, + client?: Client, fields?: Partial ): Promise< AsyncIterableIterator> | undefined diff --git a/packages/nibijs/README.md b/packages/nibijs/README.md index 747e013c..332438fb 100644 --- a/packages/nibijs/README.md +++ b/packages/nibijs/README.md @@ -65,7 +65,7 @@ The entrypoint for `nibijs` is the `Sdk` object, which is meant to mimic the roo ```js import { newRandomWallet, WalletHD } from "@nibiruchain/nibijs" -const wallet: WalletHD = await newRandomWallet() +const wallet = await newRandomWallet() const [{ address }] = await wallet.getAccounts() // Save the mnemonic somewhere to re-use the account diff --git a/packages/nibijs/docs/classes/StableSwap.md b/packages/nibijs/docs/classes/StableSwap.md index 6052893d..ac424a9f 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/intro.md b/packages/nibijs/docs/intro.md index 75c0432d..23611246 100644 --- a/packages/nibijs/docs/intro.md +++ b/packages/nibijs/docs/intro.md @@ -67,7 +67,7 @@ The entrypoint for `nibijs` is the `Sdk` object, which is meant to mimic the roo ```js import { newRandomWallet, WalletHD } from "@nibiruchain/nibijs" -const wallet: WalletHD = await newRandomWallet() +const wallet = await newRandomWallet() const [{ address }] = await wallet.getAccounts() // Save the mnemonic somewhere to re-use the account diff --git a/packages/nibijs/docs/modules.md b/packages/nibijs/docs/modules.md index 1bdaf3e0..9d2980e0 100644 --- a/packages/nibijs/docs/modules.md +++ b/packages/nibijs/docs/modules.md @@ -76,7 +76,6 @@ - [fromSdkDec](modules.md#fromsdkdec) - [fromSdkDecSafe](modules.md#fromsdkdecsafe) - [fromSdkInt](modules.md#fromsdkint) -- [getKeplr](modules.md#getkeplr) - [getRegistry](modules.md#getregistry) - [go](modules.md#go) - [instanceOfError](modules.md#instanceoferror) @@ -402,26 +401,6 @@ Constructs a faucet URL from a Chain object. --- -### getKeplr - -▸ **getKeplr**(`chain`): `Promise`<`Keplr`\> - -#### Parameters - -| Name | Type | -| :------ | :----------------------------- | -| `chain` | [`Chain`](interfaces/Chain.md) | - -#### Returns - -`Promise`<`Keplr`\> - -#### Defined in - -[wallet/keplr.ts:8](https://github.com/NibiruChain/ts-sdk/blob/f9e55f7/packages/nibijs/src/wallet/keplr.ts#L8) - ---- - ### getRegistry ▸ **getRegistry**(): `Registry` diff --git a/packages/nibijs/src/chain/types.ts b/packages/nibijs/src/chain/types.ts index e88ebd49..749b8709 100644 --- a/packages/nibijs/src/chain/types.ts +++ b/packages/nibijs/src/chain/types.ts @@ -1,25 +1,11 @@ -import { - AccountData, - Coin, - coin as newCoin, - coins as newCoins, - DirectSecp256k1HdWallet as WalletHD, - parseCoins, -} from "@cosmjs/proto-signing" +import { Coin } from "@cosmjs/proto-signing" import BigNumber from "bignumber.js" -import { instanceOfError } from "./error" - -export { AccountData, newCoin, newCoins, Coin, parseCoins, WalletHD } export const go = async (promise: Promise) => { try { return { res: await promise, err: undefined } } catch (err) { - if (instanceOfError(err)) { - return { res: undefined, err } - } else { - return { res: undefined, err: new Error(`${err}`) } - } + return { res: undefined, err: (err as Error).message } } } diff --git a/packages/nibijs/src/index.ts b/packages/nibijs/src/index.ts index 61617d27..269512de 100644 --- a/packages/nibijs/src/index.ts +++ b/packages/nibijs/src/index.ts @@ -3,4 +3,3 @@ export * from "./msg" export * from "./query" export * from "./stableswap" export * from "./tx" -export * from "./wallet" diff --git a/packages/nibijs/src/query/spot.ts b/packages/nibijs/src/query/spot.ts index 280bc284..f9ff7258 100644 --- a/packages/nibijs/src/query/spot.ts +++ b/packages/nibijs/src/query/spot.ts @@ -1,4 +1,5 @@ import { createProtobufRpcClient, QueryClient } from "@cosmjs/stargate" +import { Coin } from "@cosmjs/proto-signing" import { Pool, PoolParams } from "@nibiruchain/protojs/dist/nibiru/spot/v1/pool" import { QueryClientImpl as SpotQueryClientImpl, @@ -35,7 +36,7 @@ import { QueryTotalSharesRequest, QueryTotalSharesResponse, } from "@nibiruchain/protojs/dist/nibiru/spot/v1/query" -import { Coin, fromSdkDec } from "../chain" +import { fromSdkDec } from "../chain" function transformPoolParams(pp?: PoolParams): PoolParams | undefined { if (pp) { diff --git a/packages/nibijs/src/test/chain.test.ts b/packages/nibijs/src/test/chain.test.ts index 400019e5..e0b62819 100644 --- a/packages/nibijs/src/test/chain.test.ts +++ b/packages/nibijs/src/test/chain.test.ts @@ -1,12 +1,13 @@ import { SigningStargateClient } from "@cosmjs/stargate" +import { Coin, coin } from "@cosmjs/proto-signing" import { assert, Chain, - Coin, CoinMap, CustomChain, + fromSdkInt, + go, isRestEndptLive, - newCoin, newCoinMapFromCoins, queryChainIdWithRest, } from "../chain" @@ -41,14 +42,23 @@ describe("chain connections", () => { }) }) +describe("chain/parse", () => { + test("fromSdkInt", () => { + const result = fromSdkInt("123456789.987654321") + + expect(result).toEqual(123456789) + }) +}) + describe("chain/types", () => { const coinsIn: Coin[] = [ - newCoin(10, "unusd"), - newCoin(50, "unibi"), + coin(10, "unusd"), + coin(50, "unibi"), { amount: "42.42", denom: "uatom" }, { amount: "16800456610195729831", denom: "nibiru/pool/2" }, { denom: "unibi2", amount: "21519262" }, ] + test("coin map fns", () => { const coins: CoinMap = newCoinMapFromCoins(coinsIn) expect(coins.unusd.toString()).toBe("10") @@ -57,6 +67,13 @@ describe("chain/types", () => { expect(coins.unibi2.toString()).toBe("21519262") expect(coins["nibiru/pool/2"].toString()).toBe("16800456610195729831") }) + + test("go", async () => { + const error = Error("Failure") + const result = await go(Promise.reject(error)) + expect(result.err).toEqual(error.message) + expect(result.res).toBeUndefined() + }) }) test("custom assert fn", () => { diff --git a/packages/nibijs/src/test/faucet.test.ts b/packages/nibijs/src/test/faucet.test.ts index 99404317..f8fde098 100644 --- a/packages/nibijs/src/test/faucet.test.ts +++ b/packages/nibijs/src/test/faucet.test.ts @@ -1,12 +1,11 @@ import { assertIsDeliverTxSuccess, DeliverTxResponse } from "@cosmjs/stargate" +import { coins } from "@cosmjs/proto-signing" import { fetch } from "cross-fetch" import { Chain, faucetUrlFromChain, newCoinMapFromCoins, - newCoins, useFaucet, - WalletHD, } from "../chain" import { newRandomWallet, @@ -26,7 +25,7 @@ jest.mock("cross-fetch", () => ({ // In this case, this test can be skipped and checked it manually. // eslint-disable-next-line jest/no-disabled-tests test.skip("faucet utility works", async () => { - const wallet: WalletHD = await newRandomWallet() + const wallet = await newRandomWallet() const [{ address: toAddr }] = await wallet.getAccounts() const validator = await newSignerFromMnemonic(TEST_MNEMONIC) @@ -39,7 +38,7 @@ test.skip("faucet utility works", async () => { const txResp: DeliverTxResponse = await signingClient.sendTokens( fromAddr, toAddr, - newCoins(100, "unibi"), + coins(100, "unibi"), "auto" ) assertIsDeliverTxSuccess(txResp) diff --git a/packages/nibijs/src/test/signer.test.ts b/packages/nibijs/src/test/signer.test.ts index 7f009c83..4012da17 100644 --- a/packages/nibijs/src/test/signer.test.ts +++ b/packages/nibijs/src/test/signer.test.ts @@ -1,8 +1,7 @@ -import { WalletHD } from "../chain/types" import { newRandomWallet, newSignerFromMnemonic } from "../tx/signer" test("newRandomWallet", async () => { - const wallet: WalletHD = await newRandomWallet(24) + const wallet = await newRandomWallet(24) const [{ address }] = await wallet.getAccounts() expect(address).toHaveLength(43) expect(wallet.mnemonic.split(" ")).toHaveLength(24) @@ -15,7 +14,7 @@ test("newSignerFromMnemonic", async () => { const mnemonic = "honey club license water device crew gap hidden prize debate enhance true absent vibrant image pitch audit beef ability shadow dog label fetch cup" const addressForMnemonic = "nibi1qdk4jkwghcq7lz9uf28tf3qcy3appa42k8wxzg" - const wallet: WalletHD = await newSignerFromMnemonic(mnemonic) + const wallet = await newSignerFromMnemonic(mnemonic) const [{ address }] = await wallet.getAccounts() expect(address).toEqual(addressForMnemonic) }) diff --git a/packages/nibijs/src/test/stableswap.test.ts b/packages/nibijs/src/test/stableswap.test.ts index 756dadbb..62eda12c 100644 --- a/packages/nibijs/src/test/stableswap.test.ts +++ b/packages/nibijs/src/test/stableswap.test.ts @@ -34,4 +34,14 @@ describe("stableswap tests", () => { ).toEqual(true) }) }) + + test("Stableswap failure", () => { + const balances = [BigNumber(0), BigNumber(0)] + const amplification = BigNumber(0) + const curveModel = new StableSwap(amplification, balances, BigNumber(0)) + + expect(() => curveModel.exchange(0, 1, BigNumber(0))).toThrow( + "Invalid exchange operation" + ) + }) }) diff --git a/packages/nibijs/src/tx/signer.test.ts b/packages/nibijs/src/tx/signer.test.ts new file mode 100644 index 00000000..a2b9a779 --- /dev/null +++ b/packages/nibijs/src/tx/signer.test.ts @@ -0,0 +1,41 @@ +import { DirectSecp256k1HdWallet, Registry } from "@cosmjs/proto-signing" +import { getRegistry, newRandomWallet, newSignerFromMnemonic } from "./signer" + +describe("signer tests", () => { + test("getRegistry", () => { + const testResult = getRegistry() + + expect(testResult).toBeInstanceOf(Registry) + expect(testResult.encode).toBeTruthy() + expect(testResult.decode).toBeTruthy() + expect(testResult.decodeTxBody).toBeTruthy() + expect(testResult.encodeAsAny).toBeTruthy() + expect(testResult.encodeTxBody).toBeTruthy() + expect(testResult.lookupType).toBeTruthy() + expect(testResult.register).toBeTruthy() + }) + + test("newSignerFromMnemonic", async () => { + const mnemonic = + "guard cream sadness conduct invite crumble clock pudding hole grit liar hotel maid produce squeeze return argue turtle know drive eight casino maze host" + const testResult = await newSignerFromMnemonic(mnemonic) + + expect(testResult).toBeInstanceOf(DirectSecp256k1HdWallet) + expect(testResult.getAccounts).toBeTruthy() + expect(testResult.mnemonic).toEqual(mnemonic) + expect(testResult.serialize).toBeTruthy() + expect(testResult.serializeWithEncryptionKey).toBeTruthy() + expect(testResult.signDirect).toBeTruthy() + }) + + test("newRandomWallet", async () => { + const testResult = await newRandomWallet() + + expect(testResult).toBeInstanceOf(DirectSecp256k1HdWallet) + expect(testResult.getAccounts).toBeTruthy() + expect(testResult.mnemonic).toBeTruthy() + expect(testResult.serialize).toBeTruthy() + expect(testResult.serializeWithEncryptionKey).toBeTruthy() + expect(testResult.signDirect).toBeTruthy() + }) +}) diff --git a/packages/nibijs/src/tx/signer.ts b/packages/nibijs/src/tx/signer.ts index 15b36d4f..85cc56fd 100644 --- a/packages/nibijs/src/tx/signer.ts +++ b/packages/nibijs/src/tx/signer.ts @@ -1,6 +1,5 @@ import { DirectSecp256k1HdWallet, Registry } from "@cosmjs/proto-signing" import { defaultRegistryTypes as defaultStargateTypes } from "@cosmjs/stargate" -import { Keplr } from "../wallet" export enum BECH32_PREFIX { /** ADDR defines the Bech32 prefix of an account address */ @@ -32,9 +31,6 @@ export const newSignerFromMnemonic = async ( prefix = BECH32_PREFIX.ADDR ) => DirectSecp256k1HdWallet.fromMnemonic(mnemonic, { prefix }) -export const newSignerFromKeplr = (keplr: Keplr, chainId: string) => - keplr.getOfflineSigner(chainId) - /** * Generates a new wallet with a BIP39 mnemonic of length 24. * diff --git a/packages/nibijs/src/tx/signingClient.test.ts b/packages/nibijs/src/tx/signingClient.test.ts index 56c6e8cf..9f6f150a 100644 --- a/packages/nibijs/src/tx/signingClient.test.ts +++ b/packages/nibijs/src/tx/signingClient.test.ts @@ -13,7 +13,7 @@ import { MsgRemoveMargin, } from "@nibiruchain/protojs/dist/nibiru/perp/v2/tx" import { Direction } from "@nibiruchain/protojs/dist/nibiru/perp/v2/state" -import { TxLog } from "../chain/types" +import { TxLog } from "../chain" import { Msg, TxMessage } from "../msg" import { PERP_MSG_TYPE_URLS } from "../msg/perp" import { NibiruQueryClient } from "../query/query" @@ -48,7 +48,7 @@ describe("nibid tx bank send", () => { signer ) - const toWallet: DirectSecp256k1HdWallet = await newRandomWallet() + const toWallet = await newRandomWallet() const [{ address: toAddr }] = await toWallet.getAccounts() const resp = await signingClient.sendTokens( diff --git a/packages/nibijs/src/tx/signingClient.ts b/packages/nibijs/src/tx/signingClient.ts index 4a6c430a..ae51c081 100644 --- a/packages/nibijs/src/tx/signingClient.ts +++ b/packages/nibijs/src/tx/signingClient.ts @@ -38,6 +38,31 @@ export class NibiruSigningClient extends SigningStargateClient { public readonly nibiruExtensions: NibiruExtensions public readonly wasmClient: SigningCosmWasmClient + protected constructor( + tmClient: Tendermint37Client, + signer: OfflineSigner, + options: SigningStargateClientOptions, + wasm: SigningCosmWasmClient + ) { + super(tmClient, signer, options) + this.wasmClient = wasm + this.nibiruExtensions = QueryClient.withExtensions( + tmClient, + setupEpochsExtension, + setupOracleExtension, + setupPerpExtension, + setupSpotExtension, + setupSudoExtension, + setupInflationExtension, + setupDistributionExtension, + setupGovExtension, + setupStakingExtension, + setupIbcExtension, + setupWasmExtension, + setupAuthExtension + ) + } + public static async connectWithSigner( endpoint: string, signer: OfflineSigner, @@ -66,31 +91,6 @@ export class NibiruSigningClient extends SigningStargateClient { ) } - protected constructor( - tmClient: Tendermint37Client, - signer: OfflineSigner, - options: SigningStargateClientOptions, - wasm: SigningCosmWasmClient - ) { - super(tmClient, signer, options) - this.wasmClient = wasm - this.nibiruExtensions = QueryClient.withExtensions( - tmClient, - setupEpochsExtension, - setupOracleExtension, - setupPerpExtension, - setupSpotExtension, - setupSudoExtension, - setupInflationExtension, - setupDistributionExtension, - setupGovExtension, - setupStakingExtension, - setupIbcExtension, - setupWasmExtension, - setupAuthExtension - ) - } - public async waitForHeight(height: number) { while ((await this.getHeight()) < height) { await new Promise((resolve) => { diff --git a/packages/nibijs/src/wallet/index.ts b/packages/nibijs/src/wallet/index.ts deleted file mode 100644 index a7551873..00000000 --- a/packages/nibijs/src/wallet/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./keplr" -export { Window as KeplrWindow, Keplr } from "@keplr-wallet/types" diff --git a/packages/nibijs/src/wallet/keplr.ts b/packages/nibijs/src/wallet/keplr.ts deleted file mode 100644 index 47c22761..00000000 --- a/packages/nibijs/src/wallet/keplr.ts +++ /dev/null @@ -1,125 +0,0 @@ -import { Window as KeplrWindow, Keplr } from "@keplr-wallet/types" -import { Chain } from "../chain" - -declare global { - interface Window extends KeplrWindow {} -} - -export const getKeplr = async (chain: Chain) => { - if ((window as any).keplr) { - throw Error("Keplr wallet not found") - } - const keplr: Keplr = window.keplr! - const { chainId } = chain - - try { - // Keplr v0.6.4 introduces an experimental feature that supports the feature to suggests the chain from a webpage. - // cosmoshub-3 is integrated to Keplr so the code should return without errors. - // The code below is not needed for cosmoshub-3, but may be helpful if you’re adding a custom chain. - // If the user approves, the chain will be added to the user's Keplr extension. - // If the user rejects it or the suggested chain information doesn't include the required fields, it will throw an error. - // If the same chain id is already registered, it will resolve and not require the user interactions. - await keplr.experimentalSuggestChain({ - // Chain-id of the Osmosis chain. - chainId, - // The name of the chain to be displayed to the user. - chainName: chain.chainName, - // RPC endpoint of the chain. In this case we are using blockapsis, as it's accepts connections from any host currently. No Cors limitations. - // NOTE add http:// if this doesn't connect - // rpc: chain.endptGrpc, // Q: When does this need to switch to gRPC instead of TM? - rpc: chain.endptTm, - // REST endpoint of the chain. - rest: chain.endptRest, - // Staking coin information - stakeCurrency: { - // Coin denomination to be displayed to the user. - coinDenom: "NIBI", - // Actual denom (i.e. uatom, uscrt) used by the blockchain. - coinMinimalDenom: "unibi", - // # of decimal points to convert minimal denomination to user-facing denomination. - coinDecimals: 6, - // (Optional) Keplr can show the fiat value of the coin if a coingecko id is provided. - // You can get id from https://api.coingecko.com/api/v3/coins/list if it is listed. - // coinGeckoId: "" - }, - // (Optional) If you have a wallet webpage used to stake the coin then provide the url to the website in `walletUrlForStaking`. - // The 'stake' button in Keplr extension will link to the webpage. - // walletUrlForStaking: "", - // The BIP44 path. - bip44: { - // You can only set the coin type of BIP44. - // 'Purpose' is fixed to 44. - // (Optional) The number of the coin type. - // This field is only used to fetch the address from ENS. - // Ideally, it is recommended to be the same with BIP44 path's coin type. - // However, some early chains may choose to use the Cosmos Hub BIP44 path of '118'. - // So, this is separated to support such chains. - coinType: 118, - }, - // Bech32 configuration to show the address to user. - // This field is the interface of - // { - // bech32PrefixAccAddr: string; - // bech32PrefixAccPub: string; - // bech32PrefixValAddr: string; - // bech32PrefixValPub: string; - // bech32PrefixConsAddr: string; - // bech32PrefixConsPub: string; - // } - bech32Config: { - bech32PrefixAccAddr: "nibi", - bech32PrefixAccPub: "nibipub", - bech32PrefixValAddr: "nibivaloper", - bech32PrefixValPub: "nibivaloperpub", - bech32PrefixConsAddr: "nibivalcons", - bech32PrefixConsPub: "nibivalconspub", - }, - // List of all coin/tokens used in this chain. - currencies: [ - { - // Coin denomination to be displayed to the user. - coinDenom: "unibi", - // Actual denom (i.e. uatom, uscrt) used by the blockchain. - coinMinimalDenom: "unibi", - // # of decimal points to convert minimal denomination to user-facing denomination. - coinDecimals: 6, - // (Optional) Keplr can show the fiat value of the coin if a coingecko id is provided. - // You can get id from https://api.coingecko.com/api/v3/coins/list if it is listed. - // coinGeckoId: "" - }, - ], - // List of coin/tokens used as a fee token in this chain. - feeCurrencies: [ - { - // Coin denomination to be displayed to the user. - coinDenom: "unibi", - // Actual denom (i.e. uosmo, uscrt) used by the blockchain. - coinMinimalDenom: "unibi", - // # of decimal points to convert minimal denomination to user-facing denomination. - coinDecimals: 6, - // (Optional) Keplr can show the fiat value of the coin if a coingecko id is provided. - // You can get id from https://api.coingecko.com/api/v3/coins/list if it is listed. - // coinGeckoId: "" - // (Optional) This is used to set the fee of the transaction. - // If this field is not provided, Keplr extension will set the default gas price as (low: 0.01, average: 0.025, high: 0.04). - // Currently, Keplr doesn't support dynamic calculation of the gas prices based on on-chain data. - // Make sure that the gas prices are higher than the minimum gas prices accepted by chain validators and RPC/REST endpoint. - gasPriceStep: { - low: 0.01, - average: 0.025, - high: 0.04, - }, - }, - ], - }) - } catch { - throw Error("Failed to suggest Nibiru chain to Keplr wallet") - } - - // Enabling before using the Keplr is recommended. - // This method will ask the user whether to allow access if they haven't visited this website. - // Also, it will request that the user unlock the wallet if the wallet is locked. - await keplr.enable(chainId) - - return keplr -}