diff --git a/packages/amino/src/encoding.spec.ts b/packages/amino/src/encoding.spec.ts index 0a056e9826..387e075953 100644 --- a/packages/amino/src/encoding.spec.ts +++ b/packages/amino/src/encoding.spec.ts @@ -1,5 +1,6 @@ import { Random } from "@cosmjs/crypto"; import { fromBase64, fromBech32, fromHex } from "@cosmjs/encoding"; +import { TSError } from "ts-node"; import { decodeAminoPubkey, @@ -131,6 +132,17 @@ describe("encoding", () => { expect(() => decodeAminoPubkey(fromHex("22C1F7E20705"))).toThrowError(/expecting 0x08 prefix/i); }); + + it("throws error for invalid secp256k1 pubkey length", () => { + const data = new Uint8Array([0, 1, 2, 3, 4]); + try { + decodeAminoPubkey(data); + } catch (error) { + expect((error as TSError).message).toBe( + "Unsupported public key type. Amino data starts with: 0001020304", + ); + } + }); }); describe("decodeBech32Pubkey", () => { diff --git a/packages/amino/src/secp256k1hdwallet.spec.ts b/packages/amino/src/secp256k1hdwallet.spec.ts index 493e12bdc9..86958543ad 100644 --- a/packages/amino/src/secp256k1hdwallet.spec.ts +++ b/packages/amino/src/secp256k1hdwallet.spec.ts @@ -3,7 +3,7 @@ import { Secp256k1, Secp256k1Signature, sha256 } from "@cosmjs/crypto"; import { fromBase64, fromHex } from "@cosmjs/encoding"; import { makeCosmoshubPath } from "./paths"; -import { extractKdfConfiguration, Secp256k1HdWallet } from "./secp256k1hdwallet"; +import { extractKdfConfiguration, isDerivationJson, Secp256k1HdWallet } from "./secp256k1hdwallet"; import { serializeSignDoc, StdSignDoc } from "./signdoc"; import { base64Matcher } from "./testutils.spec"; import { executeKdf, KdfConfiguration } from "./wallet"; @@ -311,4 +311,46 @@ describe("Secp256k1HdWallet", () => { }); }); }); + + describe("isDerivationJson function", () => { + it("returns true for valid DerivationInfoJson", () => { + const validInput: unknown = { + hdPath: "validHdPath", + prefix: "validPrefix", + }; + expect(isDerivationJson(validInput)).toBe(true); + }); + + it("returns false for undefined input", () => { + expect(isDerivationJson(undefined)).toBe(false); + }); + + it("returns false for null input", () => { + expect(isDerivationJson(null)).toBe(false); + }); + + it("returns false for non-object input", () => { + expect(isDerivationJson(42)).toBe(false); + }); + + it("returns false for missing hdPath property", () => { + const missingHdPath: unknown = {}; + expect(isDerivationJson(missingHdPath)).toBe(false); + }); + + it("returns false for missing prefix property", () => { + const missingPrefix: unknown = { + hdPath: "validHdPath", + }; + expect(isDerivationJson(missingPrefix)).toBe(false); + }); + + it("returns false for incorrect hdPath type", () => { + const incorrectHdPathType: unknown = { + hdPath: 123, + prefix: "validPrefix", + }; + expect(isDerivationJson(incorrectHdPathType)).toBe(false); + }); + }); }); diff --git a/packages/amino/src/secp256k1hdwallet.ts b/packages/amino/src/secp256k1hdwallet.ts index c65644c09b..8aada72aed 100644 --- a/packages/amino/src/secp256k1hdwallet.ts +++ b/packages/amino/src/secp256k1hdwallet.ts @@ -71,7 +71,7 @@ interface DerivationInfoJson { readonly prefix: string; } -function isDerivationJson(thing: unknown): thing is DerivationInfoJson { +export function isDerivationJson(thing: unknown): thing is DerivationInfoJson { if (!isNonNullObject(thing)) return false; if (typeof (thing as DerivationInfoJson).hdPath !== "string") return false; if (typeof (thing as DerivationInfoJson).prefix !== "string") return false; diff --git a/packages/cli/src/helpers.spec.ts b/packages/cli/src/helpers.spec.ts index 6571d3cf40..65fa9dafea 100644 --- a/packages/cli/src/helpers.spec.ts +++ b/packages/cli/src/helpers.spec.ts @@ -1,6 +1,7 @@ +import { TSError } from "ts-node"; import { createContext } from "vm"; -import { executeJavaScript, executeJavaScriptAsync } from "./helpers"; +import { executeJavaScript, executeJavaScriptAsync, isRecoverable } from "./helpers"; describe("Helpers", () => { describe("executeJavaScript", () => { @@ -144,4 +145,22 @@ describe("Helpers", () => { expect(await executeJavaScriptAsync(code, "myfile.js", context)).toEqual("job done"); }); }); + + describe("isRecoverable", () => { + it("should return true for recoverable errors", () => { + const recoverableError = { + diagnosticCodes: [1003, 1160, 2355], + } as TSError; + + expect(isRecoverable(recoverableError)).toBe(true); + }); + + it("should return false for non-recoverable errors", () => { + const nonRecoverableError = { + diagnosticCodes: [1234, 5678], + } as TSError; + + expect(isRecoverable(nonRecoverableError)).toBe(false); + }); + }); });