From 795451ee14b3c87ec65a07d5a72a5215eaa7924b Mon Sep 17 00:00:00 2001 From: willclarktech Date: Wed, 19 Aug 2020 15:51:12 +0100 Subject: [PATCH 1/4] faucet: Refactor faucet to use denom Still accepts ticker via credit API request --- packages/faucet/src/api/requestparser.ts | 45 +++++++++++++++++++----- packages/faucet/src/api/webserver.ts | 20 ++++++++--- packages/faucet/src/debugging.ts | 4 +-- packages/faucet/src/faucet.ts | 24 ++++++------- packages/faucet/src/tokenmanager.ts | 38 ++++++++++++-------- 5 files changed, 88 insertions(+), 43 deletions(-) diff --git a/packages/faucet/src/api/requestparser.ts b/packages/faucet/src/api/requestparser.ts index 77dda0f7..1455b05f 100644 --- a/packages/faucet/src/api/requestparser.ts +++ b/packages/faucet/src/api/requestparser.ts @@ -2,20 +2,35 @@ import { isNonNullObject } from "@cosmjs/utils"; import { HttpError } from "./httperror"; -export interface CreditRequestBodyData { +export interface CreditRequestBodyDataWithDenom { + /** The base denomination */ + readonly denom: string; + /** The recipient address */ + readonly address: string; +} + +export interface CreditRequestBodyDataWithTicker { /** The ticker symbol */ readonly ticker: string; /** The recipient address */ 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)) { throw new HttpError(400, "Request body must be a dictionary."); } - const { address, ticker } = body as any; + const { address, denom, ticker } = body as any; if (typeof address !== "string") { throw new HttpError(400, "Property 'address' must be a string."); @@ -25,17 +40,29 @@ export class RequestParser { throw new HttpError(400, "Property 'address' must not be empty."); } - if (typeof ticker !== "string") { - throw new HttpError(400, "Property 'ticker' must be a string"); + 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 (ticker.length === 0) { + if (typeof ticker === "string" && ticker.length === 0) { throw new HttpError(400, "Property 'ticker' must not be empty."); } - return { - address: address, - ticker: ticker, - }; + if (typeof denom === "string" && denom.length === 0) { + throw new HttpError(400, "Property 'denom' must not be empty."); + } + + return denom + ? { + address: address, + denom: denom, + } + : { + address: address, + ticker: ticker, + }; } } diff --git a/packages/faucet/src/api/webserver.ts b/packages/faucet/src/api/webserver.ts index 12f4ccfc..474501eb 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 { RequestParser } from "./requestparser"; +import { isCreditRequestBodyDataWithDenom, RequestParser } from "./requestparser"; /** This will be passed 1:1 to the user */ export interface ChainConstants { @@ -57,20 +57,32 @@ export class Webserver { // context.request.body is set by the bodyParser() plugin const requestBody = context.request.body; - const { address, ticker } = RequestParser.parseCreditBody(requestBody); + const creditBody = RequestParser.parseCreditBody(requestBody); + + const { address } = creditBody; + let denom: string | undefined; + let ticker: string | undefined; + if (isCreditRequestBodyDataWithDenom(creditBody)) { + ({ denom } = creditBody); + } else { + ({ ticker } = 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(); - if (availableTokens.indexOf(ticker) === -1) { + const matchingToken = availableTokens.find( + (token) => token.denom === denom || token.tickerSymbol === ticker, + ); + if (matchingToken === undefined) { const tokens = JSON.stringify(availableTokens); throw new HttpError(422, `Token is not available. Available tokens are: ${tokens}`); } try { - await faucet.credit(address, ticker); + await faucet.credit(address, matchingToken.denom); } catch (e) { console.error(e); throw new HttpError(500, "Sending tokens failed"); diff --git a/packages/faucet/src/debugging.ts b/packages/faucet/src/debugging.ts index 9f6bec7d..b54bae26 100644 --- a/packages/faucet/src/debugging.ts +++ b/packages/faucet/src/debugging.ts @@ -1,5 +1,4 @@ import { Coin } from "@cosmjs/launchpad"; -import { Decimal } from "@cosmjs/math"; import { TokenConfiguration } from "./tokenmanager"; import { MinimalAccount, SendJob } from "./types"; @@ -8,8 +7,7 @@ import { MinimalAccount, SendJob } from "./types"; function debugCoin(coin: Coin, tokens: TokenConfiguration): string { const meta = tokens.bankTokens.find((token) => token.denom == coin.denom); if (!meta) throw new Error(`No token configuration found for denom ${coin.denom}`); - const value = Decimal.fromAtomics(coin.amount, meta.fractionalDigits).toString(); - return `${value} ${meta?.tickerSymbol}`; + return `${coin.amount} ${meta?.denom}`; } /** A string representation of a balance in a human-readable format that can change at any time */ diff --git a/packages/faucet/src/faucet.ts b/packages/faucet/src/faucet.ts index 910b6569..f4521010 100644 --- a/packages/faucet/src/faucet.ts +++ b/packages/faucet/src/faucet.ts @@ -10,6 +10,7 @@ import * as constants from "./constants"; import { debugAccount, logAccountsState, logSendJob } from "./debugging"; import { createWallets } from "./profile"; import { TokenConfiguration, TokenManager } from "./tokenmanager"; +import { BankTokenMeta } from "./tokens"; import { MinimalAccount, SendJob } from "./types"; function isDefined(value: X | undefined): value is X { @@ -74,15 +75,14 @@ export class Faucet { /** * Returns a list of ticker symbols of tokens owned by the the holder and configured in the faucet */ - public async availableTokens(): Promise { + public async availableTokens(): Promise { const holderAccount = await this.readOnlyClient.getAccount(this.holderAddress); const balance = holderAccount ? holderAccount.balance : []; return balance .filter((b) => b.amount !== "0") .map((b) => this.tokenConfig.bankTokens.find((token) => token.denom == b.denom)) - .filter(isDefined) - .map((token) => token.tickerSymbol); + .filter(isDefined); } /** @@ -94,14 +94,14 @@ export class Faucet { assertIsBroadcastTxSuccess(result); } - /** Use one of the distributor accounts to send tokend to user */ - public async credit(recipient: string, tickerSymbol: string): Promise { + /** Use one of the distributor accounts to send tokens to user */ + public async credit(recipient: string, denom: string): Promise { if (this.distributorAddresses.length === 0) throw new Error("No distributor account available"); const sender = this.distributorAddresses[this.getCreditCount() % this.distributorAddresses.length]; const job: SendJob = { sender: sender, recipient: recipient, - amount: this.tokenManager.creditAmount(tickerSymbol), + amount: this.tokenManager.creditAmount(denom), }; if (this.logging) logSendJob(job, this.tokenConfig); await this.send(job); @@ -141,17 +141,17 @@ export class Faucet { if (this.logging) logAccountsState(accounts, this.tokenConfig); const [_, ...distributorAccounts] = accounts; - const availableTokens = await this.availableTokens(); - if (this.logging) console.info("Available tokens:", availableTokens); + const availableTokenDenoms = (await this.availableTokens()).map((token) => token.denom); + if (this.logging) console.info("Available tokens:", availableTokenDenoms); const jobs: SendJob[] = []; - for (const tickerSymbol of availableTokens) { + for (const denom of availableTokenDenoms) { const refillDistibutors = distributorAccounts.filter((account) => - this.tokenManager.needsRefill(account, tickerSymbol), + this.tokenManager.needsRefill(account, denom), ); if (this.logging) { - console.info(`Refilling ${tickerSymbol} of:`); + console.info(`Refilling ${denom} of:`); console.info( refillDistibutors.length ? refillDistibutors.map((r) => ` ${debugAccount(r, this.tokenConfig)}`).join("\n") @@ -162,7 +162,7 @@ export class Faucet { jobs.push({ sender: this.holderAddress, recipient: refillDistibutor.address, - amount: this.tokenManager.refillAmount(tickerSymbol), + amount: this.tokenManager.refillAmount(denom), }); } } diff --git a/packages/faucet/src/tokenmanager.ts b/packages/faucet/src/tokenmanager.ts index cb4c8262..c15a785e 100644 --- a/packages/faucet/src/tokenmanager.ts +++ b/packages/faucet/src/tokenmanager.ts @@ -4,6 +4,8 @@ import { Decimal, Uint53 } from "@cosmjs/math"; import { BankTokenMeta } from "./tokens"; import { MinimalAccount } from "./types"; +const defaultCreditAmount = 10_000_000; + /** Send `factor` times credit amount on refilling */ const defaultRefillFactor = 20; @@ -23,46 +25,52 @@ export class TokenManager { } /** The amount of tokens that will be sent to the user */ - public creditAmount(tickerSymbol: string, factor: Uint53 = new Uint53(1)): Coin { - const amountFromEnv = process.env[`FAUCET_CREDIT_AMOUNT_${tickerSymbol}`]; - const amount = amountFromEnv ? Uint53.fromString(amountFromEnv).toNumber() : 10; + public creditAmount(denom: string, factor: Uint53 = new Uint53(1)): Coin { + const amountFromEnv = process.env[`FAUCET_CREDIT_AMOUNT_${denom.toUpperCase()}`]; + const amount = amountFromEnv ? Uint53.fromString(amountFromEnv).toNumber() : defaultCreditAmount; const value = new Uint53(amount * factor.toNumber()); - const meta = this.getTokenMeta(tickerSymbol); + const meta = this.getTokenMetaForDenom(denom); return { - amount: value.toString() + "0".repeat(meta.fractionalDigits), + amount: value.toString(), denom: meta.denom, }; } - public refillAmount(tickerSymbol: string): Coin { + public refillAmount(denom: string): Coin { const factorFromEnv = Number.parseInt(process.env.FAUCET_REFILL_FACTOR || "0", 10) || undefined; const factor = new Uint53(factorFromEnv || defaultRefillFactor); - return this.creditAmount(tickerSymbol, factor); + return this.creditAmount(denom, factor); } - public refillThreshold(tickerSymbol: string): Coin { + public refillThreshold(denom: string): Coin { const factorFromEnv = Number.parseInt(process.env.FAUCET_REFILL_THRESHOLD || "0", 10) || undefined; const factor = new Uint53(factorFromEnv || defaultRefillThresholdFactor); - return this.creditAmount(tickerSymbol, factor); + return this.creditAmount(denom, factor); } /** true iff the distributor account needs a refill */ - public needsRefill(account: MinimalAccount, tickerSymbol: string): boolean { - const meta = this.getTokenMeta(tickerSymbol); + public needsRefill(account: MinimalAccount, denom: string): boolean { + const meta = this.getTokenMetaForDenom(denom); const balanceAmount = account.balance.find((b) => b.denom === meta.denom); const balance = Decimal.fromAtomics(balanceAmount ? balanceAmount.amount : "0", meta.fractionalDigits); - const thresholdAmount = this.refillThreshold(tickerSymbol); + const thresholdAmount = this.refillThreshold(denom); const threshold = Decimal.fromAtomics(thresholdAmount.amount, meta.fractionalDigits); return balance.isLessThan(threshold); } - private getTokenMeta(tickerSymbol: string): BankTokenMeta { - const match = this.config.bankTokens.find((token) => token.tickerSymbol === tickerSymbol); - if (!match) throw new Error(`No token found for ticker symbol: ${tickerSymbol}`); + private getTokenMetaForDenom(denom: string): BankTokenMeta { + const match = this.config.bankTokens.find((token) => token.denom === denom); + if (!match) throw new Error(`No token found for denom: ${denom}`); + return match; + } + + private getTokenMetaForTicker(ticker: string): BankTokenMeta { + const match = this.config.bankTokens.find((token) => token.tickerSymbol === ticker); + if (!match) throw new Error(`No token found for ticker: ${ticker}`); return match; } } From 445b5065c0b5daf13cea88177d17a47df0249e07 Mon Sep 17 00:00:00 2001 From: willclarktech Date: Wed, 19 Aug 2020 15:51:32 +0100 Subject: [PATCH 2/4] faucet: Update tests for denom --- packages/faucet/src/api/requestparser.spec.ts | 39 +++++++- packages/faucet/src/faucet.spec.ts | 11 ++- packages/faucet/src/tokenmanager.spec.ts | 88 +++++++++---------- 3 files changed, 86 insertions(+), 52 deletions(-) diff --git a/packages/faucet/src/api/requestparser.spec.ts b/packages/faucet/src/api/requestparser.spec.ts index aeb53e38..1171ff5a 100644 --- a/packages/faucet/src/api/requestparser.spec.ts +++ b/packages/faucet/src/api/requestparser.spec.ts @@ -1,7 +1,12 @@ import { RequestParser } from "./requestparser"; describe("RequestParser", () => { - it("can process valid credit request", () => { + it("can process valid credit request with denom", () => { + const body = { address: "abc", denom: "utkn" }; + 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" }); }); @@ -37,16 +42,42 @@ describe("RequestParser", () => { expect(() => RequestParser.parseCreditBody(body)).toThrowError(/Property 'address' must not be empty/i); } - // ticker unset + // denom and ticker unset { const body = { address: "abc" }; - expect(() => RequestParser.parseCreditBody(body)).toThrowError(/Property 'ticker' must be a string/i); + 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, + ); + } + + // 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, + ); + } + + // denom empty + { + 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(/Property 'ticker' must be a string/i); + expect(() => RequestParser.parseCreditBody(body)).toThrowError( + /Exactly one of properties 'denom' or 'ticker' must be a string/i, + ); } // ticker empty diff --git a/packages/faucet/src/faucet.spec.ts b/packages/faucet/src/faucet.spec.ts index 5f664c48..f35b72fa 100644 --- a/packages/faucet/src/faucet.spec.ts +++ b/packages/faucet/src/faucet.spec.ts @@ -53,11 +53,14 @@ describe("Faucet", () => { expect(tickers).toEqual([]); }); - it("is empty when no tokens are configured", async () => { + it("is not empty with default token config", async () => { pendingWithoutWasmd(); const faucet = await Faucet.make(httpUrl, defaultAddressPrefix, defaultTokenConfig, faucetMnemonic, 3); const tickers = await faucet.availableTokens(); - expect(tickers).toEqual(["COSM", "STAKE"]); + expect(tickers).toEqual([ + { denom: "ucosm", tickerSymbol: "COSM", fractionalDigits: 6 }, + { denom: "ustake", tickerSymbol: "STAKE", fractionalDigits: 6 }, + ]); }); }); @@ -113,7 +116,7 @@ describe("Faucet", () => { pendingWithoutWasmd(); const faucet = await Faucet.make(httpUrl, defaultAddressPrefix, defaultTokenConfig, faucetMnemonic, 3); const recipient = makeRandomAddress(); - await faucet.credit(recipient, "COSM"); + await faucet.credit(recipient, "ucosm"); const readOnlyClient = new CosmosClient(httpUrl); const account = await readOnlyClient.getAccount(recipient); @@ -130,7 +133,7 @@ describe("Faucet", () => { pendingWithoutWasmd(); const faucet = await Faucet.make(httpUrl, defaultAddressPrefix, defaultTokenConfig, faucetMnemonic, 3); const recipient = makeRandomAddress(); - await faucet.credit(recipient, "STAKE"); + await faucet.credit(recipient, "ustake"); const readOnlyClient = new CosmosClient(httpUrl); const account = await readOnlyClient.getAccount(recipient); diff --git a/packages/faucet/src/tokenmanager.spec.ts b/packages/faucet/src/tokenmanager.spec.ts index 43683eba..52d05aa2 100644 --- a/packages/faucet/src/tokenmanager.spec.ts +++ b/packages/faucet/src/tokenmanager.spec.ts @@ -27,33 +27,33 @@ describe("TokenManager", () => { describe("creditAmount", () => { const tm = new TokenManager(dummyConfig); - it("returns 10 tokens by default", () => { - expect(tm.creditAmount("TOKENZ")).toEqual({ + it("returns 10_000_000 base tokens by default", () => { + expect(tm.creditAmount("utokenz")).toEqual({ amount: "10000000", denom: "utokenz", }); - expect(tm.creditAmount("TRASH")).toEqual({ - amount: "10000", + expect(tm.creditAmount("mtrash")).toEqual({ + amount: "10000000", denom: "mtrash", }); }); it("returns value from env variable when set", () => { - process.env.FAUCET_CREDIT_AMOUNT_TRASH = "22"; - expect(tm.creditAmount("TRASH")).toEqual({ - amount: "22000", + process.env.FAUCET_CREDIT_AMOUNT_MTRASH = "22"; + expect(tm.creditAmount("mtrash")).toEqual({ + amount: "22", denom: "mtrash", }); - process.env.FAUCET_CREDIT_AMOUNT_TRASH = ""; + process.env.FAUCET_CREDIT_AMOUNT_MTRASH = ""; }); it("returns default when env variable is set to empty", () => { process.env.FAUCET_CREDIT_AMOUNT_TRASH = ""; - expect(tm.creditAmount("TRASH")).toEqual({ - amount: "10000", + expect(tm.creditAmount("mtrash")).toEqual({ + amount: "10000000", denom: "mtrash", }); - process.env.FAUCET_CREDIT_AMOUNT_TRASH = ""; + process.env.FAUCET_CREDIT_AMOUNT_MTRASH = ""; }); }); @@ -62,37 +62,37 @@ describe("TokenManager", () => { beforeEach(() => { process.env.FAUCET_REFILL_FACTOR = ""; - process.env.FAUCET_CREDIT_AMOUNT_TRASH = ""; + process.env.FAUCET_CREDIT_AMOUNT_MTRASH = ""; }); - it("returns 20*10 + '000' by default", () => { - expect(tm.refillAmount("TRASH")).toEqual({ - amount: "200000", + it("returns 20*10_000_000' by default", () => { + expect(tm.refillAmount("mtrash")).toEqual({ + amount: "200000000", denom: "mtrash", }); }); - it("returns 20*22 + '000' when credit amount is 22", () => { - process.env.FAUCET_CREDIT_AMOUNT_TRASH = "22"; - expect(tm.refillAmount("TRASH")).toEqual({ - amount: "440000", + it("returns 20*22 when credit amount is 22", () => { + process.env.FAUCET_CREDIT_AMOUNT_MTRASH = "22"; + expect(tm.refillAmount("mtrash")).toEqual({ + amount: "440", denom: "mtrash", }); }); - it("returns 30*10 + '000' when refill factor is 30", () => { + it("returns 30*10_000_000' when refill factor is 30", () => { process.env.FAUCET_REFILL_FACTOR = "30"; - expect(tm.refillAmount("TRASH")).toEqual({ - amount: "300000", + expect(tm.refillAmount("mtrash")).toEqual({ + amount: "300000000", denom: "mtrash", }); }); - it("returns 30*22 + '000' when refill factor is 30 and credit amount is 22", () => { + it("returns 30*22 when refill factor is 30 and credit amount is 22", () => { process.env.FAUCET_REFILL_FACTOR = "30"; - process.env.FAUCET_CREDIT_AMOUNT_TRASH = "22"; - expect(tm.refillAmount("TRASH")).toEqual({ - amount: "660000", + process.env.FAUCET_CREDIT_AMOUNT_MTRASH = "22"; + expect(tm.refillAmount("mtrash")).toEqual({ + amount: "660", denom: "mtrash", }); }); @@ -103,37 +103,37 @@ describe("TokenManager", () => { beforeEach(() => { process.env.FAUCET_REFILL_THRESHOLD = ""; - process.env.FAUCET_CREDIT_AMOUNT_TRASH = ""; + process.env.FAUCET_CREDIT_AMOUNT_MTRASH = ""; }); - it("returns 8*10 + '000' by default", () => { - expect(tm.refillThreshold("TRASH")).toEqual({ - amount: "80000", + it("returns 8*10_000_000 by default", () => { + expect(tm.refillThreshold("mtrash")).toEqual({ + amount: "80000000", denom: "mtrash", }); }); - it("returns 8*22 + '000' when credit amount is 22", () => { - process.env.FAUCET_CREDIT_AMOUNT_TRASH = "22"; - expect(tm.refillThreshold("TRASH")).toEqual({ - amount: "176000", + it("returns 8*22 when credit amount is 22", () => { + process.env.FAUCET_CREDIT_AMOUNT_MTRASH = "22"; + expect(tm.refillThreshold("mtrash")).toEqual({ + amount: "176", denom: "mtrash", }); }); - it("returns 5*10 + '000' when refill threshold is 5", () => { + it("returns 5*10_000_000 when refill threshold is 5", () => { process.env.FAUCET_REFILL_THRESHOLD = "5"; - expect(tm.refillThreshold("TRASH")).toEqual({ - amount: "50000", + expect(tm.refillThreshold("mtrash")).toEqual({ + amount: "50000000", denom: "mtrash", }); }); - it("returns 5*22 + '000' when refill threshold is 5 and credit amount is 22", () => { + it("returns 5*22 when refill threshold is 5 and credit amount is 22", () => { process.env.FAUCET_REFILL_THRESHOLD = "5"; - process.env.FAUCET_CREDIT_AMOUNT_TRASH = "22"; - expect(tm.refillThreshold("TRASH")).toEqual({ - amount: "110000", + process.env.FAUCET_CREDIT_AMOUNT_MTRASH = "22"; + expect(tm.refillThreshold("mtrash")).toEqual({ + amount: "110", denom: "mtrash", }); }); @@ -161,8 +161,8 @@ describe("TokenManager", () => { }, ], }; - expect(tm.needsRefill(brokeAccount, "TOKENZ")).toEqual(true); - expect(tm.needsRefill(richAccount, "TOKENZ")).toEqual(false); + expect(tm.needsRefill(brokeAccount, "utokenz")).toEqual(true); + expect(tm.needsRefill(richAccount, "utokenz")).toEqual(false); }); it("works for missing balance", () => { @@ -170,7 +170,7 @@ describe("TokenManager", () => { address: "cosmos1rtfrpqt3yd7c8g73m9rsaen7fft0h52m3v9v5a", balance: [], }; - expect(tm.needsRefill(emptyAccount, "TOKENZ")).toEqual(true); + expect(tm.needsRefill(emptyAccount, "utokenz")).toEqual(true); }); }); }); From 6b0821192ef6b933928179fec9013a5f5ed8410e Mon Sep 17 00:00:00 2001 From: willclarktech Date: Wed, 19 Aug 2020 15:51:43 +0100 Subject: [PATCH 3/4] faucet: Update package.json scripts for denom --- packages/faucet/package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/faucet/package.json b/packages/faucet/package.json index 0818f60e..eb6ad47e 100644 --- a/packages/faucet/package.json +++ b/packages/faucet/package.json @@ -2,7 +2,7 @@ "name": "@cosmjs/faucet", "version": "0.22.2", "description": "The faucet", - "contributors":[ + "contributors": [ "Ethan Frey ", "Simon Warta " ], @@ -36,8 +36,8 @@ "test-node": "node jasmine-testrunner.js", "test": "yarn build-or-skip && yarn test-node", "coverage": "nyc --reporter=text --reporter=lcov yarn test --quiet", - "start-dev": "FAUCET_CREDIT_AMOUNT_COSM=10 FAUCET_CREDIT_AMOUNT_STAKE=5 FAUCET_CONCURRENCY=3 FAUCET_MNEMONIC=\"economy stock theory fatal elder harbor betray wasp final emotion task crumble siren bottom lizard educate guess current outdoor pair theory focus wife stone\" ./bin/cosmos-faucet start \"http://localhost:1317\"", - "start-coralnet": "FAUCET_ADDRESS_PREFIX=coral FAUCET_TOKENS=\"SHELL=10^6ushell, REEF=10^6ureef\" FAUCET_CREDIT_AMOUNT_SHELL=10 FAUCET_CREDIT_AMOUNT_REEF=2 FAUCET_CONCURRENCY=3 FAUCET_MNEMONIC=\"economy stock theory fatal elder harbor betray wasp final emotion task crumble siren bottom lizard educate guess current outdoor pair theory focus wife stone\" ./bin/cosmos-faucet start \"https://lcd.coralnet.cosmwasm.com\"" + "start-dev": "FAUCET_CREDIT_AMOUNT_UCOSM=10000000 FAUCET_CREDIT_AMOUNT_USTAKE=5000000 FAUCET_CONCURRENCY=3 FAUCET_MNEMONIC=\"economy stock theory fatal elder harbor betray wasp final emotion task crumble siren bottom lizard educate guess current outdoor pair theory focus wife stone\" ./bin/cosmos-faucet start \"http://localhost:1317\"", + "start-coralnet": "FAUCET_ADDRESS_PREFIX=coral FAUCET_TOKENS=\"SHELL=10^6ushell, REEF=10^6ureef\" FAUCET_CREDIT_AMOUNT_USHELL=10000000 FAUCET_CREDIT_AMOUNT_UREEF=2000000 FAUCET_CONCURRENCY=3 FAUCET_MNEMONIC=\"economy stock theory fatal elder harbor betray wasp final emotion task crumble siren bottom lizard educate guess current outdoor pair theory focus wife stone\" ./bin/cosmos-faucet start \"https://lcd.coralnet.cosmwasm.com\"" }, "dependencies": { "@cosmjs/crypto": "^0.22.2", From 7b84d7a3887b28b07365d588bcd76fe23d9f251b Mon Sep 17 00:00:00 2001 From: willclarktech Date: Wed, 19 Aug 2020 15:58:37 +0100 Subject: [PATCH 4/4] Update CHANGELOG for faucet denom change --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a3191f5..d85a0ac1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,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/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