Use CosmosAddressBech32Prefix explicitely for addresses
This commit is contained in:
parent
1ed25c1bc0
commit
00c033b669
@ -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";
|
||||
|
||||
@ -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 = {
|
||||
|
||||
@ -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(
|
||||
|
||||
@ -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 = [
|
||||
{
|
||||
|
||||
@ -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 = [
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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,
|
||||
};
|
||||
|
||||
5
packages/bcp/types/address.d.ts
vendored
5
packages/bcp/types/address.d.ts
vendored
@ -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;
|
||||
|
||||
6
packages/bcp/types/cosmwasmcodec.d.ts
vendored
6
packages/bcp/types/cosmwasmcodec.d.ts
vendored
@ -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;
|
||||
|
||||
7
packages/bcp/types/cosmwasmconnection.d.ts
vendored
7
packages/bcp/types/cosmwasmconnection.d.ts
vendored
@ -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;
|
||||
|
||||
4
packages/bcp/types/cosmwasmconnector.d.ts
vendored
4
packages/bcp/types/cosmwasmconnector.d.ts
vendored
@ -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>;
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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";
|
||||
|
||||
1
packages/sdk/types/address.d.ts
vendored
1
packages/sdk/types/address.d.ts
vendored
@ -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;
|
||||
|
||||
2
packages/sdk/types/index.d.ts
vendored
2
packages/sdk/types/index.d.ts
vendored
@ -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";
|
||||
|
||||
Loading…
Reference in New Issue
Block a user