mirror of
https://github.com/cosmos/cosmjs.git
synced 2025-03-11 14:09:15 +00:00
commit
19c9c27e76
@ -43,7 +43,6 @@
|
||||
"@iov/crypto": "^2.0.0-alpha.7",
|
||||
"@iov/encoding": "^2.0.0-alpha.7",
|
||||
"@iov/stream": "^2.0.0-alpha.7",
|
||||
"@tendermint/amino-js": "^0.7.0-alpha.1",
|
||||
"fast-deep-equal": "^3.1.1",
|
||||
"readonly-date": "^1.0.0",
|
||||
"xstream": "^11.11.0"
|
||||
|
@ -33,8 +33,8 @@ describe("address", () => {
|
||||
expect(
|
||||
decodeCosmosPubkey("cosmospub1addwnpepqd8sgxq7aw348ydctp3n5ajufgxp395hksxjzc6565yfp56scupfqhlgyg5"),
|
||||
).toEqual({
|
||||
prefix: "cosmospub",
|
||||
data: fromBase64("A08EGB7ro1ORuFhjOnZcSgwYlpe0DSFjVNUIkNNQxwKQ"),
|
||||
algo: Algorithm.Secp256k1,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Address, Algorithm, PubkeyBundle } from "@iov/bcp";
|
||||
import { Address, Algorithm, PubkeyBundle, PubkeyBytes } from "@iov/bcp";
|
||||
import { Ripemd160, Secp256k1, Sha256 } from "@iov/crypto";
|
||||
import { Bech32, Encoding } from "@iov/encoding";
|
||||
import equal from "fast-deep-equal";
|
||||
@ -8,7 +8,10 @@ export type CosmosPubkeyBech32Prefix = "cosmospub" | "cosmosvalconspub" | "cosmo
|
||||
export type CosmosBech32Prefix = CosmosAddressBech32Prefix | CosmosPubkeyBech32Prefix;
|
||||
|
||||
// As discussed in https://github.com/binance-chain/javascript-sdk/issues/163
|
||||
const pubkeyAminoPrefix = Encoding.fromHex("eb5ae98721");
|
||||
// Prefixes listed here: https://github.com/tendermint/tendermint/blob/d419fffe18531317c28c29a292ad7d253f6cafdf/docs/spec/blockchain/encoding.md#public-key-cryptography
|
||||
const pubkeyAminoPrefixSecp256k1 = Encoding.fromHex("eb5ae98721");
|
||||
const pubkeyAminoPrefixEd25519 = Encoding.fromHex("1624de64");
|
||||
const pubkeyAminoPrefixLength = pubkeyAminoPrefixSecp256k1.length;
|
||||
|
||||
function isCosmosAddressBech32Prefix(prefix: string): prefix is CosmosAddressBech32Prefix {
|
||||
return ["cosmos", "cosmosvalcons", "cosmosvaloper"].includes(prefix);
|
||||
@ -33,22 +36,27 @@ export function decodeCosmosAddress(
|
||||
|
||||
export function decodeCosmosPubkey(
|
||||
encodedPubkey: string,
|
||||
): { readonly prefix: CosmosPubkeyBech32Prefix; readonly data: Uint8Array } {
|
||||
): { readonly algo: Algorithm; readonly data: PubkeyBytes } {
|
||||
const { prefix, data } = Bech32.decode(encodedPubkey);
|
||||
if (!isCosmosPubkeyBech32Prefix(prefix)) {
|
||||
throw new Error(`Invalid bech32 prefix. Must be one of cosmos, cosmosvalcons, or cosmosvaloper.`);
|
||||
}
|
||||
|
||||
if (!equal(data.slice(0, pubkeyAminoPrefix.length), pubkeyAminoPrefix)) {
|
||||
throw new Error("Pubkey does not have the expected amino prefix " + Encoding.toHex(pubkeyAminoPrefix));
|
||||
const aminoPrefix = data.slice(0, pubkeyAminoPrefixLength);
|
||||
const rest = data.slice(pubkeyAminoPrefixLength);
|
||||
if (equal(aminoPrefix, pubkeyAminoPrefixSecp256k1)) {
|
||||
if (rest.length !== 33) {
|
||||
throw new Error("Invalid rest data length. Expected 33 bytes (compressed secp256k1 pubkey).");
|
||||
}
|
||||
return { algo: Algorithm.Secp256k1, data: rest as PubkeyBytes };
|
||||
} else if (equal(aminoPrefix, pubkeyAminoPrefixEd25519)) {
|
||||
if (rest.length !== 32) {
|
||||
throw new Error("Invalid rest data length. Expected 32 bytes (ed25519 pubkey).");
|
||||
}
|
||||
return { algo: Algorithm.Ed25519, data: rest as PubkeyBytes };
|
||||
} else {
|
||||
throw new Error("Unsupported Pubkey type. Amino prefix: " + Encoding.toHex(aminoPrefix));
|
||||
}
|
||||
|
||||
const rest = data.slice(pubkeyAminoPrefix.length);
|
||||
if (rest.length !== 33) {
|
||||
throw new Error("Invalid rest data length. Expected 33 bytes (compressed secp256k1 pubkey).");
|
||||
}
|
||||
|
||||
return { prefix: prefix, data: rest };
|
||||
}
|
||||
|
||||
export function isValidAddress(address: string): boolean {
|
||||
|
@ -2,7 +2,7 @@ import { PostableBytes, PrehashType } from "@iov/bcp";
|
||||
import { Encoding } from "@iov/encoding";
|
||||
|
||||
import { cosmWasmCodec } from "./cosmwasmcodec";
|
||||
import { chainId, nonce, sendTxJson, signedTxBin, signedTxJson, txId } from "./testdata.spec";
|
||||
import { chainId, nonce, sendTxJson, signedTxBin, signedTxEncodedJson, signedTxJson } from "./testdata.spec";
|
||||
|
||||
const { toUtf8 } = Encoding;
|
||||
|
||||
@ -21,7 +21,7 @@ describe("cosmWasmCodec", () => {
|
||||
|
||||
it("properly encodes transactions", () => {
|
||||
const encoded = cosmWasmCodec.bytesToPost(signedTxJson);
|
||||
expect(encoded).toEqual(signedTxBin);
|
||||
expect(encoded).toEqual(signedTxEncodedJson);
|
||||
});
|
||||
|
||||
it("throws when trying to decode a transaction without a nonce", () => {
|
||||
@ -31,16 +31,10 @@ describe("cosmWasmCodec", () => {
|
||||
});
|
||||
|
||||
it("properly decodes transactions", () => {
|
||||
const decoded = cosmWasmCodec.parseBytes(signedTxBin as PostableBytes, chainId, nonce);
|
||||
const decoded = cosmWasmCodec.parseBytes(signedTxEncodedJson as PostableBytes, chainId, nonce);
|
||||
expect(decoded).toEqual(signedTxJson);
|
||||
});
|
||||
|
||||
it("generates transaction id", () => {
|
||||
const id = cosmWasmCodec.identifier(signedTxJson);
|
||||
expect(id).toMatch(/^[0-9A-F]{64}$/);
|
||||
expect(id).toEqual(txId);
|
||||
});
|
||||
|
||||
it("round trip works", () => {
|
||||
const encoded = cosmWasmCodec.bytesToPost(signedTxJson);
|
||||
const decoded = cosmWasmCodec.parseBytes(encoded, chainId, nonce);
|
||||
|
@ -1,4 +1,5 @@
|
||||
/* eslint-disable @typescript-eslint/camelcase */
|
||||
import { marshalTx, unmarshalTx } from "@cosmwasm/sdk";
|
||||
import {
|
||||
Address,
|
||||
ChainId,
|
||||
@ -13,9 +14,7 @@ import {
|
||||
TxCodec,
|
||||
UnsignedTransaction,
|
||||
} from "@iov/bcp";
|
||||
import { Sha256 } from "@iov/crypto";
|
||||
import { Encoding } from "@iov/encoding";
|
||||
import { marshalTx, unmarshalTx } from "@tendermint/amino-js";
|
||||
|
||||
import { CosmosBech32Prefix, isValidAddress, pubkeyToAddress } from "./address";
|
||||
import { Caip5 } from "./caip5";
|
||||
@ -23,7 +22,7 @@ import { parseTx } from "./decode";
|
||||
import { buildSignedTx, buildUnsignedTx } from "./encode";
|
||||
import { nonceToAccountNumber, nonceToSequence, TokenInfos } from "./types";
|
||||
|
||||
const { toHex, toUtf8 } = Encoding;
|
||||
const { toUtf8 } = Encoding;
|
||||
|
||||
function sortJson(json: any): any {
|
||||
if (typeof json !== "object" || json === null) {
|
||||
@ -72,16 +71,20 @@ export class CosmWasmCodec implements TxCodec {
|
||||
};
|
||||
}
|
||||
|
||||
// PostableBytes are JSON-encoded StdTx
|
||||
public bytesToPost(signed: SignedTransaction): PostableBytes {
|
||||
// TODO: change this as well (return StdTx, not AminoTx)?
|
||||
const built = buildSignedTx(signed, this.tokens);
|
||||
const bytes = marshalTx(built, true);
|
||||
return bytes as PostableBytes;
|
||||
return marshalTx(built.value) as PostableBytes;
|
||||
}
|
||||
|
||||
public identifier(signed: SignedTransaction): TransactionId {
|
||||
const bytes = this.bytesToPost(signed);
|
||||
const hash = new Sha256(bytes).digest();
|
||||
return toHex(hash).toUpperCase() as TransactionId;
|
||||
// TODO: this needs some marshalling going on...
|
||||
// Do we need to support this??
|
||||
public identifier(_signed: SignedTransaction): TransactionId {
|
||||
throw new Error("Not yet implemented, requires amino encoding- talk to Ethan");
|
||||
// const bytes = this.bytesToPost(signed);
|
||||
// const hash = new Sha256(bytes).digest();
|
||||
// return toHex(hash).toUpperCase() as TransactionId;
|
||||
}
|
||||
|
||||
public parseBytes(bytes: PostableBytes, chainId: ChainId, nonce?: Nonce): SignedTransaction {
|
||||
|
@ -17,6 +17,7 @@ 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";
|
||||
import { nonceToSequence } from "./types";
|
||||
|
||||
const { fromBase64, toHex } = Encoding;
|
||||
@ -133,6 +134,17 @@ describe("CosmWasmConnection", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("identifier", () => {
|
||||
it("calculates tx hash from PostableBytes", async () => {
|
||||
pendingWithoutCosmos();
|
||||
const connection = await CosmWasmConnection.establish(httpUrl, defaultPrefix, defaultTokens);
|
||||
const postable = cosmWasmCodec.bytesToPost(signedTxJson);
|
||||
const id = await connection.identifier(postable);
|
||||
expect(id).toMatch(/^[0-9A-F]{64}$/);
|
||||
expect(id).toEqual(txId);
|
||||
});
|
||||
});
|
||||
|
||||
describe("getAccount", () => {
|
||||
it("gets an empty account by address", async () => {
|
||||
pendingWithoutCosmos();
|
||||
|
@ -1,10 +1,9 @@
|
||||
/* eslint-disable @typescript-eslint/camelcase */
|
||||
import { RestClient, TxsResponse } from "@cosmwasm/sdk";
|
||||
import { RestClient, TxsResponse, unmarshalTx } from "@cosmwasm/sdk";
|
||||
import {
|
||||
Account,
|
||||
AccountQuery,
|
||||
AddressQuery,
|
||||
Algorithm,
|
||||
BlockchainConnection,
|
||||
BlockHeader,
|
||||
BlockId,
|
||||
@ -20,7 +19,6 @@ import {
|
||||
Nonce,
|
||||
PostableBytes,
|
||||
PostTxResponse,
|
||||
PubkeyBytes,
|
||||
PubkeyQuery,
|
||||
Token,
|
||||
TokenTicker,
|
||||
@ -29,7 +27,8 @@ import {
|
||||
TransactionState,
|
||||
UnsignedTransaction,
|
||||
} from "@iov/bcp";
|
||||
import { Uint53 } from "@iov/encoding";
|
||||
import { Sha256 } from "@iov/crypto";
|
||||
import { Encoding, Uint53 } from "@iov/encoding";
|
||||
import { DefaultValueProducer, ValueAndUpdates } from "@iov/stream";
|
||||
import equal from "fast-deep-equal";
|
||||
import { ReadonlyDate } from "readonly-date";
|
||||
@ -40,6 +39,8 @@ import { Caip5 } from "./caip5";
|
||||
import { decodeAmount, parseTxsResponse } from "./decode";
|
||||
import { accountToNonce, TokenInfo } from "./types";
|
||||
|
||||
const { toHex } = Encoding;
|
||||
|
||||
interface ChainData {
|
||||
readonly chainId: ChainId;
|
||||
}
|
||||
@ -68,7 +69,7 @@ function buildQueryString({
|
||||
return components.filter(Boolean).join("&");
|
||||
}
|
||||
|
||||
export type TokenConfiguration = readonly (TokenInfo & { readonly name: string })[];
|
||||
export type TokenConfiguration = ReadonlyArray<TokenInfo & { readonly name: string }>;
|
||||
|
||||
export class CosmWasmConnection implements BlockchainConnection {
|
||||
// we must know prefix and tokens a priori to understand the chain
|
||||
@ -140,6 +141,13 @@ export class CosmWasmConnection implements BlockchainConnection {
|
||||
return this.supportedTokens;
|
||||
}
|
||||
|
||||
public async identifier(signed: PostableBytes): Promise<TransactionId> {
|
||||
const tx = unmarshalTx(signed);
|
||||
const bytes = await this.restClient.encodeTx(tx);
|
||||
const hash = new Sha256(bytes).digest();
|
||||
return toHex(hash).toUpperCase() as TransactionId;
|
||||
}
|
||||
|
||||
public async getAccount(query: AccountQuery): Promise<Account | undefined> {
|
||||
const address = isPubkeyQuery(query) ? pubkeyToAddress(query.pubkey, this.prefix) : query.address;
|
||||
const { result } = await this.restClient.authAccounts(address);
|
||||
@ -151,13 +159,7 @@ export class CosmWasmConnection implements BlockchainConnection {
|
||||
this.tokenInfo.find(token => token.denom === denom),
|
||||
);
|
||||
|
||||
const pubkey = !account.public_key
|
||||
? undefined
|
||||
: {
|
||||
algo: Algorithm.Secp256k1,
|
||||
// amino-js has wrong (outdated) types
|
||||
data: decodeCosmosPubkey(account.public_key as any).data as PubkeyBytes,
|
||||
};
|
||||
const pubkey = !account.public_key ? undefined : decodeCosmosPubkey(account.public_key);
|
||||
return {
|
||||
address: address,
|
||||
balance: supportedCoins.map(coin => decodeAmount(this.tokenInfo, coin)),
|
||||
|
@ -1,7 +1,7 @@
|
||||
/* eslint-disable @typescript-eslint/camelcase */
|
||||
import { types } from "@cosmwasm/sdk";
|
||||
import { Address, Algorithm, TokenTicker } from "@iov/bcp";
|
||||
import { Encoding } from "@iov/encoding";
|
||||
import amino from "@tendermint/amino-js";
|
||||
|
||||
import {
|
||||
decodeAmount,
|
||||
@ -113,7 +113,7 @@ describe("decode", () => {
|
||||
|
||||
describe("decodeAmount", () => {
|
||||
it("works", () => {
|
||||
const amount: amino.Coin = {
|
||||
const amount: types.Coin = {
|
||||
denom: "uatom",
|
||||
amount: "11657995",
|
||||
};
|
||||
@ -123,7 +123,7 @@ describe("decode", () => {
|
||||
|
||||
describe("parseMsg", () => {
|
||||
it("works", () => {
|
||||
const msg: amino.Msg = {
|
||||
const msg: types.Msg = {
|
||||
type: "cosmos-sdk/MsgSend",
|
||||
value: {
|
||||
from_address: "cosmos1h806c7khnvmjlywdrkdgk2vrayy2mmvf9rxk2r",
|
||||
@ -157,7 +157,7 @@ describe("decode", () => {
|
||||
|
||||
describe("parseTx", () => {
|
||||
it("works", () => {
|
||||
expect(parseTx(data.tx, chainId, nonce, defaultTokens)).toEqual(signedTxJson);
|
||||
expect(parseTx(data.tx.value, chainId, nonce, defaultTokens)).toEqual(signedTxJson);
|
||||
});
|
||||
});
|
||||
|
||||
@ -181,3 +181,179 @@ describe("decode", () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
/*
|
||||
|
||||
Some output from sample rest queries:
|
||||
|
||||
$ wasmcli tx send $(wasmcli keys show validator -a) $(wasmcli keys show fred -a) 98765stake -y
|
||||
{
|
||||
"height": "4",
|
||||
"txhash": "8A4613D62884EF8BB9BCCDDA3833D560701908BF17FE82A570EECCBACEF94A91",
|
||||
"raw_log": "[{\"msg_index\":0,\"log\":\"\",\"events\":[{\"type\":\"message\",\"attributes\":[{\"key\":\"action\",\"value\":\"send\"},{\"key\":\"sender\",\"value\":\"cosmos16qu479grzwanyzav6xvtzncgdjkwhqw7vy2pje\"},{\"key\":\"module\",\"value\":\"bank\"}]},{\"type\":\"transfer\",\"attributes\":[{\"key\":\"recipient\",\"value\":\"cosmos1ltkhnmdcqemmd2tkhnx7qx66tq7e0wykw2j85k\"},{\"key\":\"amount\",\"value\":\"98765stake\"}]}]}]",
|
||||
"logs": [
|
||||
{
|
||||
"msg_index": 0,
|
||||
"log": "",
|
||||
"events": [
|
||||
{
|
||||
"type": "message",
|
||||
"attributes": [
|
||||
{
|
||||
"key": "action",
|
||||
"value": "send"
|
||||
},
|
||||
{
|
||||
"key": "sender",
|
||||
"value": "cosmos16qu479grzwanyzav6xvtzncgdjkwhqw7vy2pje"
|
||||
},
|
||||
{
|
||||
"key": "module",
|
||||
"value": "bank"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "transfer",
|
||||
"attributes": [
|
||||
{
|
||||
"key": "recipient",
|
||||
"value": "cosmos1ltkhnmdcqemmd2tkhnx7qx66tq7e0wykw2j85k"
|
||||
},
|
||||
{
|
||||
"key": "amount",
|
||||
"value": "98765stake"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"gas_wanted": "200000",
|
||||
"gas_used": "53254"
|
||||
}
|
||||
|
||||
|
||||
$ wasmcli query tx 8A4613D62884EF8BB9BCCDDA3833D560701908BF17FE82A570EECCBACEF94A91
|
||||
{
|
||||
"height": "4",
|
||||
"txhash": "8A4613D62884EF8BB9BCCDDA3833D560701908BF17FE82A570EECCBACEF94A91",
|
||||
"raw_log": "[{\"msg_index\":0,\"log\":\"\",\"events\":[{\"type\":\"message\",\"attributes\":[{\"key\":\"action\",\"value\":\"send\"},{\"key\":\"sender\",\"value\":\"cosmos16qu479grzwanyzav6xvtzncgdjkwhqw7vy2pje\"},{\"key\":\"module\",\"value\":\"bank\"}]},{\"type\":\"transfer\",\"attributes\":[{\"key\":\"recipient\",\"value\":\"cosmos1ltkhnmdcqemmd2tkhnx7qx66tq7e0wykw2j85k\"},{\"key\":\"amount\",\"value\":\"98765stake\"}]}]}]",
|
||||
"logs": [
|
||||
{
|
||||
"msg_index": 0,
|
||||
"log": "",
|
||||
"events": [
|
||||
{
|
||||
"type": "message",
|
||||
"attributes": [
|
||||
{
|
||||
"key": "action",
|
||||
"value": "send"
|
||||
},
|
||||
{
|
||||
"key": "sender",
|
||||
"value": "cosmos16qu479grzwanyzav6xvtzncgdjkwhqw7vy2pje"
|
||||
},
|
||||
{
|
||||
"key": "module",
|
||||
"value": "bank"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "transfer",
|
||||
"attributes": [
|
||||
{
|
||||
"key": "recipient",
|
||||
"value": "cosmos1ltkhnmdcqemmd2tkhnx7qx66tq7e0wykw2j85k"
|
||||
},
|
||||
{
|
||||
"key": "amount",
|
||||
"value": "98765stake"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"gas_wanted": "200000",
|
||||
"gas_used": "53254",
|
||||
"tx": {
|
||||
"type": "cosmos-sdk/StdTx",
|
||||
"value": {
|
||||
"msg": [
|
||||
{
|
||||
"type": "cosmos-sdk/MsgSend",
|
||||
"value": {
|
||||
"from_address": "cosmos16qu479grzwanyzav6xvtzncgdjkwhqw7vy2pje",
|
||||
"to_address": "cosmos1ltkhnmdcqemmd2tkhnx7qx66tq7e0wykw2j85k",
|
||||
"amount": [
|
||||
{
|
||||
"denom": "stake",
|
||||
"amount": "98765"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"fee": {
|
||||
"amount": [],
|
||||
"gas": "200000"
|
||||
},
|
||||
"signatures": [
|
||||
{
|
||||
"pub_key": {
|
||||
"type": "tendermint/PubKeySecp256k1",
|
||||
"value": "A11L8EitFnA6YsZ2QSnbMNmK+qI2kxyevDtSfhPqOwcp"
|
||||
},
|
||||
"signature": "qCeKoqZeaL0LThKrUXHLgu72jwTiF+DseSBjcKHtcONE0kIdybwYJpuYg3Jj71hmfync+daHNdqgJlPRma0pPA=="
|
||||
}
|
||||
],
|
||||
"memo": ""
|
||||
}
|
||||
},
|
||||
"timestamp": "2020-02-03T17:06:58Z"
|
||||
}
|
||||
|
||||
|
||||
$ wasmcli query account $(wasmcli keys show fred -a)
|
||||
{
|
||||
"type": "cosmos-sdk/Account",
|
||||
"value": {
|
||||
"address": "cosmos1ltkhnmdcqemmd2tkhnx7qx66tq7e0wykw2j85k",
|
||||
"coins": [
|
||||
{
|
||||
"denom": "stake",
|
||||
"amount": "98765"
|
||||
}
|
||||
],
|
||||
"public_key": "",
|
||||
"account_number": 7,
|
||||
"sequence": 0
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$ wasmcli query account $(wasmcli keys show validator -a)
|
||||
{
|
||||
"type": "cosmos-sdk/Account",
|
||||
"value": {
|
||||
"address": "cosmos16qu479grzwanyzav6xvtzncgdjkwhqw7vy2pje",
|
||||
"coins": [
|
||||
{
|
||||
"denom": "stake",
|
||||
"amount": "899901235"
|
||||
},
|
||||
{
|
||||
"denom": "validatortoken",
|
||||
"amount": "1000000000"
|
||||
}
|
||||
],
|
||||
"public_key": "cosmospub1addwnpepqdw5huzg45t8qwnzcemyz2wmxrvc474zx6f3e84u8df8uyl28vrjjnp9v4p",
|
||||
"account_number": 3,
|
||||
"sequence": 2
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { isAminoStdTx, TxsResponse } from "@cosmwasm/sdk";
|
||||
import { TxsResponse, types } from "@cosmwasm/sdk";
|
||||
import {
|
||||
Address,
|
||||
Algorithm,
|
||||
@ -18,13 +18,12 @@ import {
|
||||
UnsignedTransaction,
|
||||
} from "@iov/bcp";
|
||||
import { Decimal, Encoding } from "@iov/encoding";
|
||||
import amino from "@tendermint/amino-js";
|
||||
|
||||
import { TokenInfos } from "./types";
|
||||
|
||||
const { fromBase64 } = Encoding;
|
||||
|
||||
export function decodePubkey(pubkey: amino.PubKey): PubkeyBundle {
|
||||
export function decodePubkey(pubkey: types.PubKey): PubkeyBundle {
|
||||
switch (pubkey.type) {
|
||||
// https://github.com/tendermint/tendermint/blob/v0.33.0/crypto/secp256k1/secp256k1.go#L23
|
||||
case "tendermint/PubKeySecp256k1":
|
||||
@ -47,7 +46,7 @@ export function decodeSignature(signature: string): SignatureBytes {
|
||||
return fromBase64(signature) as SignatureBytes;
|
||||
}
|
||||
|
||||
export function decodeFullSignature(signature: amino.StdSignature, nonce: number): FullSignature {
|
||||
export function decodeFullSignature(signature: types.StdSignature, nonce: number): FullSignature {
|
||||
return {
|
||||
nonce: nonce as Nonce,
|
||||
pubkey: decodePubkey(signature.pub_key),
|
||||
@ -55,7 +54,7 @@ export function decodeFullSignature(signature: amino.StdSignature, nonce: number
|
||||
};
|
||||
}
|
||||
|
||||
export function coinToDecimal(tokens: TokenInfos, coin: amino.Coin): readonly [Decimal, string] {
|
||||
export function coinToDecimal(tokens: TokenInfos, coin: types.Coin): readonly [Decimal, string] {
|
||||
const match = tokens.find(({ denom }) => denom === coin.denom);
|
||||
if (!match) {
|
||||
throw Error(`unknown denom: ${coin.denom}`);
|
||||
@ -64,7 +63,7 @@ export function coinToDecimal(tokens: TokenInfos, coin: amino.Coin): readonly [D
|
||||
return [value, match.ticker];
|
||||
}
|
||||
|
||||
export function decodeAmount(tokens: TokenInfos, coin: amino.Coin): Amount {
|
||||
export function decodeAmount(tokens: TokenInfos, coin: types.Coin): Amount {
|
||||
const [value, ticker] = coinToDecimal(tokens, coin);
|
||||
return {
|
||||
quantity: value.atomics,
|
||||
@ -73,14 +72,14 @@ export function decodeAmount(tokens: TokenInfos, coin: amino.Coin): Amount {
|
||||
};
|
||||
}
|
||||
|
||||
export function parseMsg(msg: amino.Msg, chainId: ChainId, tokens: TokenInfos): SendTransaction {
|
||||
export function parseMsg(msg: types.Msg, chainId: ChainId, tokens: TokenInfos): SendTransaction {
|
||||
if (msg.type !== "cosmos-sdk/MsgSend") {
|
||||
throw new Error("Unknown message type in transaction");
|
||||
}
|
||||
if (!(msg.value as amino.MsgSend).from_address) {
|
||||
if (!(msg.value as types.MsgSend).from_address) {
|
||||
throw new Error("Only MsgSend is supported");
|
||||
}
|
||||
const msgValue = msg.value as amino.MsgSend;
|
||||
const msgValue = msg.value as types.MsgSend;
|
||||
if (msgValue.amount.length !== 1) {
|
||||
throw new Error("Only MsgSend with one amount is supported");
|
||||
}
|
||||
@ -93,7 +92,7 @@ export function parseMsg(msg: amino.Msg, chainId: ChainId, tokens: TokenInfos):
|
||||
};
|
||||
}
|
||||
|
||||
export function parseFee(fee: amino.StdFee, tokens: TokenInfos): Fee {
|
||||
export function parseFee(fee: types.StdFee, tokens: TokenInfos): Fee {
|
||||
if (fee.amount.length !== 1) {
|
||||
throw new Error("Only fee with one amount is supported");
|
||||
}
|
||||
@ -103,9 +102,13 @@ export function parseFee(fee: amino.StdFee, tokens: TokenInfos): Fee {
|
||||
};
|
||||
}
|
||||
|
||||
export function parseTx(tx: amino.Tx, chainId: ChainId, nonce: Nonce, tokens: TokenInfos): SignedTransaction {
|
||||
const txValue = tx.value;
|
||||
if (!isAminoStdTx(txValue)) {
|
||||
export function parseTx(
|
||||
txValue: types.StdTx,
|
||||
chainId: ChainId,
|
||||
nonce: Nonce,
|
||||
tokens: TokenInfos,
|
||||
): SignedTransaction {
|
||||
if (!types.isAminoStdTx(txValue)) {
|
||||
throw new Error("Only Amino StdTx is supported");
|
||||
}
|
||||
if (txValue.msg.length !== 1) {
|
||||
@ -138,7 +141,7 @@ export function parseTxsResponse(
|
||||
): ConfirmedAndSignedTransaction<UnsignedTransaction> {
|
||||
const height = parseInt(response.height, 10);
|
||||
return {
|
||||
...parseTx(response.tx, chainId, nonce, tokens),
|
||||
...parseTx(response.tx.value, chainId, nonce, tokens),
|
||||
height: height,
|
||||
confirmations: currentHeight - height + 1,
|
||||
transactionId: response.txhash as TransactionId,
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* eslint-disable @typescript-eslint/camelcase */
|
||||
import { AminoTx } from "@cosmwasm/sdk";
|
||||
import { types } from "@cosmwasm/sdk";
|
||||
import {
|
||||
Algorithm,
|
||||
Amount,
|
||||
@ -12,13 +12,12 @@ import {
|
||||
} from "@iov/bcp";
|
||||
import { Secp256k1 } from "@iov/crypto";
|
||||
import { Decimal, Encoding } from "@iov/encoding";
|
||||
import amino from "@tendermint/amino-js";
|
||||
|
||||
import { TokenInfos } from "./types";
|
||||
|
||||
const { toBase64 } = Encoding;
|
||||
|
||||
export function encodePubkey(pubkey: PubkeyBundle): amino.PubKey {
|
||||
export function encodePubkey(pubkey: PubkeyBundle): types.PubKey {
|
||||
switch (pubkey.algo) {
|
||||
case Algorithm.Secp256k1:
|
||||
return {
|
||||
@ -35,7 +34,7 @@ export function encodePubkey(pubkey: PubkeyBundle): amino.PubKey {
|
||||
}
|
||||
}
|
||||
|
||||
export function decimalToCoin(lookup: TokenInfos, value: Decimal, ticker: string): amino.Coin {
|
||||
export function decimalToCoin(lookup: TokenInfos, value: Decimal, ticker: string): types.Coin {
|
||||
const match = lookup.find(token => token.ticker === ticker);
|
||||
if (!match) {
|
||||
throw Error(`unknown ticker: ${ticker}`);
|
||||
@ -51,7 +50,7 @@ export function decimalToCoin(lookup: TokenInfos, value: Decimal, ticker: string
|
||||
};
|
||||
}
|
||||
|
||||
export function encodeAmount(amount: Amount, tokens: TokenInfos): amino.Coin {
|
||||
export function encodeAmount(amount: Amount, tokens: TokenInfos): types.Coin {
|
||||
return decimalToCoin(
|
||||
tokens,
|
||||
Decimal.fromAtomics(amount.quantity, amount.fractionalDigits),
|
||||
@ -59,7 +58,7 @@ export function encodeAmount(amount: Amount, tokens: TokenInfos): amino.Coin {
|
||||
);
|
||||
}
|
||||
|
||||
export function encodeFee(fee: Fee, tokens: TokenInfos): amino.StdFee {
|
||||
export function encodeFee(fee: Fee, tokens: TokenInfos): types.StdFee {
|
||||
if (fee.tokens === undefined) {
|
||||
throw new Error("Cannot encode fee without tokens");
|
||||
}
|
||||
@ -72,7 +71,7 @@ export function encodeFee(fee: Fee, tokens: TokenInfos): amino.StdFee {
|
||||
};
|
||||
}
|
||||
|
||||
export function encodeFullSignature(fullSignature: FullSignature): amino.StdSignature {
|
||||
export function encodeFullSignature(fullSignature: FullSignature): types.StdSignature {
|
||||
return {
|
||||
pub_key: {
|
||||
type: "tendermint/PubKeySecp256k1",
|
||||
@ -83,7 +82,7 @@ export function encodeFullSignature(fullSignature: FullSignature): amino.StdSign
|
||||
};
|
||||
}
|
||||
|
||||
export function buildUnsignedTx(tx: UnsignedTransaction, tokens: TokenInfos): AminoTx {
|
||||
export function buildUnsignedTx(tx: UnsignedTransaction, tokens: TokenInfos): types.AminoTx {
|
||||
if (!isSendTransaction(tx)) {
|
||||
throw new Error("Received transaction of unsupported kind");
|
||||
}
|
||||
@ -112,7 +111,7 @@ export function buildUnsignedTx(tx: UnsignedTransaction, tokens: TokenInfos): Am
|
||||
};
|
||||
}
|
||||
|
||||
export function buildSignedTx(tx: SignedTransaction, tokens: TokenInfos): AminoTx {
|
||||
export function buildSignedTx(tx: SignedTransaction, tokens: TokenInfos): types.AminoTx {
|
||||
const built = buildUnsignedTx(tx.transaction, tokens);
|
||||
return {
|
||||
...built,
|
||||
|
@ -16,7 +16,7 @@ import { Encoding } from "@iov/encoding";
|
||||
|
||||
import data from "./testdata/cosmoshub.json";
|
||||
|
||||
const { fromBase64 } = Encoding;
|
||||
const { fromBase64, toUtf8 } = Encoding;
|
||||
|
||||
export const pubJson: PubkeyBundle = {
|
||||
algo: Algorithm.Secp256k1,
|
||||
@ -62,3 +62,7 @@ export const signedTxJson: SignedTransaction = {
|
||||
export const signedTxBin = fromBase64(data.tx_data);
|
||||
|
||||
export const txId = data.id as TransactionId;
|
||||
|
||||
export const signedTxEncodedJson = toUtf8(
|
||||
`{"msg":[{"type":"cosmos-sdk/MsgSend","value":{"from_address":"cosmos1txqfn5jmcts0x0q7krdxj8tgf98tj0965vqlmq","to_address":"cosmos1nynns8ex9fq6sjjfj8k79ymkdz4sqth06xexae","amount":[{"denom":"uatom","amount":"35997500"}]}}],"memo":"","signatures":[{"pub_key":{"type":"tendermint/PubKeySecp256k1","value":"A5qFcJBJvEK/fOmEAY0DHNWwSRZ9TEfNZyH8VoVvDtAq"},"signature":"NK1Oy4EUGAsoC03c1wi9GG03JC/39LEdautC5Jk643oIbEPqeXHMwaqbdvO/Jws0X/NAXaN8SAy2KNY5Qml+5Q=="}],"fee":{"amount":[{"denom":"uatom","amount":"2500"}],"gas":"100000"}}`,
|
||||
);
|
||||
|
6
packages/bcp/types/address.d.ts
vendored
6
packages/bcp/types/address.d.ts
vendored
@ -1,4 +1,4 @@
|
||||
import { Address, PubkeyBundle } from "@iov/bcp";
|
||||
import { Address, Algorithm, PubkeyBundle, PubkeyBytes } from "@iov/bcp";
|
||||
export declare type CosmosAddressBech32Prefix = "cosmos" | "cosmosvalcons" | "cosmosvaloper";
|
||||
export declare type CosmosPubkeyBech32Prefix = "cosmospub" | "cosmosvalconspub" | "cosmosvaloperpub";
|
||||
export declare type CosmosBech32Prefix = CosmosAddressBech32Prefix | CosmosPubkeyBech32Prefix;
|
||||
@ -11,8 +11,8 @@ export declare function decodeCosmosAddress(
|
||||
export declare function decodeCosmosPubkey(
|
||||
encodedPubkey: string,
|
||||
): {
|
||||
readonly prefix: CosmosPubkeyBech32Prefix;
|
||||
readonly data: Uint8Array;
|
||||
readonly algo: Algorithm;
|
||||
readonly data: PubkeyBytes;
|
||||
};
|
||||
export declare function isValidAddress(address: string): boolean;
|
||||
export declare function pubkeyToAddress(pubkey: PubkeyBundle, prefix: CosmosBech32Prefix): Address;
|
||||
|
2
packages/bcp/types/cosmwasmcodec.d.ts
vendored
2
packages/bcp/types/cosmwasmcodec.d.ts
vendored
@ -18,7 +18,7 @@ export declare class CosmWasmCodec implements TxCodec {
|
||||
constructor(prefix: CosmosBech32Prefix, tokens: TokenInfos);
|
||||
bytesToSign(unsigned: UnsignedTransaction, nonce: Nonce): SigningJob;
|
||||
bytesToPost(signed: SignedTransaction): PostableBytes;
|
||||
identifier(signed: SignedTransaction): TransactionId;
|
||||
identifier(_signed: SignedTransaction): TransactionId;
|
||||
parseBytes(bytes: PostableBytes, chainId: ChainId, nonce?: Nonce): SignedTransaction;
|
||||
identityToAddress(identity: Identity): Address;
|
||||
isValidAddress(address: string): boolean;
|
||||
|
9
packages/bcp/types/cosmwasmconnection.d.ts
vendored
9
packages/bcp/types/cosmwasmconnection.d.ts
vendored
@ -22,9 +22,11 @@ import {
|
||||
import { Stream } from "xstream";
|
||||
import { CosmosBech32Prefix } from "./address";
|
||||
import { TokenInfo } from "./types";
|
||||
export declare type TokenConfiguration = readonly (TokenInfo & {
|
||||
readonly name: string;
|
||||
})[];
|
||||
export declare type TokenConfiguration = ReadonlyArray<
|
||||
TokenInfo & {
|
||||
readonly name: string;
|
||||
}
|
||||
>;
|
||||
export declare class CosmWasmConnection implements BlockchainConnection {
|
||||
static establish(
|
||||
url: string,
|
||||
@ -45,6 +47,7 @@ export declare class CosmWasmConnection implements BlockchainConnection {
|
||||
height(): Promise<number>;
|
||||
getToken(searchTicker: TokenTicker): Promise<Token | undefined>;
|
||||
getAllTokens(): Promise<readonly Token[]>;
|
||||
identifier(signed: PostableBytes): Promise<TransactionId>;
|
||||
getAccount(query: AccountQuery): Promise<Account | undefined>;
|
||||
watchAccount(_account: AccountQuery): Stream<Account | undefined>;
|
||||
getNonce(query: AddressQuery | PubkeyQuery): Promise<Nonce>;
|
||||
|
17
packages/bcp/types/decode.d.ts
vendored
17
packages/bcp/types/decode.d.ts
vendored
@ -1,4 +1,4 @@
|
||||
import { TxsResponse } from "@cosmwasm/sdk";
|
||||
import { TxsResponse, types } from "@cosmwasm/sdk";
|
||||
import {
|
||||
Amount,
|
||||
ChainId,
|
||||
@ -13,17 +13,16 @@ import {
|
||||
UnsignedTransaction,
|
||||
} from "@iov/bcp";
|
||||
import { Decimal } from "@iov/encoding";
|
||||
import amino from "@tendermint/amino-js";
|
||||
import { TokenInfos } from "./types";
|
||||
export declare function decodePubkey(pubkey: amino.PubKey): PubkeyBundle;
|
||||
export declare function decodePubkey(pubkey: types.PubKey): PubkeyBundle;
|
||||
export declare function decodeSignature(signature: string): SignatureBytes;
|
||||
export declare function decodeFullSignature(signature: amino.StdSignature, nonce: number): FullSignature;
|
||||
export declare function coinToDecimal(tokens: TokenInfos, coin: amino.Coin): readonly [Decimal, string];
|
||||
export declare function decodeAmount(tokens: TokenInfos, coin: amino.Coin): Amount;
|
||||
export declare function parseMsg(msg: amino.Msg, chainId: ChainId, tokens: TokenInfos): SendTransaction;
|
||||
export declare function parseFee(fee: amino.StdFee, tokens: TokenInfos): Fee;
|
||||
export declare function decodeFullSignature(signature: types.StdSignature, nonce: number): FullSignature;
|
||||
export declare function coinToDecimal(tokens: TokenInfos, coin: types.Coin): readonly [Decimal, string];
|
||||
export declare function decodeAmount(tokens: TokenInfos, coin: types.Coin): Amount;
|
||||
export declare function parseMsg(msg: types.Msg, chainId: ChainId, tokens: TokenInfos): SendTransaction;
|
||||
export declare function parseFee(fee: types.StdFee, tokens: TokenInfos): Fee;
|
||||
export declare function parseTx(
|
||||
tx: amino.Tx,
|
||||
txValue: types.StdTx,
|
||||
chainId: ChainId,
|
||||
nonce: Nonce,
|
||||
tokens: TokenInfos,
|
||||
|
17
packages/bcp/types/encode.d.ts
vendored
17
packages/bcp/types/encode.d.ts
vendored
@ -1,12 +1,11 @@
|
||||
import { AminoTx } from "@cosmwasm/sdk";
|
||||
import { types } from "@cosmwasm/sdk";
|
||||
import { Amount, Fee, FullSignature, PubkeyBundle, SignedTransaction, UnsignedTransaction } from "@iov/bcp";
|
||||
import { Decimal } from "@iov/encoding";
|
||||
import amino from "@tendermint/amino-js";
|
||||
import { TokenInfos } from "./types";
|
||||
export declare function encodePubkey(pubkey: PubkeyBundle): amino.PubKey;
|
||||
export declare function decimalToCoin(lookup: TokenInfos, value: Decimal, ticker: string): amino.Coin;
|
||||
export declare function encodeAmount(amount: Amount, tokens: TokenInfos): amino.Coin;
|
||||
export declare function encodeFee(fee: Fee, tokens: TokenInfos): amino.StdFee;
|
||||
export declare function encodeFullSignature(fullSignature: FullSignature): amino.StdSignature;
|
||||
export declare function buildUnsignedTx(tx: UnsignedTransaction, tokens: TokenInfos): AminoTx;
|
||||
export declare function buildSignedTx(tx: SignedTransaction, tokens: TokenInfos): AminoTx;
|
||||
export declare function encodePubkey(pubkey: PubkeyBundle): types.PubKey;
|
||||
export declare function decimalToCoin(lookup: TokenInfos, value: Decimal, ticker: string): types.Coin;
|
||||
export declare function encodeAmount(amount: Amount, tokens: TokenInfos): types.Coin;
|
||||
export declare function encodeFee(fee: Fee, tokens: TokenInfos): types.StdFee;
|
||||
export declare function encodeFullSignature(fullSignature: FullSignature): types.StdSignature;
|
||||
export declare function buildUnsignedTx(tx: UnsignedTransaction, tokens: TokenInfos): types.AminoTx;
|
||||
export declare function buildSignedTx(tx: SignedTransaction, tokens: TokenInfos): types.AminoTx;
|
||||
|
@ -39,7 +39,6 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@iov/encoding": "^2.0.0-alpha.7",
|
||||
"@tendermint/amino-js": "^0.7.0-alpha.1",
|
||||
"axios": "^0.19.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
@ -0,0 +1,11 @@
|
||||
import { Encoding } from "@iov/encoding";
|
||||
|
||||
import { isAminoStdTx, StdTx } from "./types";
|
||||
|
||||
export function unmarshalTx(data: Uint8Array): StdTx {
|
||||
const decoded = JSON.parse(Encoding.fromUtf8(data));
|
||||
if (!isAminoStdTx(decoded)) {
|
||||
throw new Error("Must be json encoded StdTx");
|
||||
}
|
||||
return decoded;
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
import { Encoding } from "@iov/encoding";
|
||||
|
||||
import { StdTx } from "./types";
|
||||
|
||||
export function marshalTx(tx: StdTx): Uint8Array {
|
||||
const json = JSON.stringify(tx);
|
||||
return Encoding.toUtf8(json);
|
||||
}
|
@ -1,2 +1,6 @@
|
||||
import * as types from "./types";
|
||||
|
||||
export { unmarshalTx } from "./decoding";
|
||||
export { marshalTx } from "./encoding";
|
||||
export { RestClient, TxsResponse } from "./restclient";
|
||||
export { AminoTx, isAminoStdTx } from "./types";
|
||||
export { types };
|
||||
|
@ -1,7 +1,9 @@
|
||||
import amino, { unmarshalTx } from "@tendermint/amino-js";
|
||||
import { Encoding } from "@iov/encoding";
|
||||
import axios, { AxiosInstance } from "axios";
|
||||
|
||||
import { AminoTx } from "./types";
|
||||
import { AminoTx, BaseAccount, isAminoStdTx, StdTx } from "./types";
|
||||
|
||||
const { fromUtf8 } = Encoding;
|
||||
|
||||
interface NodeInfo {
|
||||
readonly network: string;
|
||||
@ -35,7 +37,7 @@ interface BlocksResponse {
|
||||
|
||||
interface AuthAccountsResponse {
|
||||
readonly result: {
|
||||
readonly value: amino.BaseAccount;
|
||||
readonly value: BaseAccount;
|
||||
};
|
||||
}
|
||||
|
||||
@ -64,13 +66,19 @@ interface PostTxsResponse {
|
||||
readonly raw_log?: string;
|
||||
}
|
||||
|
||||
interface EncodeTxResponse {
|
||||
// base64-encoded amino-binary encoded representation
|
||||
readonly tx: string;
|
||||
}
|
||||
|
||||
type RestClientResponse =
|
||||
| NodeInfoResponse
|
||||
| BlocksResponse
|
||||
| AuthAccountsResponse
|
||||
| TxsResponse
|
||||
| SearchTxsResponse
|
||||
| PostTxsResponse;
|
||||
| PostTxsResponse
|
||||
| EncodeTxResponse;
|
||||
|
||||
type BroadcastMode = "block" | "sync" | "async";
|
||||
|
||||
@ -131,6 +139,16 @@ export class RestClient {
|
||||
return responseData as BlocksResponse;
|
||||
}
|
||||
|
||||
// encodeTx returns the amino-encoding of the transaction
|
||||
public async encodeTx(stdTx: StdTx): Promise<Uint8Array> {
|
||||
const tx = { type: "cosmos-sdk/StdTx", value: stdTx };
|
||||
const responseData = await this.post("/txs/encode", tx);
|
||||
if (!(responseData as any).tx) {
|
||||
throw new Error("Unexpected response data format");
|
||||
}
|
||||
return Encoding.fromBase64((responseData as EncodeTxResponse).tx);
|
||||
}
|
||||
|
||||
public async authAccounts(address: string, height?: string): Promise<AuthAccountsResponse> {
|
||||
const path =
|
||||
height === undefined ? `/auth/accounts/${address}` : `/auth/accounts/${address}?tx.height=${height}`;
|
||||
@ -157,10 +175,15 @@ export class RestClient {
|
||||
return responseData as TxsResponse;
|
||||
}
|
||||
|
||||
// tx must be JSON encoded StdTx (no wrapper)
|
||||
public async postTx(tx: Uint8Array): Promise<PostTxsResponse> {
|
||||
const unmarshalled = unmarshalTx(tx, true);
|
||||
// TODO: check this is StdTx
|
||||
const decoded = JSON.parse(fromUtf8(tx));
|
||||
if (!isAminoStdTx(decoded)) {
|
||||
throw new Error("Must be json encoded StdTx");
|
||||
}
|
||||
const params = {
|
||||
tx: unmarshalled.value,
|
||||
tx: decoded,
|
||||
mode: this.mode,
|
||||
};
|
||||
const responseData = await this.post("/txs", params);
|
||||
|
@ -1,10 +1,69 @@
|
||||
import amino from "@tendermint/amino-js";
|
||||
// We will move all needed *interfaces* from amino-js here
|
||||
// This means bcp can just import them from here (if needed at all)
|
||||
export interface Tx {
|
||||
readonly type: string;
|
||||
// TODO
|
||||
readonly value: unknown;
|
||||
}
|
||||
|
||||
export type AminoTx = amino.Tx & { readonly value: amino.StdTx };
|
||||
export interface StdTx {
|
||||
readonly msg: ReadonlyArray<Msg>;
|
||||
readonly fee: StdFee;
|
||||
readonly signatures: ReadonlyArray<StdSignature>;
|
||||
readonly memo: string | undefined;
|
||||
}
|
||||
|
||||
export function isAminoStdTx(txValue: amino.TxValue): txValue is amino.StdTx {
|
||||
const { memo, msg, fee, signatures } = txValue as amino.StdTx;
|
||||
export type AminoTx = Tx & { readonly value: StdTx };
|
||||
|
||||
export function isAminoStdTx(txValue: unknown): txValue is StdTx {
|
||||
const { memo, msg, fee, signatures } = txValue as StdTx;
|
||||
return (
|
||||
typeof memo === "string" && Array.isArray(msg) && typeof fee === "object" && Array.isArray(signatures)
|
||||
);
|
||||
}
|
||||
|
||||
export interface Msg {
|
||||
readonly type: string;
|
||||
// TODO: make better union type
|
||||
readonly value: MsgSend | unknown;
|
||||
}
|
||||
|
||||
export interface MsgSend {
|
||||
/** Bech32 account address */
|
||||
readonly from_address: string;
|
||||
/** Bech32 account address */
|
||||
readonly to_address: string;
|
||||
readonly amount: ReadonlyArray<Coin>;
|
||||
}
|
||||
|
||||
export interface StdFee {
|
||||
readonly amount: ReadonlyArray<Coin>;
|
||||
readonly gas: string;
|
||||
}
|
||||
|
||||
export interface Coin {
|
||||
readonly denom: string;
|
||||
readonly amount: string;
|
||||
}
|
||||
|
||||
export interface StdSignature {
|
||||
readonly pub_key: PubKey;
|
||||
readonly signature: string;
|
||||
}
|
||||
|
||||
export interface PubKey {
|
||||
readonly type: string;
|
||||
readonly value: string;
|
||||
}
|
||||
|
||||
// AccountPubKey is bech32-encoded amino-binary encoded PubKey interface. oof.
|
||||
export type AccountPubKey = string;
|
||||
|
||||
export interface BaseAccount {
|
||||
/** Bech32 account address */
|
||||
readonly address: string;
|
||||
readonly coins: ReadonlyArray<Coin>;
|
||||
readonly public_key: AccountPubKey;
|
||||
readonly account_number: string;
|
||||
readonly sequence: string;
|
||||
}
|
||||
|
2
packages/sdk/types/decoding.d.ts
vendored
2
packages/sdk/types/decoding.d.ts
vendored
@ -0,0 +1,2 @@
|
||||
import { StdTx } from "./types";
|
||||
export declare function unmarshalTx(data: Uint8Array): StdTx;
|
2
packages/sdk/types/encoding.d.ts
vendored
2
packages/sdk/types/encoding.d.ts
vendored
@ -0,0 +1,2 @@
|
||||
import { StdTx } from "./types";
|
||||
export declare function marshalTx(tx: StdTx): Uint8Array;
|
5
packages/sdk/types/index.d.ts
vendored
5
packages/sdk/types/index.d.ts
vendored
@ -1,2 +1,5 @@
|
||||
import * as types from "./types";
|
||||
export { unmarshalTx } from "./decoding";
|
||||
export { marshalTx } from "./encoding";
|
||||
export { RestClient, TxsResponse } from "./restclient";
|
||||
export { AminoTx, isAminoStdTx } from "./types";
|
||||
export { types };
|
||||
|
12
packages/sdk/types/restclient.d.ts
vendored
12
packages/sdk/types/restclient.d.ts
vendored
@ -1,5 +1,4 @@
|
||||
import amino from "@tendermint/amino-js";
|
||||
import { AminoTx } from "./types";
|
||||
import { AminoTx, BaseAccount, StdTx } from "./types";
|
||||
interface NodeInfo {
|
||||
readonly network: string;
|
||||
}
|
||||
@ -27,7 +26,7 @@ interface BlocksResponse {
|
||||
}
|
||||
interface AuthAccountsResponse {
|
||||
readonly result: {
|
||||
readonly value: amino.BaseAccount;
|
||||
readonly value: BaseAccount;
|
||||
};
|
||||
}
|
||||
export interface TxsResponse {
|
||||
@ -51,13 +50,17 @@ interface PostTxsResponse {
|
||||
readonly code?: number;
|
||||
readonly raw_log?: string;
|
||||
}
|
||||
interface EncodeTxResponse {
|
||||
readonly tx: string;
|
||||
}
|
||||
declare type RestClientResponse =
|
||||
| NodeInfoResponse
|
||||
| BlocksResponse
|
||||
| AuthAccountsResponse
|
||||
| TxsResponse
|
||||
| SearchTxsResponse
|
||||
| PostTxsResponse;
|
||||
| PostTxsResponse
|
||||
| EncodeTxResponse;
|
||||
declare type BroadcastMode = "block" | "sync" | "async";
|
||||
export declare class RestClient {
|
||||
private readonly client;
|
||||
@ -68,6 +71,7 @@ export declare class RestClient {
|
||||
nodeInfo(): Promise<NodeInfoResponse>;
|
||||
blocksLatest(): Promise<BlocksResponse>;
|
||||
blocks(height: number): Promise<BlocksResponse>;
|
||||
encodeTx(stdTx: StdTx): Promise<Uint8Array>;
|
||||
authAccounts(address: string, height?: string): Promise<AuthAccountsResponse>;
|
||||
txs(query: string): Promise<SearchTxsResponse>;
|
||||
txsById(id: string): Promise<TxsResponse>;
|
||||
|
53
packages/sdk/types/types.d.ts
vendored
53
packages/sdk/types/types.d.ts
vendored
@ -1,5 +1,50 @@
|
||||
import amino from "@tendermint/amino-js";
|
||||
export declare type AminoTx = amino.Tx & {
|
||||
readonly value: amino.StdTx;
|
||||
export interface Tx {
|
||||
readonly type: string;
|
||||
readonly value: unknown;
|
||||
}
|
||||
export interface StdTx {
|
||||
readonly msg: ReadonlyArray<Msg>;
|
||||
readonly fee: StdFee;
|
||||
readonly signatures: ReadonlyArray<StdSignature>;
|
||||
readonly memo: string | undefined;
|
||||
}
|
||||
export declare type AminoTx = Tx & {
|
||||
readonly value: StdTx;
|
||||
};
|
||||
export declare function isAminoStdTx(txValue: amino.TxValue): txValue is amino.StdTx;
|
||||
export declare function isAminoStdTx(txValue: unknown): txValue is StdTx;
|
||||
export interface Msg {
|
||||
readonly type: string;
|
||||
readonly value: MsgSend | unknown;
|
||||
}
|
||||
export interface MsgSend {
|
||||
/** Bech32 account address */
|
||||
readonly from_address: string;
|
||||
/** Bech32 account address */
|
||||
readonly to_address: string;
|
||||
readonly amount: ReadonlyArray<Coin>;
|
||||
}
|
||||
export interface StdFee {
|
||||
readonly amount: ReadonlyArray<Coin>;
|
||||
readonly gas: string;
|
||||
}
|
||||
export interface Coin {
|
||||
readonly denom: string;
|
||||
readonly amount: string;
|
||||
}
|
||||
export interface StdSignature {
|
||||
readonly pub_key: PubKey;
|
||||
readonly signature: string;
|
||||
}
|
||||
export interface PubKey {
|
||||
readonly type: string;
|
||||
readonly value: string;
|
||||
}
|
||||
export declare type AccountPubKey = string;
|
||||
export interface BaseAccount {
|
||||
/** Bech32 account address */
|
||||
readonly address: string;
|
||||
readonly coins: ReadonlyArray<Coin>;
|
||||
readonly public_key: AccountPubKey;
|
||||
readonly account_number: string;
|
||||
readonly sequence: string;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user