diff --git a/packages/stargate/src/fee.spec.ts b/packages/stargate/src/fee.spec.ts index c2457a2c36..ec0839f367 100644 --- a/packages/stargate/src/fee.spec.ts +++ b/packages/stargate/src/fee.spec.ts @@ -51,16 +51,16 @@ describe("GasPrice", () => { expect(() => GasPrice.fromString("234")).toThrowError(/Invalid gas price string/i); expect(() => GasPrice.fromString("-234tkn")).toThrowError(/Invalid gas price string/i); // Checks details of - expect(() => GasPrice.fromString("234t")).toThrowError(/Invalid gas price string/i); - expect(() => GasPrice.fromString("234tt")).toThrowError(/Invalid gas price string/i); + expect(() => GasPrice.fromString("234t")).toThrowError(/denom must be between 3 and 128 characters/i); + expect(() => GasPrice.fromString("234tt")).toThrowError(/denom must be between 3 and 128 characters/i); expect(() => GasPrice.fromString( "234ttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt", ), - ).toThrowError(/Invalid gas price string/i); + ).toThrowError(/denom must be between 3 and 128 characters/i); // Checks details of - expect(() => GasPrice.fromString("3.utkn")).toThrowError(/Invalid gas price string/i); - expect(() => GasPrice.fromString("..utkn")).toThrowError(/Invalid gas price string/i); + expect(() => GasPrice.fromString("3.utkn")).toThrowError(/Fractional part missing/i); + expect(() => GasPrice.fromString("..utkn")).toThrowError(/More than one separator found/i); }); }); diff --git a/packages/stargate/src/fee.ts b/packages/stargate/src/fee.ts index a1332dd9c8..9ca8682a44 100644 --- a/packages/stargate/src/fee.ts +++ b/packages/stargate/src/fee.ts @@ -2,6 +2,18 @@ import { StdFee } from "@cosmjs/amino"; import { Decimal, Uint53 } from "@cosmjs/math"; import { coins } from "@cosmjs/proto-signing"; +/** + * Denom checker for the Cosmos SDK 0.42 denom pattern + * (https://github.com/cosmos/cosmos-sdk/blob/v0.42.4/types/coin.go#L599-L601). + * + * This is like a regexp but with helpful error messages. + */ +function checkDenom(denom: string): void { + if (denom.length < 3 || denom.length > 128) { + throw new Error("Denom must be between 3 and 128 characters"); + } +} + /** * A gas price, i.e. the price of a single unit of gas. This is typically a fraction of * the smallest fee token unit, such as 0.012utoken. @@ -25,11 +37,12 @@ export class GasPrice { */ public static fromString(gasPrice: string): GasPrice { // Use Decimal.fromUserInput and checkDenom for detailed checks and helpful error messages - const matchResult = gasPrice.match(/^(\d+(?:\.\d+)?|\.\d+)([a-zA-Z][a-zA-Z0-9/:._-]{2,127})$/i); + const matchResult = gasPrice.match(/^([0-9.]+)([a-zA-Z][a-zA-Z0-9/:._-]*)$/i); if (!matchResult) { throw new Error("Invalid gas price string"); } const [_, amount, denom] = matchResult; + checkDenom(denom); const fractionalDigits = 18; const decimalAmount = Decimal.fromUserInput(amount, fractionalDigits); return new GasPrice(decimalAmount, denom);