diff --git a/CHANGELOG.md b/CHANGELOG.md index 01abe683..be5a8a63 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,7 +16,17 @@ `BroadcastTxSuccess` and `BroadcastTxFailure` respectively, as well as helper functions `isBroadcastTxFailure`, `isBroadcastTxSuccess` and `assertIsBroadcastTxSuccess`. + +## 0.22.1 (2020-08-11) + +- @cosmjs/cli: Import `encodeAminoPubkey`, `encodeBech32Pubkey`, + `decodeAminoPubkey` and `decodeBech32Pubkey` by default. +- @cosmjs/launchpad: Add ed25519 support to `encodeBech32Pubkey`. +- @cosmjs/launchpad: Add `encodeAminoPubkey` and `decodeAminoPubkey`. - @cosmjs/utils: Add `arrayContentEquals`. +- @cosmjs/faucet: Add config variables `FAUCET_ADDRESS_PREFIX` and + `FAUCET_TOKENS`. +- @cosmjs/faucet: Remove broken chain ID from `cosmwasm-faucet generate`. ## 0.22.0 (2020-08-03) diff --git a/lerna.json b/lerna.json index 15adaf7c..f81d8541 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "0.22.0", + "version": "0.22.1", "useWorkspaces": true, "npmClient": "yarn" } diff --git a/packages/cli/nonces/1597132850 b/packages/cli/nonces/1597132850 new file mode 100644 index 00000000..e69de29b diff --git a/packages/cli/package.json b/packages/cli/package.json index c678941a..1976419c 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@cosmjs/cli", - "version": "0.22.0", + "version": "0.22.1", "description": "Command line interface", "contributors": [ "IOV SAS ", @@ -39,12 +39,12 @@ "!**/testdata/" ], "dependencies": { - "@cosmjs/cosmwasm": "^0.22.0", - "@cosmjs/crypto": "^0.22.0", - "@cosmjs/encoding": "^0.22.0", - "@cosmjs/launchpad": "^0.22.0", - "@cosmjs/math": "^0.22.0", - "@cosmjs/utils": "^0.22.0", + "@cosmjs/cosmwasm": "^0.22.1", + "@cosmjs/crypto": "^0.22.1", + "@cosmjs/encoding": "^0.22.1", + "@cosmjs/launchpad": "^0.22.1", + "@cosmjs/math": "^0.22.1", + "@cosmjs/utils": "^0.22.1", "axios": "^0.19.2", "babylon": "^6.18.0", "colors": "^1.3.3", diff --git a/packages/cli/src/cli.ts b/packages/cli/src/cli.ts index a9754714..bf937150 100644 --- a/packages/cli/src/cli.ts +++ b/packages/cli/src/cli.ts @@ -89,6 +89,10 @@ export async function main(originalArgs: readonly string[]): Promise { [ "coin", "coins", + "decodeAminoPubkey", + "decodeBech32Pubkey", + "encodeAminoPubkey", + "encodeBech32Pubkey", "encodeSecp256k1Pubkey", "encodeSecp256k1Signature", "logs", @@ -112,7 +116,7 @@ export async function main(originalArgs: readonly string[]): Promise { ], ], ["@cosmjs/math", ["Decimal", "Int53", "Uint32", "Uint53", "Uint64"]], - ["@cosmjs/utils", ["assert", "sleep"]], + ["@cosmjs/utils", ["assert", "arrayContentEquals", "sleep"]], ]); console.info(colors.green("Initializing session for you. Have fun!")); @@ -156,6 +160,12 @@ export async function main(originalArgs: readonly string[]): Promise { const data = toAscii("foo bar"); const signature = await wallet.sign(address, data); + const bechPubkey = "coralvalconspub1zcjduepqvxg72ccnl9r65fv0wn3amlk4sfzqfe2k36l073kjx2qyaf6sk23qw7j8wq"; + assert(encodeBech32Pubkey(decodeBech32Pubkey(bechPubkey), "coralvalconspub") == bechPubkey); + + const aminoPubkey = fromHex("eb5ae98721034f04181eeba35391b858633a765c4a0c189697b40d216354d50890d350c70290"); + assert(arrayContentEquals(encodeAminoPubkey(decodeAminoPubkey(aminoPubkey)), aminoPubkey)); + console.info("Done testing, will exit now."); process.exit(0); `; diff --git a/packages/cosmwasm/nonces/1597132850 b/packages/cosmwasm/nonces/1597132850 new file mode 100644 index 00000000..e69de29b diff --git a/packages/cosmwasm/package.json b/packages/cosmwasm/package.json index fadc0b49..ad633fe9 100644 --- a/packages/cosmwasm/package.json +++ b/packages/cosmwasm/package.json @@ -1,6 +1,6 @@ { "name": "@cosmjs/cosmwasm", - "version": "0.22.0", + "version": "0.22.1", "description": "CosmWasm SDK", "author": "Ethan Frey ", "license": "Apache-2.0", @@ -38,13 +38,12 @@ "pack-web": "yarn build-or-skip && webpack --mode development --config webpack.web.config.js" }, "dependencies": { - "@cosmjs/crypto": "^0.22.0", - "@cosmjs/encoding": "^0.22.0", - "@cosmjs/launchpad": "^0.22.0", - "@cosmjs/math": "^0.22.0", - "@cosmjs/utils": "^0.22.0", + "@cosmjs/crypto": "^0.22.1", + "@cosmjs/encoding": "^0.22.1", + "@cosmjs/launchpad": "^0.22.1", + "@cosmjs/math": "^0.22.1", + "@cosmjs/utils": "^0.22.1", "axios": "^0.19.0", - "fast-deep-equal": "^3.1.1", "pako": "^1.0.11" }, "devDependencies": { diff --git a/packages/crypto/nonces/1597132850 b/packages/crypto/nonces/1597132850 new file mode 100644 index 00000000..e69de29b diff --git a/packages/crypto/package.json b/packages/crypto/package.json index 4e621bf6..4ac5120a 100644 --- a/packages/crypto/package.json +++ b/packages/crypto/package.json @@ -1,6 +1,6 @@ { "name": "@cosmjs/crypto", - "version": "0.22.0", + "version": "0.22.1", "description": "Cryptography resources for blockchain projects", "contributors": [ "IOV SAS ", @@ -43,9 +43,9 @@ "pack-web": "yarn build-or-skip && webpack --mode development --config webpack.web.config.js" }, "dependencies": { - "@cosmjs/encoding": "^0.22.0", - "@cosmjs/math": "^0.22.0", - "@cosmjs/utils": "^0.22.0", + "@cosmjs/encoding": "^0.22.1", + "@cosmjs/math": "^0.22.1", + "@cosmjs/utils": "^0.22.1", "bip39": "^3.0.2", "bn.js": "^4.11.8", "elliptic": "^6.5.3", diff --git a/packages/encoding/nonces/1597132850 b/packages/encoding/nonces/1597132850 new file mode 100644 index 00000000..e69de29b diff --git a/packages/encoding/package.json b/packages/encoding/package.json index 0b1dc739..151c4ff6 100644 --- a/packages/encoding/package.json +++ b/packages/encoding/package.json @@ -1,6 +1,6 @@ { "name": "@cosmjs/encoding", - "version": "0.22.0", + "version": "0.22.1", "description": "Encoding helpers for blockchain projects", "contributors": [ "IOV SAS " diff --git a/packages/faucet/README.md b/packages/faucet/README.md index 35db2ad9..54981b72 100644 --- a/packages/faucet/README.md +++ b/packages/faucet/README.md @@ -38,7 +38,6 @@ help Shows a help text and exits version Prints the version and exits generate Generates a random mnemonic, shows derived faucet addresses and exits - 1 Chain ID start Starts the faucet 1 Node base URL, e.g. http://localhost:1317 @@ -49,6 +48,10 @@ FAUCET_CONCURRENCY Number of distributor accounts. Defaults to 5. FAUCET_PORT Port of the webserver. Defaults to 8000. FAUCET_MNEMONIC Secret mnemonic that serves as the base secret for the faucet HD accounts +FAUCET_ADDRESS_PREFIX The bech32 address prefix. Defaults to "cosmos". +FAUCET_TOKENS A comma separated list of tokens configs in the format + {DISPLAY}=10^{DIGITS}{base}, e.g. + "ATOM=10^6uatom" or "COSM = 10^6ucosm, STAKE = 10^3mstake". FAUCET_CREDIT_AMOUNT_TKN Send this amount of TKN to a user requesting TKN. TKN is a placeholder for the token ticker. Defaults to 10. FAUCET_REFILL_FACTOR Send factor times credit amount on refilling. Defauls to 8. diff --git a/packages/faucet/nonces/1597132850 b/packages/faucet/nonces/1597132850 new file mode 100644 index 00000000..e69de29b diff --git a/packages/faucet/package.json b/packages/faucet/package.json index 96b972af..72d0fea2 100644 --- a/packages/faucet/package.json +++ b/packages/faucet/package.json @@ -1,6 +1,6 @@ { "name": "@cosmjs/faucet", - "version": "0.22.0", + "version": "0.22.1", "description": "The faucet", "author": "Ethan Frey ", "license": "Apache-2.0", @@ -22,7 +22,7 @@ "access": "public" }, "scripts": { - "dev-start": "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/cosmwasm-faucet start \"http://localhost:1317\"", + "dev-start": "yarn start-dev", "format": "prettier --write --loglevel warn \"./src/**/*.ts\"", "format-text": "prettier --write --prose-wrap always --print-width 80 \"./*.md\"", "lint": "eslint --max-warnings 0 \"**/*.{js,ts}\"", @@ -31,14 +31,16 @@ "build-or-skip": "[ -n \"$SKIP_BUILD\" ] || yarn build", "test-node": "node jasmine-testrunner.js", "test": "yarn build-or-skip && yarn test-node", - "coverage": "nyc --reporter=text --reporter=lcov yarn test --quiet" + "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/cosmwasm-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/cosmwasm-faucet start \"https://lcd.coralnet.cosmwasm.com\"" }, "dependencies": { - "@cosmjs/crypto": "^0.22.0", - "@cosmjs/encoding": "^0.22.0", - "@cosmjs/launchpad": "^0.22.0", - "@cosmjs/math": "^0.22.0", - "@cosmjs/utils": "^0.22.0", + "@cosmjs/crypto": "^0.22.1", + "@cosmjs/encoding": "^0.22.1", + "@cosmjs/launchpad": "^0.22.1", + "@cosmjs/math": "^0.22.1", + "@cosmjs/utils": "^0.22.1", "@koa/cors": "^3.0.0", "koa": "^2.11.0", "koa-bodyparser": "^4.2.1" diff --git a/packages/faucet/src/actions/generate.ts b/packages/faucet/src/actions/generate.ts index ad876dae..a7720b75 100644 --- a/packages/faucet/src/actions/generate.ts +++ b/packages/faucet/src/actions/generate.ts @@ -4,17 +4,15 @@ import * as constants from "../constants"; import { createWallets } from "../profile"; export async function generate(args: readonly string[]): Promise { - if (args.length < 1) { - throw Error( - `Not enough arguments for action 'generate'. See '${constants.binaryName} help' or README for arguments.`, + if (args.length > 0) { + console.warn( + `Warning: ${constants.binaryName} generate does not require positional arguments anymore. Use env variables FAUCET_ADDRESS_PREFIX or FAUCET_CONCURRENCY to configure how accounts are created.`, ); } - const chainId = args[0]; - const mnemonic = Bip39.encode(Random.getBytes(16)).toString(); console.info(`FAUCET_MNEMONIC="${mnemonic}"`); // Log the addresses - await createWallets(mnemonic, chainId, constants.concurrency, true); + await createWallets(mnemonic, constants.addressPrefix, constants.concurrency, true); } diff --git a/packages/faucet/src/actions/help.ts b/packages/faucet/src/actions/help.ts index 745e0ba3..c7bdea20 100644 --- a/packages/faucet/src/actions/help.ts +++ b/packages/faucet/src/actions/help.ts @@ -11,7 +11,6 @@ help Shows a help text and exits version Prints the version and exits generate Generates a random mnemonic, shows derived faucet addresses and exits - 1 Chain ID start Starts the faucet 1 Node base URL, e.g. http://localhost:1317 @@ -22,6 +21,10 @@ FAUCET_CONCURRENCY Number of distributor accounts. Defaults to 5. FAUCET_PORT Port of the webserver. Defaults to 8000. FAUCET_MNEMONIC Secret mnemonic that serves as the base secret for the faucet HD accounts +FAUCET_ADDRESS_PREFIX The bech32 address prefix. Defaults to "cosmos". +FAUCET_TOKENS A comma separated list of tokens configs in the format + {DISPLAY}=10^{DIGITS}{base}, e.g. + "ATOM=10^6uatom" or "COSM = 10^6ucosm, STAKE = 10^3mstake". FAUCET_CREDIT_AMOUNT_TKN Send this amount of TKN to a user requesting TKN. TKN is a placeholder for the token ticker. Defaults to 10. FAUCET_REFILL_FACTOR Send factor times credit amount on refilling. Defauls to 8. diff --git a/packages/faucet/src/actions/start/start.ts b/packages/faucet/src/actions/start.ts similarity index 80% rename from packages/faucet/src/actions/start/start.ts rename to packages/faucet/src/actions/start.ts index 877ae70b..63c13fef 100644 --- a/packages/faucet/src/actions/start/start.ts +++ b/packages/faucet/src/actions/start.ts @@ -1,9 +1,9 @@ import { CosmosClient } from "@cosmjs/launchpad"; -import { Webserver } from "../../api/webserver"; -import * as constants from "../../constants"; -import { logAccountsState } from "../../debugging"; -import { Faucet } from "../../faucet"; +import { Webserver } from "../api/webserver"; +import * as constants from "../constants"; +import { logAccountsState } from "../debugging"; +import { Faucet } from "../faucet"; export async function start(args: readonly string[]): Promise { if (args.length < 1) { @@ -23,7 +23,7 @@ export async function start(args: readonly string[]): Promise { const faucet = await Faucet.make( blockchainBaseUrl, constants.addressPrefix, - constants.developmentTokenConfig, + constants.tokenConfig, constants.mnemonic, constants.concurrency, true, @@ -31,7 +31,7 @@ export async function start(args: readonly string[]): Promise { const chainTokens = faucet.loadTokenTickers(); console.info("Chain tokens:", chainTokens); const accounts = await faucet.loadAccounts(); - logAccountsState(accounts, constants.developmentTokenConfig); + logAccountsState(accounts, constants.tokenConfig); let availableTokens = await faucet.availableTokens(); console.info("Available tokens:", availableTokens); setInterval(async () => { @@ -45,4 +45,5 @@ export async function start(args: readonly string[]): Promise { console.info("Creating webserver ..."); const server = new Webserver(faucet, { nodeUrl: blockchainBaseUrl, chainId: chainId }); server.start(constants.port); + console.info(`Try "curl -sS http://localhost:${constants.port}/status | jq" to check the status.`); } diff --git a/packages/faucet/src/actions/start/index.ts b/packages/faucet/src/actions/start/index.ts deleted file mode 100644 index 56e0e121..00000000 --- a/packages/faucet/src/actions/start/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { start } from "./start"; diff --git a/packages/faucet/src/constants.ts b/packages/faucet/src/constants.ts index b9528833..53bf0b83 100644 --- a/packages/faucet/src/constants.ts +++ b/packages/faucet/src/constants.ts @@ -1,24 +1,11 @@ -import { TokenConfiguration } from "./types"; +import { TokenConfiguration } from "./tokenmanager"; +import { parseBankTokens } from "./tokens"; export const binaryName = "cosmwasm-faucet"; export const concurrency: number = Number.parseInt(process.env.FAUCET_CONCURRENCY || "", 10) || 5; export const port: number = Number.parseInt(process.env.FAUCET_PORT || "", 10) || 8000; export const mnemonic: string | undefined = process.env.FAUCET_MNEMONIC; - -export const addressPrefix = "cosmos"; - -/** For the local development chain */ -export const developmentTokenConfig: TokenConfiguration = { - bankTokens: [ - { - fractionalDigits: 6, - tickerSymbol: "COSM", - denom: "ucosm", - }, - { - fractionalDigits: 6, - tickerSymbol: "STAKE", - denom: "ustake", - }, - ], +export const addressPrefix = process.env.FAUCET_ADDRESS_PREFIX || "cosmos"; +export const tokenConfig: TokenConfiguration = { + bankTokens: parseBankTokens(process.env.FAUCET_TOKENS || "COSM=10^6ucosm, STAKE=10^6ustake"), }; diff --git a/packages/faucet/src/debugging.ts b/packages/faucet/src/debugging.ts index fce36e0b..9f6bec7d 100644 --- a/packages/faucet/src/debugging.ts +++ b/packages/faucet/src/debugging.ts @@ -1,7 +1,8 @@ import { Coin } from "@cosmjs/launchpad"; import { Decimal } from "@cosmjs/math"; -import { MinimalAccount, SendJob, TokenConfiguration } from "./types"; +import { TokenConfiguration } from "./tokenmanager"; +import { MinimalAccount, SendJob } from "./types"; /** A string representation of a coin in a human-readable format that can change at any time */ function debugCoin(coin: Coin, tokens: TokenConfiguration): string { diff --git a/packages/faucet/src/faucet.spec.ts b/packages/faucet/src/faucet.spec.ts index 51732b15..5f664c48 100644 --- a/packages/faucet/src/faucet.spec.ts +++ b/packages/faucet/src/faucet.spec.ts @@ -4,7 +4,7 @@ import { CosmosClient } from "@cosmjs/launchpad"; import { assert } from "@cosmjs/utils"; import { Faucet } from "./faucet"; -import { TokenConfiguration } from "./types"; +import { TokenConfiguration } from "./tokenmanager"; function pendingWithoutWasmd(): void { if (!process.env.WASMD_ENABLED) { diff --git a/packages/faucet/src/faucet.ts b/packages/faucet/src/faucet.ts index ab170d89..e83f3f78 100644 --- a/packages/faucet/src/faucet.ts +++ b/packages/faucet/src/faucet.ts @@ -3,8 +3,8 @@ import { sleep } from "@cosmjs/utils"; import { debugAccount, logAccountsState, logSendJob } from "./debugging"; import { createWallets } from "./profile"; -import { TokenManager } from "./tokenmanager"; -import { MinimalAccount, SendJob, TokenConfiguration } from "./types"; +import { TokenConfiguration, TokenManager } from "./tokenmanager"; +import { MinimalAccount, SendJob } from "./types"; function isDefined(value: X | undefined): value is X { return value !== undefined; @@ -119,7 +119,7 @@ export class Faucet { public async refill(): Promise { if (this.logging) { - console.info(`Connected to network: ${this.readOnlyClient.getChainId()}`); + console.info(`Connected to network: ${await this.readOnlyClient.getChainId()}`); console.info(`Tokens on network: ${this.loadTokenTickers().join(", ")}`); } diff --git a/packages/faucet/src/tokenmanager.spec.ts b/packages/faucet/src/tokenmanager.spec.ts index 35ade7a7..43683eba 100644 --- a/packages/faucet/src/tokenmanager.spec.ts +++ b/packages/faucet/src/tokenmanager.spec.ts @@ -1,5 +1,5 @@ -import { TokenManager } from "./tokenmanager"; -import { MinimalAccount, TokenConfiguration } from "./types"; +import { TokenConfiguration, TokenManager } from "./tokenmanager"; +import { MinimalAccount } from "./types"; const dummyConfig: TokenConfiguration = { bankTokens: [ diff --git a/packages/faucet/src/tokenmanager.ts b/packages/faucet/src/tokenmanager.ts index 4022fcc4..cb4c8262 100644 --- a/packages/faucet/src/tokenmanager.ts +++ b/packages/faucet/src/tokenmanager.ts @@ -1,7 +1,8 @@ import { Coin } from "@cosmjs/launchpad"; import { Decimal, Uint53 } from "@cosmjs/math"; -import { BankTokenMeta, MinimalAccount, TokenConfiguration } from "./types"; +import { BankTokenMeta } from "./tokens"; +import { MinimalAccount } from "./types"; /** Send `factor` times credit amount on refilling */ const defaultRefillFactor = 20; @@ -9,6 +10,11 @@ const defaultRefillFactor = 20; /** refill when balance gets below `factor` times credit amount */ const defaultRefillThresholdFactor = 8; +export interface TokenConfiguration { + /** Supported tokens of the Cosmos SDK bank module */ + readonly bankTokens: readonly BankTokenMeta[]; +} + export class TokenManager { private readonly config: TokenConfiguration; diff --git a/packages/faucet/src/tokens.spec.ts b/packages/faucet/src/tokens.spec.ts new file mode 100644 index 00000000..39836c9e --- /dev/null +++ b/packages/faucet/src/tokens.spec.ts @@ -0,0 +1,78 @@ +import { parseBankToken, parseBankTokens } from "./tokens"; + +describe("tokens", () => { + describe("parseBankToken", () => { + it("works", () => { + expect(parseBankToken("COSM=10^6ucosm")).toEqual({ + tickerSymbol: "COSM", + fractionalDigits: 6, + denom: "ucosm", + }); + }); + + it("allows using whitespace", () => { + expect(parseBankToken("COSM = 10^6 ucosm")).toEqual({ + tickerSymbol: "COSM", + fractionalDigits: 6, + denom: "ucosm", + }); + }); + }); + + describe("parseBankTokens", () => { + it("works for one", () => { + expect(parseBankTokens("COSM=10^6ucosm")).toEqual([ + { + tickerSymbol: "COSM", + fractionalDigits: 6, + denom: "ucosm", + }, + ]); + }); + + it("works for two", () => { + expect(parseBankTokens("COSM=10^6ucosm,STAKE=10^3mstake")).toEqual([ + { + tickerSymbol: "COSM", + fractionalDigits: 6, + denom: "ucosm", + }, + { + tickerSymbol: "STAKE", + fractionalDigits: 3, + denom: "mstake", + }, + ]); + }); + + it("ignores whitespace", () => { + expect(parseBankTokens("COSM=10^6ucosm, STAKE=10^3mstake\n")).toEqual([ + { + tickerSymbol: "COSM", + fractionalDigits: 6, + denom: "ucosm", + }, + { + tickerSymbol: "STAKE", + fractionalDigits: 3, + denom: "mstake", + }, + ]); + }); + + it("ignores empty elements", () => { + expect(parseBankTokens("COSM=10^6ucosm,STAKE=10^3mstake,")).toEqual([ + { + tickerSymbol: "COSM", + fractionalDigits: 6, + denom: "ucosm", + }, + { + tickerSymbol: "STAKE", + fractionalDigits: 3, + denom: "mstake", + }, + ]); + }); + }); +}); diff --git a/packages/faucet/src/tokens.ts b/packages/faucet/src/tokens.ts new file mode 100644 index 00000000..a3ca321b --- /dev/null +++ b/packages/faucet/src/tokens.ts @@ -0,0 +1,41 @@ +import { Uint53 } from "@cosmjs/math"; + +export interface BankTokenMeta { + readonly denom: string; + /** + * The token ticker symbol, e.g. ATOM or ETH. + */ + readonly tickerSymbol: string; + /** + * The number of fractional digits the token supports. + * + * A quantity is expressed as atomic units. 10^fractionalDigits of those + * atomic units make up 1 token. + * + * E.g. in Ethereum 10^18 wei are 1 ETH and from the quantity 123000000000000000000 + * the last 18 digits are the fractional part and the rest the wole part. + */ + readonly fractionalDigits: number; +} + +const parseBankTokenPattern = /^([a-zA-Z]{2,20})=10\^([0-9]+)([a-zA-Z]{2,20})$/; + +export function parseBankToken(input: string): BankTokenMeta { + const match = input.replace(/\s/g, "").match(parseBankTokenPattern); + if (!match) { + throw new Error("Token could not be parsed. Format: {DISPLAY}=10^{DIGITS}{base}, e.g. ATOM=10^6uatom"); + } + return { + tickerSymbol: match[1], + fractionalDigits: Uint53.fromString(match[2]).toNumber(), + denom: match[3], + }; +} + +export function parseBankTokens(input: string): BankTokenMeta[] { + return input + .trim() + .split(",") + .filter((part) => part.trim() !== "") + .map((part) => parseBankToken(part)); +} diff --git a/packages/faucet/src/types.ts b/packages/faucet/src/types.ts index b5c68ac6..9241c572 100644 --- a/packages/faucet/src/types.ts +++ b/packages/faucet/src/types.ts @@ -6,27 +6,4 @@ export interface SendJob { readonly amount: Coin; } -export interface BankTokenMeta { - readonly denom: string; - /** - * The token ticker symbol, e.g. ATOM or ETH. - */ - readonly tickerSymbol: string; - /** - * The number of fractional digits the token supports. - * - * A quantity is expressed as atomic units. 10^fractionalDigits of those - * atomic units make up 1 token. - * - * E.g. in Ethereum 10^18 wei are 1 ETH and from the quantity 123000000000000000000 - * the last 18 digits are the fractional part and the rest the wole part. - */ - readonly fractionalDigits: number; -} - -export interface TokenConfiguration { - /** Supported tokens of the Cosmos SDK bank module */ - readonly bankTokens: readonly BankTokenMeta[]; -} - export type MinimalAccount = Pick; diff --git a/packages/json-rpc/nonces/1597132850 b/packages/json-rpc/nonces/1597132850 new file mode 100644 index 00000000..e69de29b diff --git a/packages/json-rpc/package.json b/packages/json-rpc/package.json index ff7d9c93..99ea16b0 100644 --- a/packages/json-rpc/package.json +++ b/packages/json-rpc/package.json @@ -1,6 +1,6 @@ { "name": "@cosmjs/json-rpc", - "version": "0.22.0", + "version": "0.22.1", "description": "Framework for implementing a JSON-RPC 2.0 API", "contributors": [ "IOV SAS ", @@ -44,7 +44,7 @@ "pack-web": "yarn build-or-skip && webpack --mode development --config webpack.web.config.js" }, "dependencies": { - "@cosmjs/stream": "^0.22.0", + "@cosmjs/stream": "^0.22.1", "xstream": "^11.10.0" } } diff --git a/packages/launchpad/nonces/1597132850 b/packages/launchpad/nonces/1597132850 new file mode 100644 index 00000000..e69de29b diff --git a/packages/launchpad/package.json b/packages/launchpad/package.json index 7fe56adb..a89e7411 100644 --- a/packages/launchpad/package.json +++ b/packages/launchpad/package.json @@ -1,6 +1,6 @@ { "name": "@cosmjs/launchpad", - "version": "0.22.0", + "version": "0.22.1", "description": "A client library for the Cosmos SDK 0.37 (cosmoshub-3), 0.38 and 0.39 (Launchpad)", "contributors": [ "Ethan Frey ", @@ -41,12 +41,11 @@ "pack-web": "yarn build-or-skip && webpack --mode development --config webpack.web.config.js" }, "dependencies": { - "@cosmjs/crypto": "^0.22.0", - "@cosmjs/encoding": "^0.22.0", - "@cosmjs/math": "^0.22.0", - "@cosmjs/utils": "^0.22.0", - "axios": "^0.19.0", - "fast-deep-equal": "^3.1.1" + "@cosmjs/crypto": "^0.22.1", + "@cosmjs/encoding": "^0.22.1", + "@cosmjs/math": "^0.22.1", + "@cosmjs/utils": "^0.22.1", + "axios": "^0.19.0" }, "devDependencies": { "readonly-date": "^1.0.0" diff --git a/packages/launchpad/src/index.ts b/packages/launchpad/src/index.ts index 99f39b4e..6f912c8b 100644 --- a/packages/launchpad/src/index.ts +++ b/packages/launchpad/src/index.ts @@ -84,7 +84,13 @@ export { uint64ToString, } from "./lcdapi"; export { isMsgDelegate, isMsgSend, Msg, MsgDelegate, MsgSend } from "./msgs"; -export { decodeAminoPubkey, decodeBech32Pubkey, encodeBech32Pubkey, encodeSecp256k1Pubkey } from "./pubkey"; +export { + decodeAminoPubkey, + decodeBech32Pubkey, + encodeAminoPubkey, + encodeBech32Pubkey, + encodeSecp256k1Pubkey, +} from "./pubkey"; export { findSequenceForSignedTx } from "./sequence"; export { encodeSecp256k1Signature, decodeSignature } from "./signature"; export { FeeTable, SigningCosmosClient } from "./signingcosmosclient"; diff --git a/packages/launchpad/src/pubkey.spec.ts b/packages/launchpad/src/pubkey.spec.ts index 03253695..9576239b 100644 --- a/packages/launchpad/src/pubkey.spec.ts +++ b/packages/launchpad/src/pubkey.spec.ts @@ -1,6 +1,12 @@ -import { fromBase64 } from "@cosmjs/encoding"; +import { Bech32, fromBase64 } from "@cosmjs/encoding"; -import { decodeBech32Pubkey, encodeBech32Pubkey, encodeSecp256k1Pubkey } from "./pubkey"; +import { + decodeAminoPubkey, + decodeBech32Pubkey, + encodeAminoPubkey, + encodeBech32Pubkey, + encodeSecp256k1Pubkey, +} from "./pubkey"; import { PubKey } from "./types"; describe("pubkey", () => { @@ -21,6 +27,30 @@ describe("pubkey", () => { }); }); + describe("decodeAminoPubkey", () => { + it("works for secp256k1", () => { + const amino = Bech32.decode( + "cosmospub1addwnpepqd8sgxq7aw348ydctp3n5ajufgxp395hksxjzc6565yfp56scupfqhlgyg5", + ).data; + expect(decodeAminoPubkey(amino)).toEqual({ + type: "tendermint/PubKeySecp256k1", + value: "A08EGB7ro1ORuFhjOnZcSgwYlpe0DSFjVNUIkNNQxwKQ", + }); + }); + + it("works for ed25519", () => { + // Encoded from `corald tendermint show-validator` + // Decoded from http://localhost:26657/validators + const amino = Bech32.decode( + "coralvalconspub1zcjduepqvxg72ccnl9r65fv0wn3amlk4sfzqfe2k36l073kjx2qyaf6sk23qw7j8wq", + ).data; + expect(decodeAminoPubkey(amino)).toEqual({ + type: "tendermint/PubKeyEd25519", + value: "YZHlYxP5R6olj3Tj3f7VgkQE5VaOvv9G0jKATqdQsqI=", + }); + }); + }); + describe("decodeBech32Pubkey", () => { it("works", () => { expect( @@ -39,6 +69,44 @@ describe("pubkey", () => { value: "A6lihrEs3PEFCu8m01ebcas3KjEVAjDIEmU7P9ED3PFx", }); }); + + it("works for ed25519", () => { + // Encoded from `corald tendermint show-validator` + // Decoded from http://localhost:26657/validators + const decoded = decodeBech32Pubkey( + "coralvalconspub1zcjduepqvxg72ccnl9r65fv0wn3amlk4sfzqfe2k36l073kjx2qyaf6sk23qw7j8wq", + ); + expect(decoded).toEqual({ + type: "tendermint/PubKeyEd25519", + value: "YZHlYxP5R6olj3Tj3f7VgkQE5VaOvv9G0jKATqdQsqI=", + }); + }); + }); + + describe("encodeAminoPubkey", () => { + it("works for secp256k1", () => { + const pubkey: PubKey = { + type: "tendermint/PubKeySecp256k1", + value: "A08EGB7ro1ORuFhjOnZcSgwYlpe0DSFjVNUIkNNQxwKQ", + }; + const expected = Bech32.decode( + "cosmospub1addwnpepqd8sgxq7aw348ydctp3n5ajufgxp395hksxjzc6565yfp56scupfqhlgyg5", + ).data; + expect(encodeAminoPubkey(pubkey)).toEqual(expected); + }); + + it("works for ed25519", () => { + // Decoded from http://localhost:26657/validators + // Encoded from `corald tendermint show-validator` + const pubkey: PubKey = { + type: "tendermint/PubKeyEd25519", + value: "YZHlYxP5R6olj3Tj3f7VgkQE5VaOvv9G0jKATqdQsqI=", + }; + const expected = Bech32.decode( + "coralvalconspub1zcjduepqvxg72ccnl9r65fv0wn3amlk4sfzqfe2k36l073kjx2qyaf6sk23qw7j8wq", + ).data; + expect(encodeAminoPubkey(pubkey)).toEqual(expected); + }); }); describe("encodeBech32Pubkey", () => { @@ -51,5 +119,17 @@ describe("pubkey", () => { "cosmospub1addwnpepqd8sgxq7aw348ydctp3n5ajufgxp395hksxjzc6565yfp56scupfqhlgyg5", ); }); + + it("works for ed25519", () => { + // Decoded from http://localhost:26657/validators + // Encoded from `corald tendermint show-validator` + const pubkey: PubKey = { + type: "tendermint/PubKeyEd25519", + value: "YZHlYxP5R6olj3Tj3f7VgkQE5VaOvv9G0jKATqdQsqI=", + }; + expect(encodeBech32Pubkey(pubkey, "coralvalconspub")).toEqual( + "coralvalconspub1zcjduepqvxg72ccnl9r65fv0wn3amlk4sfzqfe2k36l073kjx2qyaf6sk23qw7j8wq", + ); + }); }); }); diff --git a/packages/launchpad/src/pubkey.ts b/packages/launchpad/src/pubkey.ts index 82753525..bebc3c62 100644 --- a/packages/launchpad/src/pubkey.ts +++ b/packages/launchpad/src/pubkey.ts @@ -1,5 +1,5 @@ import { Bech32, fromBase64, fromHex, toBase64, toHex } from "@cosmjs/encoding"; -import equal from "fast-deep-equal"; +import { arrayContentEquals } from "@cosmjs/utils"; import { PubKey, pubkeyType } from "./types"; @@ -21,10 +21,13 @@ const pubkeyAminoPrefixEd25519 = fromHex("1624de6420"); const pubkeyAminoPrefixSr25519 = fromHex("0dfb1005"); const pubkeyAminoPrefixLength = pubkeyAminoPrefixSecp256k1.length; +/** + * Decodes a pubkey in the Amino binary format to a type/value object. + */ export function decodeAminoPubkey(data: Uint8Array): PubKey { const aminoPrefix = data.slice(0, pubkeyAminoPrefixLength); const rest = data.slice(pubkeyAminoPrefixLength); - if (equal(aminoPrefix, pubkeyAminoPrefixSecp256k1)) { + if (arrayContentEquals(aminoPrefix, pubkeyAminoPrefixSecp256k1)) { if (rest.length !== 33) { throw new Error("Invalid rest data length. Expected 33 bytes (compressed secp256k1 pubkey)."); } @@ -32,7 +35,7 @@ export function decodeAminoPubkey(data: Uint8Array): PubKey { type: pubkeyType.secp256k1, value: toBase64(rest), }; - } else if (equal(aminoPrefix, pubkeyAminoPrefixEd25519)) { + } else if (arrayContentEquals(aminoPrefix, pubkeyAminoPrefixEd25519)) { if (rest.length !== 32) { throw new Error("Invalid rest data length. Expected 32 bytes (Ed25519 pubkey)."); } @@ -40,7 +43,7 @@ export function decodeAminoPubkey(data: Uint8Array): PubKey { type: pubkeyType.ed25519, value: toBase64(rest), }; - } else if (equal(aminoPrefix, pubkeyAminoPrefixSr25519)) { + } else if (arrayContentEquals(aminoPrefix, pubkeyAminoPrefixSr25519)) { if (rest.length !== 32) { throw new Error("Invalid rest data length. Expected 32 bytes (Sr25519 pubkey)."); } @@ -53,22 +56,42 @@ export function decodeAminoPubkey(data: Uint8Array): PubKey { } } +/** + * Decodes a bech32 pubkey to Amino binary, which is then decoded to a type/value object. + * The bech32 prefix is ignored and discareded. + * + * @param bechEncoded the bech32 encoded pubkey + */ export function decodeBech32Pubkey(bechEncoded: string): PubKey { const { data } = Bech32.decode(bechEncoded); return decodeAminoPubkey(data); } -export function encodeBech32Pubkey(pubkey: PubKey, prefix: string): string { +/** + * Encodes a public key to binary Amino. + */ +export function encodeAminoPubkey(pubkey: PubKey): Uint8Array { let aminoPrefix: Uint8Array; switch (pubkey.type) { // Note: please don't add cases here without writing additional unit tests case pubkeyType.secp256k1: aminoPrefix = pubkeyAminoPrefixSecp256k1; break; + case pubkeyType.ed25519: + aminoPrefix = pubkeyAminoPrefixEd25519; + break; default: throw new Error("Unsupported pubkey type"); } - - const data = new Uint8Array([...aminoPrefix, ...fromBase64(pubkey.value)]); - return Bech32.encode(prefix, data); + return new Uint8Array([...aminoPrefix, ...fromBase64(pubkey.value)]); +} + +/** + * Encodes a public key to binary Amino and then to bech32. + * + * @param pubkey the public key to encode + * @param prefix the bech32 prefix (human readable part) + */ +export function encodeBech32Pubkey(pubkey: PubKey, prefix: string): string { + return Bech32.encode(prefix, encodeAminoPubkey(pubkey)); } diff --git a/packages/launchpad/src/types.ts b/packages/launchpad/src/types.ts index e0de1e84..dc799014 100644 --- a/packages/launchpad/src/types.ts +++ b/packages/launchpad/src/types.ts @@ -37,7 +37,7 @@ export interface StdSignature { } export interface PubKey { - // type is one of the strings defined in pubkeyTypes + // type is one of the strings defined in pubkeyType // I don't use a string literal union here as that makes trouble with json test data: // https://github.com/CosmWasm/cosmjs/pull/44#pullrequestreview-353280504 readonly type: string; @@ -54,5 +54,3 @@ export const pubkeyType = { /** @see https://github.com/tendermint/tendermint/blob/v0.33.0/crypto/sr25519/codec.go#L12 */ sr25519: "tendermint/PubKeySr25519" as const, }; - -export const pubkeyTypes: readonly string[] = [pubkeyType.secp256k1, pubkeyType.ed25519, pubkeyType.sr25519]; diff --git a/packages/launchpad/types/index.d.ts b/packages/launchpad/types/index.d.ts index 8a873502..3798f46b 100644 --- a/packages/launchpad/types/index.d.ts +++ b/packages/launchpad/types/index.d.ts @@ -82,7 +82,13 @@ export { uint64ToString, } from "./lcdapi"; export { isMsgDelegate, isMsgSend, Msg, MsgDelegate, MsgSend } from "./msgs"; -export { decodeAminoPubkey, decodeBech32Pubkey, encodeBech32Pubkey, encodeSecp256k1Pubkey } from "./pubkey"; +export { + decodeAminoPubkey, + decodeBech32Pubkey, + encodeAminoPubkey, + encodeBech32Pubkey, + encodeSecp256k1Pubkey, +} from "./pubkey"; export { findSequenceForSignedTx } from "./sequence"; export { encodeSecp256k1Signature, decodeSignature } from "./signature"; export { FeeTable, SigningCosmosClient } from "./signingcosmosclient"; diff --git a/packages/launchpad/types/pubkey.d.ts b/packages/launchpad/types/pubkey.d.ts index 2319d77f..e3986512 100644 --- a/packages/launchpad/types/pubkey.d.ts +++ b/packages/launchpad/types/pubkey.d.ts @@ -1,5 +1,24 @@ import { PubKey } from "./types"; export declare function encodeSecp256k1Pubkey(pubkey: Uint8Array): PubKey; +/** + * Decodes a pubkey in the Amino binary format to a type/value object. + */ export declare function decodeAminoPubkey(data: Uint8Array): PubKey; +/** + * Decodes a bech32 pubkey to Amino binary, which is then decoded to a type/value object. + * The bech32 prefix is ignored and discareded. + * + * @param bechEncoded the bech32 encoded pubkey + */ export declare function decodeBech32Pubkey(bechEncoded: string): PubKey; +/** + * Encodes a public key to binary Amino. + */ +export declare function encodeAminoPubkey(pubkey: PubKey): Uint8Array; +/** + * Encodes a public key to binary Amino and then to bech32. + * + * @param pubkey the public key to encode + * @param prefix the bech32 prefix (human readable part) + */ export declare function encodeBech32Pubkey(pubkey: PubKey, prefix: string): string; diff --git a/packages/launchpad/types/types.d.ts b/packages/launchpad/types/types.d.ts index c12484fa..1a513b41 100644 --- a/packages/launchpad/types/types.d.ts +++ b/packages/launchpad/types/types.d.ts @@ -36,4 +36,3 @@ export declare const pubkeyType: { /** @see https://github.com/tendermint/tendermint/blob/v0.33.0/crypto/sr25519/codec.go#L12 */ sr25519: "tendermint/PubKeySr25519"; }; -export declare const pubkeyTypes: readonly string[]; diff --git a/packages/math/nonces/1597132850 b/packages/math/nonces/1597132850 new file mode 100644 index 00000000..e69de29b diff --git a/packages/math/package.json b/packages/math/package.json index 4e3058fd..77bf6de9 100644 --- a/packages/math/package.json +++ b/packages/math/package.json @@ -1,6 +1,6 @@ { "name": "@cosmjs/math", - "version": "0.22.0", + "version": "0.22.1", "description": "Math helpers for blockchain projects", "contributors": [ "IOV SAS " diff --git a/packages/proto-signing/nonces/1597132850 b/packages/proto-signing/nonces/1597132850 new file mode 100644 index 00000000..e69de29b diff --git a/packages/proto-signing/package.json b/packages/proto-signing/package.json index 8c39689d..b38eaafe 100644 --- a/packages/proto-signing/package.json +++ b/packages/proto-signing/package.json @@ -1,7 +1,7 @@ { "name": "@cosmjs/proto-signing", "private": true, - "version": "0.22.0", + "version": "0.22.1", "description": "Utilities for protobuf based signing (Cosmos SDK 0.40+)", "contributors": [ "Will Clark ", @@ -47,7 +47,7 @@ "protobufjs": "~6.10.0" }, "devDependencies": { - "@cosmjs/encoding": "^0.22.0", - "@cosmjs/utils": "^0.22.0" + "@cosmjs/encoding": "^0.22.1", + "@cosmjs/utils": "^0.22.1" } } diff --git a/packages/socket/nonces/1597132850 b/packages/socket/nonces/1597132850 new file mode 100644 index 00000000..e69de29b diff --git a/packages/socket/package.json b/packages/socket/package.json index c81815f4..87b793e4 100644 --- a/packages/socket/package.json +++ b/packages/socket/package.json @@ -1,6 +1,6 @@ { "name": "@cosmjs/socket", - "version": "0.22.0", + "version": "0.22.1", "description": "Utility functions for working with WebSockets", "contributors": [ "IOV SAS ", @@ -44,7 +44,7 @@ "pack-web": "yarn build-or-skip && webpack --mode development --config webpack.web.config.js" }, "dependencies": { - "@cosmjs/stream": "^0.22.0", + "@cosmjs/stream": "^0.22.1", "isomorphic-ws": "^4.0.1", "ws": "^6.2.0", "xstream": "^11.10.0" diff --git a/packages/stargate/package.json b/packages/stargate/package.json index edc84595..01549353 100644 --- a/packages/stargate/package.json +++ b/packages/stargate/package.json @@ -1,7 +1,7 @@ { "name": "@cosmjs/stargate", "private": true, - "version": "0.22.0", + "version": "0.22.1", "description": "Utilities for Cosmos SDK 0.40", "contributors": [ "Simon Warta " @@ -43,12 +43,12 @@ "postdefine-proto": "prettier --write \"src/generated/codecimpl.*\"" }, "dependencies": { - "@cosmjs/encoding": "^0.22.0", - "@cosmjs/launchpad": "^0.22.0", - "@cosmjs/math": "^0.22.0", - "@cosmjs/proto-signing": "^0.22.0", - "@cosmjs/tendermint-rpc": "^0.22.0", - "@cosmjs/utils": "^0.22.0", + "@cosmjs/encoding": "^0.22.1", + "@cosmjs/launchpad": "^0.22.1", + "@cosmjs/math": "^0.22.1", + "@cosmjs/proto-signing": "^0.22.1", + "@cosmjs/tendermint-rpc": "^0.22.1", + "@cosmjs/utils": "^0.22.1", "protobufjs": "~6.10.0" } } diff --git a/packages/stream/nonces/1597132850 b/packages/stream/nonces/1597132850 new file mode 100644 index 00000000..e69de29b diff --git a/packages/stream/package.json b/packages/stream/package.json index 2ec448d8..2fc0b767 100644 --- a/packages/stream/package.json +++ b/packages/stream/package.json @@ -1,6 +1,6 @@ { "name": "@cosmjs/stream", - "version": "0.22.0", + "version": "0.22.1", "description": "Utility functions for producing and consuming streams", "contributors": [ "IOV SAS ", diff --git a/packages/tendermint-rpc/nonces/1597132850 b/packages/tendermint-rpc/nonces/1597132850 new file mode 100644 index 00000000..e69de29b diff --git a/packages/tendermint-rpc/package.json b/packages/tendermint-rpc/package.json index b15b22c4..be5e4efc 100644 --- a/packages/tendermint-rpc/package.json +++ b/packages/tendermint-rpc/package.json @@ -1,6 +1,6 @@ { "name": "@cosmjs/tendermint-rpc", - "version": "0.22.0", + "version": "0.22.1", "description": "Tendermint RPC clients", "contributors": [ "IOV SAS ", @@ -44,18 +44,18 @@ "pack-web": "yarn build-or-skip && webpack --mode development --config webpack.web.config.js" }, "dependencies": { - "@cosmjs/crypto": "^0.22.0", - "@cosmjs/encoding": "^0.22.0", - "@cosmjs/json-rpc": "^0.22.0", - "@cosmjs/math": "^0.22.0", - "@cosmjs/socket": "^0.22.0", - "@cosmjs/stream": "^0.22.0", + "@cosmjs/crypto": "^0.22.1", + "@cosmjs/encoding": "^0.22.1", + "@cosmjs/json-rpc": "^0.22.1", + "@cosmjs/math": "^0.22.1", + "@cosmjs/socket": "^0.22.1", + "@cosmjs/stream": "^0.22.1", "axios": "^0.19.0", "readonly-date": "^1.0.0", "type-tagger": "^1.0.0", "xstream": "^11.10.0" }, "devDependencies": { - "@cosmjs/utils": "^0.22.0" + "@cosmjs/utils": "^0.22.1" } } diff --git a/packages/utils/nonces/1597132850 b/packages/utils/nonces/1597132850 new file mode 100644 index 00000000..e69de29b diff --git a/packages/utils/package.json b/packages/utils/package.json index 8ae535fd..4252d9da 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -1,6 +1,6 @@ { "name": "@cosmjs/utils", - "version": "0.22.0", + "version": "0.22.1", "description": "Utility tools, primarily for testing code", "contributors": [ "IOV SAS "