Merge branch '0.22'

This commit is contained in:
Simon Warta 2020-08-11 10:20:09 +02:00
commit 2ffda0d25e
51 changed files with 386 additions and 141 deletions

View File

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

View File

@ -1,5 +1,5 @@
{
"version": "0.22.0",
"version": "0.22.1",
"useWorkspaces": true,
"npmClient": "yarn"
}

View File

View File

@ -1,6 +1,6 @@
{
"name": "@cosmjs/cli",
"version": "0.22.0",
"version": "0.22.1",
"description": "Command line interface",
"contributors": [
"IOV SAS <admin@iov.one>",
@ -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",

View File

@ -89,6 +89,10 @@ export async function main(originalArgs: readonly string[]): Promise<void> {
[
"coin",
"coins",
"decodeAminoPubkey",
"decodeBech32Pubkey",
"encodeAminoPubkey",
"encodeBech32Pubkey",
"encodeSecp256k1Pubkey",
"encodeSecp256k1Signature",
"logs",
@ -112,7 +116,7 @@ export async function main(originalArgs: readonly string[]): Promise<void> {
],
],
["@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<void> {
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);
`;

View File

View File

@ -1,6 +1,6 @@
{
"name": "@cosmjs/cosmwasm",
"version": "0.22.0",
"version": "0.22.1",
"description": "CosmWasm SDK",
"author": "Ethan Frey <ethanfrey@users.noreply.github.com>",
"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": {

View File

View File

@ -1,6 +1,6 @@
{
"name": "@cosmjs/crypto",
"version": "0.22.0",
"version": "0.22.1",
"description": "Cryptography resources for blockchain projects",
"contributors": [
"IOV SAS <admin@iov.one>",
@ -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",

View File

View File

@ -1,6 +1,6 @@
{
"name": "@cosmjs/encoding",
"version": "0.22.0",
"version": "0.22.1",
"description": "Encoding helpers for blockchain projects",
"contributors": [
"IOV SAS <admin@iov.one>"

View File

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

View File

View File

@ -1,6 +1,6 @@
{
"name": "@cosmjs/faucet",
"version": "0.22.0",
"version": "0.22.1",
"description": "The faucet",
"author": "Ethan Frey <ethanfrey@users.noreply.github.com>",
"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"

View File

@ -4,17 +4,15 @@ import * as constants from "../constants";
import { createWallets } from "../profile";
export async function generate(args: readonly string[]): Promise<void> {
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);
}

View File

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

View File

@ -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<void> {
if (args.length < 1) {
@ -23,7 +23,7 @@ export async function start(args: readonly string[]): Promise<void> {
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<void> {
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<void> {
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.`);
}

View File

@ -1 +0,0 @@
export { start } from "./start";

View File

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

View File

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

View File

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

View File

@ -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<X>(value: X | undefined): value is X {
return value !== undefined;
@ -119,7 +119,7 @@ export class Faucet {
public async refill(): Promise<void> {
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(", ")}`);
}

View File

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

View File

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

View File

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

View File

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

View File

@ -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<Account, "address" | "balance">;

View File

View File

@ -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 <admin@iov.one>",
@ -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"
}
}

View File

View File

@ -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 <ethanfrey@users.noreply.github.com>",
@ -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"

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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[];

View File

View File

@ -1,6 +1,6 @@
{
"name": "@cosmjs/math",
"version": "0.22.0",
"version": "0.22.1",
"description": "Math helpers for blockchain projects",
"contributors": [
"IOV SAS <admin@iov.one>"

View File

View File

@ -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 <willclarktech@users.noreply.github.com>",
@ -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"
}
}

View File

View File

@ -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 <admin@iov.one>",
@ -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"

View File

@ -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 <webmaster128@users.noreply.github.com>"
@ -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"
}
}

View File

View File

@ -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 <admin@iov.one>",

View File

@ -1,6 +1,6 @@
{
"name": "@cosmjs/tendermint-rpc",
"version": "0.22.0",
"version": "0.22.1",
"description": "Tendermint RPC clients",
"contributors": [
"IOV SAS <admin@iov.one>",
@ -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"
}
}

View File

View File

@ -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 <admin@iov.one>"