Merge pull request #110 from confio/simplify-prefix
Simplify address prefix handling
This commit is contained in:
commit
db550220db
@ -1,4 +1,4 @@
|
||||
import { CosmosAddressBech32Prefix, decodeBech32Pubkey, encodeAddress, types } from "@cosmwasm/sdk";
|
||||
import { decodeBech32Pubkey, pubkeyToAddress as sdkPubkeyToAddress, types } from "@cosmwasm/sdk";
|
||||
import { Address, Algorithm, PubkeyBundle, PubkeyBytes } from "@iov/bcp";
|
||||
import { Secp256k1 } from "@iov/crypto";
|
||||
import { Encoding } from "@iov/encoding";
|
||||
@ -18,7 +18,7 @@ export function decodeCosmosPubkey(encodedPubkey: string): PubkeyBundle {
|
||||
}
|
||||
|
||||
// See https://github.com/tendermint/tendermint/blob/f2ada0a604b4c0763bda2f64fac53d506d3beca7/docs/spec/blockchain/encoding.md#public-key-cryptography
|
||||
export function pubkeyToAddress(pubkey: PubkeyBundle, prefix: CosmosAddressBech32Prefix): Address {
|
||||
export function pubkeyToAddress(pubkey: PubkeyBundle, prefix: string): Address {
|
||||
let sdkKey: types.PubKey;
|
||||
if (pubkey.algo === Algorithm.Secp256k1) {
|
||||
sdkKey = {
|
||||
@ -34,5 +34,5 @@ export function pubkeyToAddress(pubkey: PubkeyBundle, prefix: CosmosAddressBech3
|
||||
throw new Error(`Unsupported algorithm: ${pubkey.algo}`);
|
||||
}
|
||||
|
||||
return encodeAddress(sdkKey, prefix) as Address;
|
||||
return sdkPubkeyToAddress(sdkKey, prefix) as Address;
|
||||
}
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
import { CosmosAddressBech32Prefix } from "@cosmwasm/sdk";
|
||||
import { Address, PostableBytes, PrehashType, SendTransaction, TokenTicker } from "@iov/bcp";
|
||||
import { Encoding } from "@iov/encoding";
|
||||
|
||||
@ -8,7 +7,7 @@ import { BankToken, Erc20Token } from "./types";
|
||||
|
||||
const { toUtf8 } = Encoding;
|
||||
|
||||
const defaultPrefix = "cosmos" as CosmosAddressBech32Prefix;
|
||||
const defaultPrefix = "cosmos";
|
||||
|
||||
const defaultBankTokens: readonly BankToken[] = [
|
||||
{
|
||||
@ -42,8 +41,6 @@ describe("CosmWasmCodec", () => {
|
||||
describe("isValidAddress", () => {
|
||||
it("accepts valid addresses", () => {
|
||||
expect(codec.isValidAddress("cosmos1pkptre7fdkl6gfrzlesjjvhxhlc3r4gmmk8rs6")).toEqual(true);
|
||||
expect(codec.isValidAddress("cosmosvalcons10q82zkzzmaku5lazhsvxv7hsg4ntpuhdwadmss")).toEqual(true);
|
||||
expect(codec.isValidAddress("cosmosvaloper17mggn4znyeyg25wd7498qxl7r2jhgue8u4qjcq")).toEqual(true);
|
||||
});
|
||||
|
||||
it("rejects invalid addresses", () => {
|
||||
@ -53,6 +50,8 @@ describe("CosmWasmCodec", () => {
|
||||
expect(codec.isValidAddress("cosmos1pkptre7fdkl6gfrzlesjjvhxhlc3r4gmmk8rs7")).toEqual(false);
|
||||
// Bad prefix
|
||||
expect(codec.isValidAddress("cosmot10q82zkzzmaku5lazhsvxv7hsg4ntpuhd8j5266")).toEqual(false);
|
||||
expect(codec.isValidAddress("cosmosvalcons10q82zkzzmaku5lazhsvxv7hsg4ntpuhdwadmss")).toEqual(false);
|
||||
expect(codec.isValidAddress("cosmosvaloper17mggn4znyeyg25wd7498qxl7r2jhgue8u4qjcq")).toEqual(false);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@ -1,11 +1,5 @@
|
||||
/* eslint-disable @typescript-eslint/camelcase */
|
||||
import {
|
||||
CosmosAddressBech32Prefix,
|
||||
isValidAddress,
|
||||
makeSignBytes,
|
||||
marshalTx,
|
||||
unmarshalTx,
|
||||
} from "@cosmwasm/sdk";
|
||||
import { makeSignBytes, marshalTx, unmarshalTx } from "@cosmwasm/sdk";
|
||||
import {
|
||||
Address,
|
||||
ChainId,
|
||||
@ -20,6 +14,7 @@ import {
|
||||
TxCodec,
|
||||
UnsignedTransaction,
|
||||
} from "@iov/bcp";
|
||||
import { Bech32 } from "@iov/encoding";
|
||||
|
||||
import { pubkeyToAddress } from "./address";
|
||||
import { Caip5 } from "./caip5";
|
||||
@ -28,15 +23,11 @@ import { buildSignedTx, buildUnsignedTx } from "./encode";
|
||||
import { BankTokens, Erc20Token, nonceToAccountNumber, nonceToSequence } from "./types";
|
||||
|
||||
export class CosmWasmCodec implements TxCodec {
|
||||
private readonly addressPrefix: CosmosAddressBech32Prefix;
|
||||
private readonly addressPrefix: string;
|
||||
private readonly bankTokens: BankTokens;
|
||||
private readonly erc20Tokens: readonly Erc20Token[];
|
||||
|
||||
public constructor(
|
||||
addressPrefix: CosmosAddressBech32Prefix,
|
||||
bankTokens: BankTokens,
|
||||
erc20Tokens: readonly Erc20Token[] = [],
|
||||
) {
|
||||
public constructor(addressPrefix: string, bankTokens: BankTokens, erc20Tokens: readonly Erc20Token[] = []) {
|
||||
this.addressPrefix = addressPrefix;
|
||||
this.bankTokens = bankTokens;
|
||||
this.erc20Tokens = erc20Tokens;
|
||||
@ -89,6 +80,14 @@ export class CosmWasmCodec implements TxCodec {
|
||||
}
|
||||
|
||||
public isValidAddress(address: string): boolean {
|
||||
return isValidAddress(address);
|
||||
try {
|
||||
const { prefix, data } = Bech32.decode(address);
|
||||
if (prefix !== this.addressPrefix) {
|
||||
return false;
|
||||
}
|
||||
return data.length === 20;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,8 +1,4 @@
|
||||
import {
|
||||
CosmosAddressBech32Prefix,
|
||||
decodeSignature,
|
||||
makeSecp256k1SignatureFromFixedLength,
|
||||
} from "@cosmwasm/sdk";
|
||||
import { decodeSignature, makeSecp256k1SignatureFromFixedLength } from "@cosmwasm/sdk";
|
||||
import {
|
||||
Account,
|
||||
Address,
|
||||
@ -39,10 +35,10 @@ function pendingWithoutWasmd(): void {
|
||||
}
|
||||
}
|
||||
|
||||
const defaultPrefix = "cosmos" as CosmosAddressBech32Prefix;
|
||||
const defaultAddressPrefix = "cosmos";
|
||||
|
||||
function makeRandomAddress(): Address {
|
||||
return Bech32.encode(defaultPrefix, Random.getBytes(20)) as Address;
|
||||
return Bech32.encode(defaultAddressPrefix, Random.getBytes(20)) as Address;
|
||||
}
|
||||
|
||||
const faucet = {
|
||||
@ -129,7 +125,7 @@ describe("CosmWasmConnection", () => {
|
||||
describe("establish", () => {
|
||||
it("can connect to Cosmos via http", async () => {
|
||||
pendingWithoutWasmd();
|
||||
const connection = await CosmWasmConnection.establish(httpUrl, defaultPrefix, defaultConfig);
|
||||
const connection = await CosmWasmConnection.establish(httpUrl, defaultAddressPrefix, defaultConfig);
|
||||
expect(connection).toBeTruthy();
|
||||
connection.disconnect();
|
||||
});
|
||||
@ -138,7 +134,7 @@ describe("CosmWasmConnection", () => {
|
||||
describe("chainId", () => {
|
||||
it("displays the chain ID", async () => {
|
||||
pendingWithoutWasmd();
|
||||
const connection = await CosmWasmConnection.establish(httpUrl, defaultPrefix, defaultConfig);
|
||||
const connection = await CosmWasmConnection.establish(httpUrl, defaultAddressPrefix, defaultConfig);
|
||||
expect(connection.chainId).toEqual(defaultChainId);
|
||||
connection.disconnect();
|
||||
});
|
||||
@ -147,7 +143,7 @@ describe("CosmWasmConnection", () => {
|
||||
describe("height", () => {
|
||||
it("displays the current height", async () => {
|
||||
pendingWithoutWasmd();
|
||||
const connection = await CosmWasmConnection.establish(httpUrl, defaultPrefix, defaultConfig);
|
||||
const connection = await CosmWasmConnection.establish(httpUrl, defaultAddressPrefix, defaultConfig);
|
||||
const height = await connection.height();
|
||||
expect(height).toBeGreaterThan(0);
|
||||
connection.disconnect();
|
||||
@ -157,7 +153,7 @@ describe("CosmWasmConnection", () => {
|
||||
describe("getToken", () => {
|
||||
it("displays a given token", async () => {
|
||||
pendingWithoutWasmd();
|
||||
const connection = await CosmWasmConnection.establish(httpUrl, defaultPrefix, defaultConfig);
|
||||
const connection = await CosmWasmConnection.establish(httpUrl, defaultAddressPrefix, defaultConfig);
|
||||
const token = await connection.getToken("COSM" as TokenTicker);
|
||||
expect(token).toEqual({
|
||||
fractionalDigits: 6,
|
||||
@ -169,7 +165,7 @@ describe("CosmWasmConnection", () => {
|
||||
|
||||
it("resolves to undefined if the token is not supported", async () => {
|
||||
pendingWithoutWasmd();
|
||||
const connection = await CosmWasmConnection.establish(httpUrl, defaultPrefix, defaultConfig);
|
||||
const connection = await CosmWasmConnection.establish(httpUrl, defaultAddressPrefix, defaultConfig);
|
||||
const token = await connection.getToken("whatever" as TokenTicker);
|
||||
expect(token).toBeUndefined();
|
||||
connection.disconnect();
|
||||
@ -179,7 +175,7 @@ describe("CosmWasmConnection", () => {
|
||||
describe("getAllTokens", () => {
|
||||
it("resolves to a list of all supported tokens", async () => {
|
||||
pendingWithoutWasmd();
|
||||
const connection = await CosmWasmConnection.establish(httpUrl, defaultPrefix, defaultConfig);
|
||||
const connection = await CosmWasmConnection.establish(httpUrl, defaultAddressPrefix, defaultConfig);
|
||||
const tokens = await connection.getAllTokens();
|
||||
expect(tokens).toEqual([
|
||||
{
|
||||
@ -215,7 +211,7 @@ describe("CosmWasmConnection", () => {
|
||||
describe("identifier", () => {
|
||||
it("calculates tx hash from PostableBytes", async () => {
|
||||
pendingWithoutWasmd();
|
||||
const connection = await CosmWasmConnection.establish(httpUrl, defaultPrefix, atomConfig);
|
||||
const connection = await CosmWasmConnection.establish(httpUrl, defaultAddressPrefix, atomConfig);
|
||||
const id = await connection.identifier(testdata.signedTxJson);
|
||||
expect(id).toMatch(/^[0-9A-F]{64}$/);
|
||||
expect(id).toEqual(testdata.txId);
|
||||
@ -225,7 +221,7 @@ describe("CosmWasmConnection", () => {
|
||||
describe("getAccount", () => {
|
||||
it("gets an empty account by address", async () => {
|
||||
pendingWithoutWasmd();
|
||||
const connection = await CosmWasmConnection.establish(httpUrl, defaultPrefix, defaultConfig);
|
||||
const connection = await CosmWasmConnection.establish(httpUrl, defaultAddressPrefix, defaultConfig);
|
||||
const account = await connection.getAccount({ address: defaultEmptyAddress });
|
||||
expect(account).toBeUndefined();
|
||||
connection.disconnect();
|
||||
@ -233,7 +229,7 @@ describe("CosmWasmConnection", () => {
|
||||
|
||||
it("gets an account by address", async () => {
|
||||
pendingWithoutWasmd();
|
||||
const connection = await CosmWasmConnection.establish(httpUrl, defaultPrefix, defaultConfig);
|
||||
const connection = await CosmWasmConnection.establish(httpUrl, defaultAddressPrefix, defaultConfig);
|
||||
const account = await connection.getAccount({ address: unusedAccount.address });
|
||||
assert(account, "Account must be defined");
|
||||
expect(account.address).toEqual(unusedAccount.address);
|
||||
@ -265,7 +261,7 @@ describe("CosmWasmConnection", () => {
|
||||
|
||||
it("gets an account by pubkey", async () => {
|
||||
pendingWithoutWasmd();
|
||||
const connection = await CosmWasmConnection.establish(httpUrl, defaultPrefix, defaultConfig);
|
||||
const connection = await CosmWasmConnection.establish(httpUrl, defaultAddressPrefix, defaultConfig);
|
||||
const byAddress = await connection.getAccount({ address: unusedAccount.address });
|
||||
const byPubkey = await connection.getAccount({ pubkey: unusedAccount.pubkey });
|
||||
expect(byPubkey).toEqual(byAddress); // above we verified that by address works as expected
|
||||
@ -274,7 +270,7 @@ describe("CosmWasmConnection", () => {
|
||||
|
||||
it("has a pubkey when getting account with transactions", async () => {
|
||||
pendingWithoutWasmd();
|
||||
const connection = await CosmWasmConnection.establish(httpUrl, defaultPrefix, defaultConfig);
|
||||
const connection = await CosmWasmConnection.establish(httpUrl, defaultAddressPrefix, defaultConfig);
|
||||
const account = await connection.getAccount({ address: faucet.address });
|
||||
expect(account?.pubkey).toEqual(faucet.pubkey);
|
||||
connection.disconnect();
|
||||
@ -288,7 +284,7 @@ describe("CosmWasmConnection", () => {
|
||||
const events = new Array<Account | undefined>();
|
||||
|
||||
(async () => {
|
||||
const connection = await CosmWasmConnection.establish(httpUrl, defaultPrefix, defaultConfig);
|
||||
const connection = await CosmWasmConnection.establish(httpUrl, defaultAddressPrefix, defaultConfig);
|
||||
const subscription = connection.watchAccount({ address: recipient }).subscribe({
|
||||
next: event => {
|
||||
events.push(event);
|
||||
@ -348,7 +344,7 @@ describe("CosmWasmConnection", () => {
|
||||
describe("getTx", () => {
|
||||
it("can get a recently posted bank send transaction", async () => {
|
||||
pendingWithoutWasmd();
|
||||
const connection = await CosmWasmConnection.establish(httpUrl, defaultPrefix, defaultConfig);
|
||||
const connection = await CosmWasmConnection.establish(httpUrl, defaultAddressPrefix, defaultConfig);
|
||||
const profile = new UserProfile();
|
||||
const wallet = profile.addWallet(Secp256k1HdWallet.fromMnemonic(faucet.mnemonic));
|
||||
const senderIdentity = await profile.createIdentity(wallet.id, defaultChainId, faucet.path);
|
||||
@ -399,7 +395,7 @@ describe("CosmWasmConnection", () => {
|
||||
|
||||
it("can get a recently posted ERC20 send transaction", async () => {
|
||||
pendingWithoutWasmd();
|
||||
const connection = await CosmWasmConnection.establish(httpUrl, defaultPrefix, defaultConfig);
|
||||
const connection = await CosmWasmConnection.establish(httpUrl, defaultAddressPrefix, defaultConfig);
|
||||
const profile = new UserProfile();
|
||||
const wallet = profile.addWallet(Secp256k1HdWallet.fromMnemonic(faucet.mnemonic));
|
||||
const senderIdentity = await profile.createIdentity(wallet.id, defaultChainId, faucet.path);
|
||||
@ -449,7 +445,7 @@ describe("CosmWasmConnection", () => {
|
||||
|
||||
it("can get an old transaction", async () => {
|
||||
pendingWithoutWasmd();
|
||||
const connection = await CosmWasmConnection.establish(httpUrl, defaultPrefix, defaultConfig);
|
||||
const connection = await CosmWasmConnection.establish(httpUrl, defaultAddressPrefix, defaultConfig);
|
||||
|
||||
const results = await connection.searchTx({ sentFromOrTo: faucet.address });
|
||||
const firstSearchResult = results.find(() => true);
|
||||
@ -490,7 +486,7 @@ describe("CosmWasmConnection", () => {
|
||||
|
||||
it("throws for non-existent transaction", async () => {
|
||||
pendingWithoutWasmd();
|
||||
const connection = await CosmWasmConnection.establish(httpUrl, defaultPrefix, defaultConfig);
|
||||
const connection = await CosmWasmConnection.establish(httpUrl, defaultAddressPrefix, defaultConfig);
|
||||
|
||||
const nonExistentId = "0000000000000000000000000000000000000000000000000000000000000000" as TransactionId;
|
||||
await connection.getTx(nonExistentId).then(
|
||||
@ -505,7 +501,7 @@ describe("CosmWasmConnection", () => {
|
||||
describe("searchTx", () => {
|
||||
it("can post and search for a transaction", async () => {
|
||||
pendingWithoutWasmd();
|
||||
const connection = await CosmWasmConnection.establish(httpUrl, defaultPrefix, defaultConfig);
|
||||
const connection = await CosmWasmConnection.establish(httpUrl, defaultAddressPrefix, defaultConfig);
|
||||
const profile = new UserProfile();
|
||||
const wallet = profile.addWallet(Secp256k1HdWallet.fromMnemonic(faucet.mnemonic));
|
||||
const sender = await profile.createIdentity(wallet.id, defaultChainId, faucet.path);
|
||||
@ -595,7 +591,7 @@ describe("CosmWasmConnection", () => {
|
||||
|
||||
it("can search by minHeight and maxHeight", async () => {
|
||||
pendingWithoutWasmd();
|
||||
const connection = await CosmWasmConnection.establish(httpUrl, defaultPrefix, defaultConfig);
|
||||
const connection = await CosmWasmConnection.establish(httpUrl, defaultAddressPrefix, defaultConfig);
|
||||
const profile = new UserProfile();
|
||||
const wallet = profile.addWallet(Secp256k1HdWallet.fromMnemonic(faucet.mnemonic));
|
||||
const sender = await profile.createIdentity(wallet.id, defaultChainId, faucet.path);
|
||||
@ -806,7 +802,7 @@ describe("CosmWasmConnection", () => {
|
||||
pendingWithoutWasmd();
|
||||
|
||||
(async () => {
|
||||
const connection = await CosmWasmConnection.establish(httpUrl, defaultPrefix, defaultConfig);
|
||||
const connection = await CosmWasmConnection.establish(httpUrl, defaultAddressPrefix, defaultConfig);
|
||||
|
||||
const profile = new UserProfile();
|
||||
const wallet = profile.addWallet(Secp256k1HdWallet.fromMnemonic(faucet.mnemonic));
|
||||
@ -889,7 +885,7 @@ describe("CosmWasmConnection", () => {
|
||||
pendingWithoutWasmd();
|
||||
|
||||
(async () => {
|
||||
const connection = await CosmWasmConnection.establish(httpUrl, defaultPrefix, defaultConfig);
|
||||
const connection = await CosmWasmConnection.establish(httpUrl, defaultAddressPrefix, defaultConfig);
|
||||
|
||||
const profile = new UserProfile();
|
||||
const wallet = profile.addWallet(Secp256k1HdWallet.fromMnemonic(faucet.mnemonic));
|
||||
@ -939,7 +935,7 @@ describe("CosmWasmConnection", () => {
|
||||
pendingWithoutWasmd();
|
||||
|
||||
(async () => {
|
||||
const connection = await CosmWasmConnection.establish(httpUrl, defaultPrefix, defaultConfig);
|
||||
const connection = await CosmWasmConnection.establish(httpUrl, defaultAddressPrefix, defaultConfig);
|
||||
|
||||
const profile = new UserProfile();
|
||||
const wallet = profile.addWallet(Secp256k1HdWallet.fromMnemonic(faucet.mnemonic));
|
||||
@ -988,7 +984,7 @@ describe("CosmWasmConnection", () => {
|
||||
describe("integration tests", () => {
|
||||
it("can send ERC20 tokens", async () => {
|
||||
pendingWithoutWasmd();
|
||||
const connection = await CosmWasmConnection.establish(httpUrl, defaultPrefix, defaultConfig);
|
||||
const connection = await CosmWasmConnection.establish(httpUrl, defaultAddressPrefix, defaultConfig);
|
||||
const profile = new UserProfile();
|
||||
const wallet = profile.addWallet(Secp256k1HdWallet.fromMnemonic(faucet.mnemonic));
|
||||
const sender = await profile.createIdentity(wallet.id, defaultChainId, faucet.path);
|
||||
|
||||
@ -1,11 +1,5 @@
|
||||
/* eslint-disable @typescript-eslint/camelcase */
|
||||
import {
|
||||
CosmosAddressBech32Prefix,
|
||||
CosmWasmClient,
|
||||
findSequenceForSignedTx,
|
||||
TxsResponse,
|
||||
types,
|
||||
} from "@cosmwasm/sdk";
|
||||
import { CosmWasmClient, findSequenceForSignedTx, TxsResponse, types } from "@cosmwasm/sdk";
|
||||
import {
|
||||
Account,
|
||||
AccountQuery,
|
||||
@ -73,7 +67,7 @@ export class CosmWasmConnection implements BlockchainConnection {
|
||||
// we must know prefix and tokens a priori to understand the chain
|
||||
public static async establish(
|
||||
url: string,
|
||||
addressPrefix: CosmosAddressBech32Prefix,
|
||||
addressPrefix: string,
|
||||
tokens: TokenConfiguration,
|
||||
): Promise<CosmWasmConnection> {
|
||||
const cosmWasmClient = new CosmWasmClient(url);
|
||||
@ -90,7 +84,7 @@ export class CosmWasmConnection implements BlockchainConnection {
|
||||
public readonly codec: TxCodec;
|
||||
|
||||
private readonly cosmWasmClient: CosmWasmClient;
|
||||
private readonly addressPrefix: CosmosAddressBech32Prefix;
|
||||
private readonly addressPrefix: string;
|
||||
private readonly bankTokens: readonly BankToken[];
|
||||
private readonly erc20Tokens: readonly Erc20Token[];
|
||||
|
||||
@ -101,7 +95,7 @@ export class CosmWasmConnection implements BlockchainConnection {
|
||||
private constructor(
|
||||
cosmWasmClient: CosmWasmClient,
|
||||
chainId: ChainId,
|
||||
addressPrefix: CosmosAddressBech32Prefix,
|
||||
addressPrefix: string,
|
||||
tokens: TokenConfiguration,
|
||||
) {
|
||||
this.cosmWasmClient = cosmWasmClient;
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
import { CosmosAddressBech32Prefix } from "@cosmwasm/sdk";
|
||||
import { ChainConnector, ChainId } from "@iov/bcp";
|
||||
|
||||
import { CosmWasmCodec } from "./cosmwasmcodec";
|
||||
@ -9,7 +8,7 @@ import { CosmWasmConnection, TokenConfiguration } from "./cosmwasmconnection";
|
||||
*/
|
||||
export function createCosmWasmConnector(
|
||||
url: string,
|
||||
addressPrefix: CosmosAddressBech32Prefix,
|
||||
addressPrefix: string,
|
||||
tokenConfig: TokenConfiguration,
|
||||
expectedChainId?: ChainId,
|
||||
): ChainConnector<CosmWasmConnection> {
|
||||
|
||||
3
packages/bcp/types/address.d.ts
vendored
3
packages/bcp/types/address.d.ts
vendored
@ -1,4 +1,3 @@
|
||||
import { CosmosAddressBech32Prefix } from "@cosmwasm/sdk";
|
||||
import { Address, PubkeyBundle } from "@iov/bcp";
|
||||
export declare function decodeCosmosPubkey(encodedPubkey: string): PubkeyBundle;
|
||||
export declare function pubkeyToAddress(pubkey: PubkeyBundle, prefix: CosmosAddressBech32Prefix): Address;
|
||||
export declare function pubkeyToAddress(pubkey: PubkeyBundle, prefix: string): Address;
|
||||
|
||||
7
packages/bcp/types/cosmwasmcodec.d.ts
vendored
7
packages/bcp/types/cosmwasmcodec.d.ts
vendored
@ -1,4 +1,3 @@
|
||||
import { CosmosAddressBech32Prefix } from "@cosmwasm/sdk";
|
||||
import {
|
||||
Address,
|
||||
ChainId,
|
||||
@ -16,11 +15,7 @@ export declare class CosmWasmCodec implements TxCodec {
|
||||
private readonly addressPrefix;
|
||||
private readonly bankTokens;
|
||||
private readonly erc20Tokens;
|
||||
constructor(
|
||||
addressPrefix: CosmosAddressBech32Prefix,
|
||||
bankTokens: BankTokens,
|
||||
erc20Tokens?: readonly Erc20Token[],
|
||||
);
|
||||
constructor(addressPrefix: string, bankTokens: BankTokens, erc20Tokens?: readonly Erc20Token[]);
|
||||
bytesToSign(unsigned: UnsignedTransaction, nonce: Nonce): SigningJob;
|
||||
bytesToPost(signed: SignedTransaction): PostableBytes;
|
||||
identifier(_signed: SignedTransaction): TransactionId;
|
||||
|
||||
3
packages/bcp/types/cosmwasmconnection.d.ts
vendored
3
packages/bcp/types/cosmwasmconnection.d.ts
vendored
@ -1,4 +1,3 @@
|
||||
import { CosmosAddressBech32Prefix } from "@cosmwasm/sdk";
|
||||
import {
|
||||
Account,
|
||||
AccountQuery,
|
||||
@ -41,7 +40,7 @@ export interface TokenConfiguration {
|
||||
export declare class CosmWasmConnection implements BlockchainConnection {
|
||||
static establish(
|
||||
url: string,
|
||||
addressPrefix: CosmosAddressBech32Prefix,
|
||||
addressPrefix: string,
|
||||
tokens: TokenConfiguration,
|
||||
): Promise<CosmWasmConnection>;
|
||||
private static initialize;
|
||||
|
||||
3
packages/bcp/types/cosmwasmconnector.d.ts
vendored
3
packages/bcp/types/cosmwasmconnector.d.ts
vendored
@ -1,4 +1,3 @@
|
||||
import { CosmosAddressBech32Prefix } from "@cosmwasm/sdk";
|
||||
import { ChainConnector, ChainId } from "@iov/bcp";
|
||||
import { CosmWasmConnection, TokenConfiguration } from "./cosmwasmconnection";
|
||||
/**
|
||||
@ -6,7 +5,7 @@ import { CosmWasmConnection, TokenConfiguration } from "./cosmwasmconnection";
|
||||
*/
|
||||
export declare function createCosmWasmConnector(
|
||||
url: string,
|
||||
addressPrefix: CosmosAddressBech32Prefix,
|
||||
addressPrefix: string,
|
||||
tokenConfig: TokenConfiguration,
|
||||
expectedChainId?: ChainId,
|
||||
): ChainConnector<CosmWasmConnection>;
|
||||
|
||||
@ -127,7 +127,7 @@ smartQuery(client, foo, { balance: { address: rcpt } })
|
||||
const mnemonic = Bip39.encode(Random.getBytes(16)).toString();
|
||||
const pen = await Secp256k1Pen.fromMnemonic(mnemonic);
|
||||
const pubkey = encodeSecp256k1Pubkey(pen.pubkey);
|
||||
const address = encodeAddress(pubkey, "cosmos");
|
||||
const address = pubkeyToAddress(pubkey, "cosmos");
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
const mnemonic = Bip39.encode(Random.getBytes(16)).toString();
|
||||
const pen = await Secp256k1Pen.fromMnemonic(mnemonic);
|
||||
const pubkey = encodeSecp256k1Pubkey(pen.pubkey);
|
||||
const address = encodeAddress(pubkey, "cosmos");
|
||||
const address = pubkeyToAddress(pubkey, "cosmos");
|
||||
|
||||
console.info("mnemonic:", mnemonic);
|
||||
console.info("pubkey:", pubkey);
|
||||
|
||||
@ -28,7 +28,7 @@ const networkId = "testing";
|
||||
// helper functions
|
||||
const instantiateContract = async (initClient: RestClient, initPen: Secp256k1Pen, codeId: number, msg: object, transferAmount?: types.Coin[]): Promise<string> => {
|
||||
const memo = "Create an ERC20 instance";
|
||||
const sender = encodeAddress({ "type": types.pubkeyType.secp256k1, "value": toBase64(initPen.pubkey)}, "cosmos");
|
||||
const sender = pubkeyToAddress({ "type": types.pubkeyType.secp256k1, "value": toBase64(initPen.pubkey)}, "cosmos");
|
||||
const instantiateContractMsg = {
|
||||
type: "wasm/instantiate",
|
||||
value: {
|
||||
@ -59,7 +59,7 @@ const instantiateContract = async (initClient: RestClient, initPen: Secp256k1Pen
|
||||
// helper functions
|
||||
const executeContract = async (execClient: RestClient, execPen: Secp256k1Pen, contractAddr: string, msg: object, transferAmount?: types.Coin[]): Promise<readonly logs.Log[]> => {
|
||||
const memo = "Create an ERC20 instance";
|
||||
const sender = encodeAddress({ "type": types.pubkeyType.secp256k1, "value": toBase64(execPen.pubkey)}, "cosmos");
|
||||
const sender = pubkeyToAddress({ "type": types.pubkeyType.secp256k1, "value": toBase64(execPen.pubkey)}, "cosmos");
|
||||
const instantiateContractMsg = {
|
||||
type: "wasm/execute",
|
||||
value: {
|
||||
@ -97,5 +97,5 @@ const randomAddress = async (): Promise<string> => {
|
||||
const mnemonic = Bip39.encode(Random.getBytes(16)).toString();
|
||||
const randomPen = await Secp256k1Pen.fromMnemonic(mnemonic);
|
||||
const pubkey = encodeSecp256k1Pubkey(randomPen.pubkey);
|
||||
return encodeAddress(pubkey, "cosmos");
|
||||
return pubkeyToAddress(pubkey, "cosmos");
|
||||
}
|
||||
|
||||
@ -41,12 +41,12 @@ export function main(originalArgs: readonly string[]): void {
|
||||
[
|
||||
"@cosmwasm/sdk",
|
||||
[
|
||||
"encodeAddress",
|
||||
"encodeSecp256k1Pubkey",
|
||||
"encodeSecp256k1Signature",
|
||||
"makeSignBytes",
|
||||
"marshalTx",
|
||||
"Pen",
|
||||
"pubkeyToAddress",
|
||||
"RestClient",
|
||||
"Secp256k1Pen",
|
||||
"types",
|
||||
@ -134,7 +134,7 @@ export function main(originalArgs: readonly string[]): void {
|
||||
const mnemonic = Bip39.encode(Random.getBytes(16)).toString();
|
||||
const pen = await Secp256k1Pen.fromMnemonic(mnemonic);
|
||||
const pubkey = encodeSecp256k1Pubkey(pen.pubkey);
|
||||
const address = encodeAddress(pubkey, "cosmos");
|
||||
const address = pubkeyToAddress(pubkey, "cosmos");
|
||||
const data = Encoding.toAscii("foo bar");
|
||||
const signature = await pen.sign(data);
|
||||
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
import { CosmWasmCodec, CosmWasmConnection, TokenConfiguration } from "@cosmwasm/bcp";
|
||||
import { CosmosAddressBech32Prefix } from "@cosmwasm/sdk";
|
||||
import { Address, ChainId, Identity, TokenTicker } from "@iov/bcp";
|
||||
import { Random } from "@iov/crypto";
|
||||
import { Bech32 } from "@iov/encoding";
|
||||
@ -40,12 +39,12 @@ const defaultConfig: TokenConfiguration = {
|
||||
},
|
||||
],
|
||||
};
|
||||
const defaultPrefix = "cosmos" as CosmosAddressBech32Prefix;
|
||||
const defaultAddressPrefix = "cosmos";
|
||||
const defaultChainId = "cosmos:testing" as ChainId;
|
||||
const codec = new CosmWasmCodec(defaultPrefix, defaultConfig.bankTokens, defaultConfig.erc20Tokens);
|
||||
const codec = new CosmWasmCodec(defaultAddressPrefix, defaultConfig.bankTokens, defaultConfig.erc20Tokens);
|
||||
|
||||
function makeRandomAddress(): Address {
|
||||
return Bech32.encode(defaultPrefix, Random.getBytes(20)) as Address;
|
||||
return Bech32.encode(defaultAddressPrefix, Random.getBytes(20)) as Address;
|
||||
}
|
||||
|
||||
const faucetMnemonic =
|
||||
@ -66,7 +65,7 @@ describe("Faucet", () => {
|
||||
describe("constructor", () => {
|
||||
it("can be constructed", async () => {
|
||||
pendingWithoutWasmd();
|
||||
const connection = await CosmWasmConnection.establish(httpUrl, defaultPrefix, defaultConfig);
|
||||
const connection = await CosmWasmConnection.establish(httpUrl, defaultAddressPrefix, defaultConfig);
|
||||
const { profile } = await makeProfile();
|
||||
const faucet = new Faucet(defaultConfig, connection, codec, profile);
|
||||
expect(faucet).toBeTruthy();
|
||||
@ -77,7 +76,7 @@ describe("Faucet", () => {
|
||||
describe("send", () => {
|
||||
it("can send bank token", async () => {
|
||||
pendingWithoutWasmd();
|
||||
const connection = await CosmWasmConnection.establish(httpUrl, defaultPrefix, defaultConfig);
|
||||
const connection = await CosmWasmConnection.establish(httpUrl, defaultAddressPrefix, defaultConfig);
|
||||
const { profile, holder } = await makeProfile();
|
||||
const faucet = new Faucet(defaultConfig, connection, codec, profile);
|
||||
const recipient = makeRandomAddress();
|
||||
@ -104,7 +103,7 @@ describe("Faucet", () => {
|
||||
|
||||
it("can send ERC20 token", async () => {
|
||||
pendingWithoutWasmd();
|
||||
const connection = await CosmWasmConnection.establish(httpUrl, defaultPrefix, defaultConfig);
|
||||
const connection = await CosmWasmConnection.establish(httpUrl, defaultAddressPrefix, defaultConfig);
|
||||
const { profile, holder } = await makeProfile();
|
||||
const faucet = new Faucet(defaultConfig, connection, codec, profile);
|
||||
const recipient = makeRandomAddress();
|
||||
@ -133,7 +132,7 @@ describe("Faucet", () => {
|
||||
describe("refill", () => {
|
||||
it("works", async () => {
|
||||
pendingWithoutWasmd();
|
||||
const connection = await CosmWasmConnection.establish(httpUrl, defaultPrefix, defaultConfig);
|
||||
const connection = await CosmWasmConnection.establish(httpUrl, defaultAddressPrefix, defaultConfig);
|
||||
const { profile, distributors } = await makeProfile(1);
|
||||
const faucet = new Faucet(defaultConfig, connection, codec, profile);
|
||||
await faucet.refill();
|
||||
@ -163,7 +162,7 @@ describe("Faucet", () => {
|
||||
describe("credit", () => {
|
||||
it("works for fee token", async () => {
|
||||
pendingWithoutWasmd();
|
||||
const connection = await CosmWasmConnection.establish(httpUrl, defaultPrefix, defaultConfig);
|
||||
const connection = await CosmWasmConnection.establish(httpUrl, defaultAddressPrefix, defaultConfig);
|
||||
const { profile } = await makeProfile(1);
|
||||
const faucet = new Faucet(defaultConfig, connection, codec, profile);
|
||||
const recipient = makeRandomAddress();
|
||||
@ -182,7 +181,7 @@ describe("Faucet", () => {
|
||||
|
||||
it("works for stake token", async () => {
|
||||
pendingWithoutWasmd();
|
||||
const connection = await CosmWasmConnection.establish(httpUrl, defaultPrefix, defaultConfig);
|
||||
const connection = await CosmWasmConnection.establish(httpUrl, defaultAddressPrefix, defaultConfig);
|
||||
const { profile } = await makeProfile(1);
|
||||
const faucet = new Faucet(defaultConfig, connection, codec, profile);
|
||||
const recipient = makeRandomAddress();
|
||||
@ -203,7 +202,7 @@ describe("Faucet", () => {
|
||||
describe("loadTokenTickers", () => {
|
||||
it("works", async () => {
|
||||
pendingWithoutWasmd();
|
||||
const connection = await CosmWasmConnection.establish(httpUrl, defaultPrefix, defaultConfig);
|
||||
const connection = await CosmWasmConnection.establish(httpUrl, defaultAddressPrefix, defaultConfig);
|
||||
const { profile } = await makeProfile();
|
||||
const faucet = new Faucet(defaultConfig, connection, codec, profile);
|
||||
const tickers = await faucet.loadTokenTickers();
|
||||
@ -215,7 +214,7 @@ describe("Faucet", () => {
|
||||
describe("loadAccounts", () => {
|
||||
it("works", async () => {
|
||||
pendingWithoutWasmd();
|
||||
const connection = await CosmWasmConnection.establish(httpUrl, defaultPrefix, defaultConfig);
|
||||
const connection = await CosmWasmConnection.establish(httpUrl, defaultAddressPrefix, defaultConfig);
|
||||
const { profile, holder } = await makeProfile();
|
||||
const faucet = new Faucet(defaultConfig, connection, codec, profile);
|
||||
const accounts = await faucet.loadAccounts();
|
||||
|
||||
@ -1,35 +1,18 @@
|
||||
import { Encoding } from "@iov/encoding";
|
||||
|
||||
import { encodeAddress, isValidAddress } from "./address";
|
||||
import { pubkeyToAddress } from "./address";
|
||||
|
||||
const { toBase64, fromHex } = Encoding;
|
||||
|
||||
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("encodeAddress", () => {
|
||||
describe("pubkeyToAddress", () => {
|
||||
it("works for Secp256k1 compressed", () => {
|
||||
const prefix = "cosmos";
|
||||
const pubkey = {
|
||||
type: "tendermint/PubKeySecp256k1",
|
||||
value: "AtQaCqFnshaZQp6rIkvAPyzThvCvXSDO+9AzbxVErqJP",
|
||||
};
|
||||
expect(encodeAddress(pubkey, prefix)).toEqual("cosmos1h806c7khnvmjlywdrkdgk2vrayy2mmvf9rxk2r");
|
||||
expect(pubkeyToAddress(pubkey, prefix)).toEqual("cosmos1h806c7khnvmjlywdrkdgk2vrayy2mmvf9rxk2r");
|
||||
});
|
||||
|
||||
it("works for Ed25519", () => {
|
||||
@ -38,7 +21,7 @@ describe("address", () => {
|
||||
type: "tendermint/PubKeyEd25519",
|
||||
value: toBase64(fromHex("12ee6f581fe55673a1e9e1382a0829e32075a0aa4763c968bc526e1852e78c95")),
|
||||
};
|
||||
expect(encodeAddress(pubkey, prefix)).toEqual("cosmos1pfq05em6sfkls66ut4m2257p7qwlk448h8mysz");
|
||||
expect(pubkeyToAddress(pubkey, prefix)).toEqual("cosmos1pfq05em6sfkls66ut4m2257p7qwlk448h8mysz");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -5,28 +5,9 @@ import { PubKey, pubkeyType } from "./types";
|
||||
|
||||
const { fromBase64 } = Encoding;
|
||||
|
||||
// TODO: make this much more configurable
|
||||
export type CosmosAddressBech32Prefix = "cosmos" | "cosmosvalcons" | "cosmosvaloper";
|
||||
|
||||
function isCosmosAddressBech32Prefix(prefix: string): prefix is CosmosAddressBech32Prefix {
|
||||
return ["cosmos", "cosmosvalcons", "cosmosvaloper"].includes(prefix);
|
||||
}
|
||||
|
||||
export function isValidAddress(address: string): boolean {
|
||||
try {
|
||||
const { prefix, data } = Bech32.decode(address);
|
||||
if (!isCosmosAddressBech32Prefix(prefix)) {
|
||||
return false;
|
||||
}
|
||||
return data.length === 20;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// See https://github.com/tendermint/tendermint/blob/f2ada0a604b4c0763bda2f64fac53d506d3beca7/docs/spec/blockchain/encoding.md#public-key-cryptography
|
||||
// This assumes we already have a cosmos-compressed pubkey
|
||||
export function encodeAddress(pubkey: PubKey, prefix: string): string {
|
||||
export function pubkeyToAddress(pubkey: PubKey, prefix: string): string {
|
||||
const pubkeyBytes = fromBase64(pubkey.value);
|
||||
switch (pubkey.type) {
|
||||
case pubkeyType.secp256k1: {
|
||||
|
||||
@ -2,7 +2,7 @@ import * as logs from "./logs";
|
||||
import * as types from "./types";
|
||||
export { logs, types };
|
||||
|
||||
export { CosmosAddressBech32Prefix, encodeAddress, isValidAddress } from "./address";
|
||||
export { pubkeyToAddress } from "./address";
|
||||
export { unmarshalTx } from "./decoding";
|
||||
export { makeSignBytes, marshalTx } from "./encoding";
|
||||
export { BroadcastMode, RestClient, TxsResponse } from "./restclient";
|
||||
|
||||
4
packages/sdk/types/address.d.ts
vendored
4
packages/sdk/types/address.d.ts
vendored
@ -1,4 +1,2 @@
|
||||
import { PubKey } from "./types";
|
||||
export declare type CosmosAddressBech32Prefix = "cosmos" | "cosmosvalcons" | "cosmosvaloper";
|
||||
export declare function isValidAddress(address: string): boolean;
|
||||
export declare function encodeAddress(pubkey: PubKey, prefix: string): string;
|
||||
export declare function pubkeyToAddress(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 { CosmosAddressBech32Prefix, encodeAddress, isValidAddress } from "./address";
|
||||
export { pubkeyToAddress } from "./address";
|
||||
export { unmarshalTx } from "./decoding";
|
||||
export { makeSignBytes, marshalTx } from "./encoding";
|
||||
export { BroadcastMode, RestClient, TxsResponse } from "./restclient";
|
||||
|
||||
Loading…
Reference in New Issue
Block a user