Use CosmosAddressBech32Prefix explicitely for addresses

This commit is contained in:
Simon Warta 2020-02-09 13:41:16 +01:00
parent 1ed25c1bc0
commit 00c033b669
15 changed files with 65 additions and 64 deletions

View File

@ -1,7 +1,7 @@
import { Algorithm, PubkeyBytes } from "@iov/bcp";
import { Encoding } from "@iov/encoding";
import { decodeCosmosPubkey, isValidAddress, pubkeyToAddress } from "./address";
import { decodeCosmosPubkey, pubkeyToAddress } from "./address";
const { fromBase64, fromHex } = Encoding;
@ -17,23 +17,6 @@ describe("address", () => {
});
});
describe("isValidAddress", () => {
it("accepts valid addresses", () => {
expect(isValidAddress("cosmos1pkptre7fdkl6gfrzlesjjvhxhlc3r4gmmk8rs6")).toEqual(true);
expect(isValidAddress("cosmosvalcons10q82zkzzmaku5lazhsvxv7hsg4ntpuhdwadmss")).toEqual(true);
expect(isValidAddress("cosmosvaloper17mggn4znyeyg25wd7498qxl7r2jhgue8u4qjcq")).toEqual(true);
});
it("rejects invalid addresses", () => {
// Bad size
expect(isValidAddress("cosmos10q82zkzzmaku5lazhsvxv7hsg4ntpuhh8289f")).toEqual(false);
// Bad checksum
expect(isValidAddress("cosmos1pkptre7fdkl6gfrzlesjjvhxhlc3r4gmmk8rs7")).toEqual(false);
// Bad prefix
expect(isValidAddress("cosmot10q82zkzzmaku5lazhsvxv7hsg4ntpuhd8j5266")).toEqual(false);
});
});
describe("pubkeyToAddress", () => {
it("works for Secp256k1 compressed", () => {
const prefix = "cosmos";

View File

@ -1,10 +1,8 @@
import { CosmosBech32Prefix, decodeBech32Pubkey, encodeAddress, isValidAddress, types } from "@cosmwasm/sdk";
import { CosmosAddressBech32Prefix, decodeBech32Pubkey, encodeAddress, types } from "@cosmwasm/sdk";
import { Address, Algorithm, PubkeyBundle, PubkeyBytes } from "@iov/bcp";
import { Secp256k1 } from "@iov/crypto";
import { Encoding } from "@iov/encoding";
export { CosmosBech32Prefix, isValidAddress };
const { fromBase64, toBase64 } = Encoding;
export function decodeCosmosPubkey(
@ -22,7 +20,7 @@ export function decodeCosmosPubkey(
}
// See https://github.com/tendermint/tendermint/blob/f2ada0a604b4c0763bda2f64fac53d506d3beca7/docs/spec/blockchain/encoding.md#public-key-cryptography
export function pubkeyToAddress(pubkey: PubkeyBundle, prefix: CosmosBech32Prefix): Address {
export function pubkeyToAddress(pubkey: PubkeyBundle, prefix: CosmosAddressBech32Prefix): Address {
let sdkKey: types.PubKey;
if (pubkey.algo === Algorithm.Secp256k1) {
sdkKey = {

View File

@ -7,6 +7,27 @@ import { chainId, nonce, sendTxJson, signedTxBin, signedTxEncodedJson, signedTxJ
const { toUtf8 } = Encoding;
describe("cosmWasmCodec", () => {
describe("isValidAddress", () => {
it("accepts valid addresses", () => {
expect(cosmWasmCodec.isValidAddress("cosmos1pkptre7fdkl6gfrzlesjjvhxhlc3r4gmmk8rs6")).toEqual(true);
expect(cosmWasmCodec.isValidAddress("cosmosvalcons10q82zkzzmaku5lazhsvxv7hsg4ntpuhdwadmss")).toEqual(
true,
);
expect(cosmWasmCodec.isValidAddress("cosmosvaloper17mggn4znyeyg25wd7498qxl7r2jhgue8u4qjcq")).toEqual(
true,
);
});
it("rejects invalid addresses", () => {
// Bad size
expect(cosmWasmCodec.isValidAddress("cosmos10q82zkzzmaku5lazhsvxv7hsg4ntpuhh8289f")).toEqual(false);
// Bad checksum
expect(cosmWasmCodec.isValidAddress("cosmos1pkptre7fdkl6gfrzlesjjvhxhlc3r4gmmk8rs7")).toEqual(false);
// Bad prefix
expect(cosmWasmCodec.isValidAddress("cosmot10q82zkzzmaku5lazhsvxv7hsg4ntpuhd8j5266")).toEqual(false);
});
});
it("properly generates bytes to sign", () => {
const expected = {
bytes: toUtf8(

View File

@ -1,5 +1,12 @@
/* eslint-disable @typescript-eslint/camelcase */
import { makeSignBytes, marshalTx, types, unmarshalTx } from "@cosmwasm/sdk";
import {
CosmosAddressBech32Prefix,
isValidAddress,
makeSignBytes,
marshalTx,
types,
unmarshalTx,
} from "@cosmwasm/sdk";
import {
Address,
ChainId,
@ -15,18 +22,18 @@ import {
UnsignedTransaction,
} from "@iov/bcp";
import { CosmosBech32Prefix, isValidAddress, pubkeyToAddress } from "./address";
import { pubkeyToAddress } from "./address";
import { Caip5 } from "./caip5";
import { parseTx } from "./decode";
import { buildSignedTx, buildUnsignedTx } from "./encode";
import { nonceToAccountNumber, nonceToSequence, TokenInfos } from "./types";
export class CosmWasmCodec implements TxCodec {
private readonly prefix: CosmosBech32Prefix;
private readonly addressPrefix: CosmosAddressBech32Prefix;
private readonly tokens: TokenInfos;
public constructor(prefix: CosmosBech32Prefix, tokens: TokenInfos) {
this.prefix = prefix;
public constructor(prefix: CosmosAddressBech32Prefix, tokens: TokenInfos) {
this.addressPrefix = prefix;
this.tokens = tokens;
}
@ -76,7 +83,7 @@ export class CosmWasmCodec implements TxCodec {
}
public identityToAddress(identity: Identity): Address {
return pubkeyToAddress(identity.pubkey, this.prefix);
return pubkeyToAddress(identity.pubkey, this.addressPrefix);
}
public isValidAddress(address: string): boolean {
@ -84,7 +91,7 @@ export class CosmWasmCodec implements TxCodec {
}
}
const defaultPrefix = "cosmos" as CosmosBech32Prefix;
const defaultPrefix = "cosmos" as CosmosAddressBech32Prefix;
const defaultTokens: TokenInfos = [
{

View File

@ -1,3 +1,4 @@
import { CosmosAddressBech32Prefix } from "@cosmwasm/sdk";
import {
Address,
Algorithm,
@ -14,7 +15,6 @@ import { Secp256k1 } from "@iov/crypto";
import { Encoding } from "@iov/encoding";
import { HdPaths, Secp256k1HdWallet, UserProfile } from "@iov/keycontrol";
import { CosmosBech32Prefix } from "./address";
import { CosmWasmCodec, cosmWasmCodec } from "./cosmwasmcodec";
import { CosmWasmConnection, TokenConfiguration } from "./cosmwasmconnection";
import { signedTxJson, txId } from "./testdata.spec";
@ -43,7 +43,7 @@ describe("CosmWasmConnection", () => {
const faucetPath = HdPaths.cosmos(0);
const defaultRecipient = "cosmos1t70qnpr0az8tf7py83m4ue5y89w58lkjmx0yq2" as Address;
const defaultPrefix = "cosmos" as CosmosBech32Prefix;
const defaultPrefix = "cosmos" as CosmosAddressBech32Prefix;
// this is for wasmd blockchain
const defaultTokens: TokenConfiguration = [

View File

@ -1,5 +1,5 @@
/* eslint-disable @typescript-eslint/camelcase */
import { RestClient, TxsResponse, types, unmarshalTx } from "@cosmwasm/sdk";
import { CosmosAddressBech32Prefix, RestClient, TxsResponse, types, unmarshalTx } from "@cosmwasm/sdk";
import {
Account,
AccountQuery,
@ -34,7 +34,7 @@ import equal from "fast-deep-equal";
import { ReadonlyDate } from "readonly-date";
import { Stream } from "xstream";
import { CosmosBech32Prefix, decodeCosmosPubkey, pubkeyToAddress } from "./address";
import { decodeCosmosPubkey, pubkeyToAddress } from "./address";
import { Caip5 } from "./caip5";
import { decodeAmount, parseTxsResponse } from "./decode";
import { accountToNonce, TokenInfo } from "./types";
@ -75,12 +75,12 @@ export class CosmWasmConnection implements BlockchainConnection {
// we must know prefix and tokens a priori to understand the chain
public static async establish(
url: string,
prefix: CosmosBech32Prefix,
addressPrefix: CosmosAddressBech32Prefix,
tokens: TokenConfiguration,
): Promise<CosmWasmConnection> {
const restClient = new RestClient(url);
const chainData = await this.initialize(restClient);
return new CosmWasmConnection(restClient, chainData, prefix, tokens);
return new CosmWasmConnection(restClient, chainData, addressPrefix, tokens);
}
private static async initialize(restClient: RestClient): Promise<ChainData> {
@ -90,26 +90,22 @@ export class CosmWasmConnection implements BlockchainConnection {
private readonly restClient: RestClient;
private readonly chainData: ChainData;
private readonly _prefix: CosmosBech32Prefix;
private readonly addressPrefix: CosmosAddressBech32Prefix;
private readonly tokenInfo: readonly TokenInfo[];
// these are derived from arguments (cached for use in multiple functions)
private readonly primaryToken: Token;
private readonly supportedTokens: readonly Token[];
private get prefix(): CosmosBech32Prefix {
return this._prefix;
}
private constructor(
restClient: RestClient,
chainData: ChainData,
prefix: CosmosBech32Prefix,
addressPrefix: CosmosAddressBech32Prefix,
tokens: TokenConfiguration,
) {
this.restClient = restClient;
this.chainData = chainData;
this._prefix = prefix;
this.addressPrefix = addressPrefix;
this.tokenInfo = tokens;
this.supportedTokens = tokens.map(info => ({
@ -149,7 +145,7 @@ export class CosmWasmConnection implements BlockchainConnection {
}
public async getAccount(query: AccountQuery): Promise<Account | undefined> {
const address = isPubkeyQuery(query) ? pubkeyToAddress(query.pubkey, this.prefix) : query.address;
const address = isPubkeyQuery(query) ? pubkeyToAddress(query.pubkey, this.addressPrefix) : query.address;
const { result } = await this.restClient.authAccounts(address);
const account = result.value;
if (!account.address) {
@ -172,7 +168,7 @@ export class CosmWasmConnection implements BlockchainConnection {
}
public async getNonce(query: AddressQuery | PubkeyQuery): Promise<Nonce> {
const address = isPubkeyQuery(query) ? pubkeyToAddress(query.pubkey, this.prefix) : query.address;
const address = isPubkeyQuery(query) ? pubkeyToAddress(query.pubkey, this.addressPrefix) : query.address;
const { result } = await this.restClient.authAccounts(address);
const account = result.value;
return accountToNonce(account);

View File

@ -1,6 +1,6 @@
import { CosmosAddressBech32Prefix } from "@cosmwasm/sdk";
import { ChainConnector, ChainId } from "@iov/bcp";
import { CosmosBech32Prefix } from "./address";
import { CosmWasmCodec } from "./cosmwasmcodec";
import { CosmWasmConnection, TokenConfiguration } from "./cosmwasmconnection";
@ -9,13 +9,13 @@ import { CosmWasmConnection, TokenConfiguration } from "./cosmwasmconnection";
*/
export function createCosmWasmConnector(
url: string,
prefix: CosmosBech32Prefix,
addressPrefix: CosmosAddressBech32Prefix,
tokens: TokenConfiguration,
expectedChainId?: ChainId,
): ChainConnector<CosmWasmConnection> {
const codec = new CosmWasmCodec(prefix, tokens);
const codec = new CosmWasmCodec(addressPrefix, tokens);
return {
establishConnection: async () => CosmWasmConnection.establish(url, prefix, tokens),
establishConnection: async () => CosmWasmConnection.establish(url, addressPrefix, tokens),
codec: codec,
expectedChainId: expectedChainId,
};

View File

@ -1,10 +1,9 @@
import { CosmosBech32Prefix, isValidAddress } from "@cosmwasm/sdk";
import { CosmosAddressBech32Prefix } from "@cosmwasm/sdk";
import { Address, Algorithm, PubkeyBundle, PubkeyBytes } from "@iov/bcp";
export { CosmosBech32Prefix, isValidAddress };
export declare function decodeCosmosPubkey(
encodedPubkey: string,
): {
readonly algo: Algorithm;
readonly data: PubkeyBytes;
};
export declare function pubkeyToAddress(pubkey: PubkeyBundle, prefix: CosmosBech32Prefix): Address;
export declare function pubkeyToAddress(pubkey: PubkeyBundle, prefix: CosmosAddressBech32Prefix): Address;

View File

@ -1,3 +1,4 @@
import { CosmosAddressBech32Prefix } from "@cosmwasm/sdk";
import {
Address,
ChainId,
@ -10,12 +11,11 @@ import {
TxCodec,
UnsignedTransaction,
} from "@iov/bcp";
import { CosmosBech32Prefix } from "./address";
import { TokenInfos } from "./types";
export declare class CosmWasmCodec implements TxCodec {
private readonly prefix;
private readonly addressPrefix;
private readonly tokens;
constructor(prefix: CosmosBech32Prefix, tokens: TokenInfos);
constructor(prefix: CosmosAddressBech32Prefix, tokens: TokenInfos);
bytesToSign(unsigned: UnsignedTransaction, nonce: Nonce): SigningJob;
bytesToPost(signed: SignedTransaction): PostableBytes;
identifier(_signed: SignedTransaction): TransactionId;

View File

@ -1,3 +1,4 @@
import { CosmosAddressBech32Prefix } from "@cosmwasm/sdk";
import {
Account,
AccountQuery,
@ -20,7 +21,6 @@ import {
UnsignedTransaction,
} from "@iov/bcp";
import { Stream } from "xstream";
import { CosmosBech32Prefix } from "./address";
import { TokenInfo } from "./types";
export declare type TokenConfiguration = ReadonlyArray<
TokenInfo & {
@ -30,17 +30,16 @@ export declare type TokenConfiguration = ReadonlyArray<
export declare class CosmWasmConnection implements BlockchainConnection {
static establish(
url: string,
prefix: CosmosBech32Prefix,
addressPrefix: CosmosAddressBech32Prefix,
tokens: TokenConfiguration,
): Promise<CosmWasmConnection>;
private static initialize;
private readonly restClient;
private readonly chainData;
private readonly _prefix;
private readonly addressPrefix;
private readonly tokenInfo;
private readonly primaryToken;
private readonly supportedTokens;
private get prefix();
private constructor();
disconnect(): void;
chainId(): ChainId;

View File

@ -1,12 +1,12 @@
import { CosmosAddressBech32Prefix } from "@cosmwasm/sdk";
import { ChainConnector, ChainId } from "@iov/bcp";
import { CosmosBech32Prefix } from "./address";
import { CosmWasmConnection, TokenConfiguration } from "./cosmwasmconnection";
/**
* A helper to connect to a cosmos-based chain at a given url
*/
export declare function createCosmWasmConnector(
url: string,
prefix: CosmosBech32Prefix,
addressPrefix: CosmosAddressBech32Prefix,
tokens: TokenConfiguration,
expectedChainId?: ChainId,
): ChainConnector<CosmWasmConnection>;

View File

@ -8,7 +8,6 @@ const { fromBase64 } = Encoding;
// TODO: make this much more configurable
export type CosmosAddressBech32Prefix = "cosmos" | "cosmosvalcons" | "cosmosvaloper";
export type CosmosPubkeyBech32Prefix = "cosmospub" | "cosmosvalconspub" | "cosmosvaloperpub";
export type CosmosBech32Prefix = CosmosAddressBech32Prefix | CosmosPubkeyBech32Prefix;
function isCosmosAddressBech32Prefix(prefix: string): prefix is CosmosAddressBech32Prefix {
return ["cosmos", "cosmosvalcons", "cosmosvaloper"].includes(prefix);

View File

@ -2,7 +2,7 @@ import * as logs from "./logs";
import * as types from "./types";
export { logs, types };
export { CosmosBech32Prefix, encodeAddress, isValidAddress } from "./address";
export { CosmosAddressBech32Prefix, encodeAddress, isValidAddress } from "./address";
export { unmarshalTx } from "./decoding";
export { encodeSecp256k1Signature, makeSignBytes, marshalTx } from "./encoding";
export { RestClient, TxsResponse } from "./restclient";

View File

@ -1,6 +1,5 @@
import { PubKey } from "./types";
export declare type CosmosAddressBech32Prefix = "cosmos" | "cosmosvalcons" | "cosmosvaloper";
export declare type CosmosPubkeyBech32Prefix = "cosmospub" | "cosmosvalconspub" | "cosmosvaloperpub";
export declare type CosmosBech32Prefix = CosmosAddressBech32Prefix | CosmosPubkeyBech32Prefix;
export declare function isValidAddress(address: string): boolean;
export declare function encodeAddress(pubkey: PubKey, prefix: string): string;

View File

@ -1,7 +1,7 @@
import * as logs from "./logs";
import * as types from "./types";
export { logs, types };
export { CosmosBech32Prefix, encodeAddress, isValidAddress } from "./address";
export { CosmosAddressBech32Prefix, encodeAddress, isValidAddress } from "./address";
export { unmarshalTx } from "./decoding";
export { encodeSecp256k1Signature, makeSignBytes, marshalTx } from "./encoding";
export { RestClient, TxsResponse } from "./restclient";