diff --git a/CHANGELOG.md b/CHANGELOG.md index 580a20fa..5e9e0a31 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,9 +23,9 @@ - @cosmjs/faucet: Environmental variable `FAUCET_FEE` renamed to `FAUCET_GAS_PRICE` and now only accepts one token. Environmental variable `FAUCET_GAS` renamed to `FAUCET_GAS_LIMIT`. -- @cosmjs/faucet: `/credit` API now accepts either `denom` (base token) or as - before `ticker` (unit token). Environmental variables specifying credit - amounts now need to use uppercase denom. +- @cosmjs/faucet: `/credit` API now expects `denom` (base token) instead of + `ticker` (unit token). Environmental variables specifying credit amounts now + need to use uppercase denom. - @cosmjs/launchpad: Rename `FeeTable` type to `CosmosFeeTable` and export a new more generic type `FeeTable`. - @cosmjs/launchpad: Add new class `GasPrice`, new helper type `GasLimits` and diff --git a/packages/faucet/README.md b/packages/faucet/README.md index c191adbf..da3f175d 100644 --- a/packages/faucet/README.md +++ b/packages/faucet/README.md @@ -124,7 +124,7 @@ situation is different. ``` curl --header "Content-Type: application/json" \ --request POST \ - --data '{"ticker":"ISA","address":"cosmos1yre6ac7qfgyfgvh58ph0rgw627rhw766y430qq"}' \ + --data '{"denom":"ucosm","address":"cosmos1yre6ac7qfgyfgvh58ph0rgw627rhw766y430qq"}' \ http://localhost:8000/credit ``` diff --git a/packages/faucet/src/api/requestparser.spec.ts b/packages/faucet/src/api/requestparser.spec.ts index 1171ff5a..c8ae110c 100644 --- a/packages/faucet/src/api/requestparser.spec.ts +++ b/packages/faucet/src/api/requestparser.spec.ts @@ -6,9 +6,16 @@ describe("RequestParser", () => { expect(RequestParser.parseCreditBody(body)).toEqual({ address: "abc", denom: "utkn" }); }); - it("can process valid credit request with ticker", () => { - const body = { address: "abc", ticker: "TKN" }; - expect(RequestParser.parseCreditBody(body)).toEqual({ address: "abc", ticker: "TKN" }); + it("throws helpful error message when ticker is found", () => { + const oldBody = { address: "abc", ticker: "TKN" }; + expect(() => RequestParser.parseCreditBody(oldBody)).toThrowError( + /The 'ticker' field was removed in CosmJS 0.23. Please use 'denom' instead./i, + ); + + const confusedBody = { address: "abc", ticker: "TKN", denom: "utkn" }; + expect(() => RequestParser.parseCreditBody(confusedBody)).toThrowError( + /The 'ticker' field was removed in CosmJS 0.23. Please use 'denom' instead./i, + ); }); it("throws for invalid credit requests", () => { @@ -26,44 +33,32 @@ describe("RequestParser", () => { // address unset { - const body = { ticker: "TKN" }; + const body = { denom: "utkn" }; expect(() => RequestParser.parseCreditBody(body)).toThrowError(/Property 'address' must be a string/i); } // address wrong type { - const body = { address: true, ticker: "TKN" }; + const body = { address: true, denom: "utkn" }; expect(() => RequestParser.parseCreditBody(body)).toThrowError(/Property 'address' must be a string/i); } // address empty { - const body = { address: "", ticker: "TKN" }; + const body = { address: "", denom: "utkn" }; expect(() => RequestParser.parseCreditBody(body)).toThrowError(/Property 'address' must not be empty/i); } - // denom and ticker unset + // denom unset { const body = { address: "abc" }; - expect(() => RequestParser.parseCreditBody(body)).toThrowError( - /Exactly one of properties 'denom' or 'ticker' must be a string/i, - ); - } - - // denom and ticker both set - { - const body = { address: "abc", denom: "ustake", ticker: "COSM" }; - expect(() => RequestParser.parseCreditBody(body)).toThrowError( - /Exactly one of properties 'denom' or 'ticker' must be a string/i, - ); + expect(() => RequestParser.parseCreditBody(body)).toThrowError(/Property 'denom' must be a string/i); } // denom wrong type { const body = { address: "abc", denom: true }; - expect(() => RequestParser.parseCreditBody(body)).toThrowError( - /Exactly one of properties 'denom' or 'ticker' must be a string/i, - ); + expect(() => RequestParser.parseCreditBody(body)).toThrowError(/Property 'denom' must be a string/i); } // denom empty @@ -71,19 +66,5 @@ describe("RequestParser", () => { const body = { address: "abc", denom: "" }; expect(() => RequestParser.parseCreditBody(body)).toThrowError(/Property 'denom' must not be empty/i); } - - // ticker wrong type - { - const body = { address: "abc", ticker: true }; - expect(() => RequestParser.parseCreditBody(body)).toThrowError( - /Exactly one of properties 'denom' or 'ticker' must be a string/i, - ); - } - - // ticker empty - { - const body = { address: "abc", ticker: "" }; - expect(() => RequestParser.parseCreditBody(body)).toThrowError(/Property 'ticker' must not be empty/i); - } }); }); diff --git a/packages/faucet/src/api/requestparser.ts b/packages/faucet/src/api/requestparser.ts index 1455b05f..2ff99d3c 100644 --- a/packages/faucet/src/api/requestparser.ts +++ b/packages/faucet/src/api/requestparser.ts @@ -2,7 +2,7 @@ import { isNonNullObject } from "@cosmjs/utils"; import { HttpError } from "./httperror"; -export interface CreditRequestBodyDataWithDenom { +export interface CreditRequestBodyData { /** The base denomination */ readonly denom: string; /** The recipient address */ @@ -16,14 +16,6 @@ export interface CreditRequestBodyDataWithTicker { readonly address: string; } -export type CreditRequestBodyData = CreditRequestBodyDataWithDenom | CreditRequestBodyDataWithTicker; - -export function isCreditRequestBodyDataWithDenom( - data: CreditRequestBodyData, -): data is CreditRequestBodyDataWithDenom { - return typeof (data as CreditRequestBodyDataWithDenom).denom === "string"; -} - export class RequestParser { public static parseCreditBody(body: unknown): CreditRequestBodyData { if (!isNonNullObject(body) || Array.isArray(body)) { @@ -32,6 +24,10 @@ export class RequestParser { const { address, denom, ticker } = body as any; + if (typeof ticker !== "undefined") { + throw new HttpError(400, "The 'ticker' field was removed in CosmJS 0.23. Please use 'denom' instead."); + } + if (typeof address !== "string") { throw new HttpError(400, "Property 'address' must be a string."); } @@ -40,29 +36,17 @@ export class RequestParser { throw new HttpError(400, "Property 'address' must not be empty."); } - if ( - (typeof denom !== "string" && typeof ticker !== "string") || - (typeof denom === "string" && typeof ticker === "string") - ) { - throw new HttpError(400, "Exactly one of properties 'denom' or 'ticker' must be a string"); + if (typeof denom !== "string") { + throw new HttpError(400, "Property 'denom' must be a string."); } - if (typeof ticker === "string" && ticker.length === 0) { - throw new HttpError(400, "Property 'ticker' must not be empty."); - } - - if (typeof denom === "string" && denom.length === 0) { + if (denom.length === 0) { throw new HttpError(400, "Property 'denom' must not be empty."); } - return denom - ? { - address: address, - denom: denom, - } - : { - address: address, - ticker: ticker, - }; + return { + address: address, + denom: denom, + }; } } diff --git a/packages/faucet/src/api/webserver.ts b/packages/faucet/src/api/webserver.ts index 474501eb..19961854 100644 --- a/packages/faucet/src/api/webserver.ts +++ b/packages/faucet/src/api/webserver.ts @@ -6,7 +6,7 @@ import { isValidAddress } from "../addresses"; import * as constants from "../constants"; import { Faucet } from "../faucet"; import { HttpError } from "./httperror"; -import { isCreditRequestBodyDataWithDenom, RequestParser } from "./requestparser"; +import { RequestParser } from "./requestparser"; /** This will be passed 1:1 to the user */ export interface ChainConstants { @@ -59,23 +59,14 @@ export class Webserver { const requestBody = context.request.body; const creditBody = RequestParser.parseCreditBody(requestBody); - const { address } = creditBody; - let denom: string | undefined; - let ticker: string | undefined; - if (isCreditRequestBodyDataWithDenom(creditBody)) { - ({ denom } = creditBody); - } else { - ({ ticker } = creditBody); - } + const { address, denom } = creditBody; if (!isValidAddress(address, constants.addressPrefix)) { throw new HttpError(400, "Address is not in the expected format for this chain."); } const availableTokens = await faucet.availableTokens(); - const matchingToken = availableTokens.find( - (token) => token.denom === denom || token.tickerSymbol === ticker, - ); + const matchingToken = availableTokens.find((token) => token.denom === denom); if (matchingToken === undefined) { const tokens = JSON.stringify(availableTokens); throw new HttpError(422, `Token is not available. Available tokens are: ${tokens}`);