Let faucet error when ticker field is found

This commit is contained in:
Simon Warta 2020-09-17 15:32:35 +02:00
parent 1eb02553dd
commit 97f0949ee2
5 changed files with 35 additions and 79 deletions

View File

@ -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

View File

@ -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
```

View File

@ -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);
}
});
});

View File

@ -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,
};
}
}

View File

@ -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}`);