mirror of
https://github.com/cosmos/cosmjs.git
synced 2025-03-10 21:49:15 +00:00
Merge pull request #28 from confio/add-sdk
Extract RestClient, TxsResponse, AminoTx into @cosmwasm/sdk
This commit is contained in:
commit
8610da30d2
@ -5,6 +5,7 @@ FROM node:12.14-alpine AS build-env
|
||||
ADD package.json yarn.lock tsconfig.json lerna.json /build_repo_root/
|
||||
ADD packages/bcp /build_repo_root/packages/bcp
|
||||
ADD packages/faucet /build_repo_root/packages/faucet
|
||||
ADD packages/sdk /build_repo_root/packages/sdk
|
||||
|
||||
WORKDIR /build_repo_root
|
||||
RUN yarn install --frozen-lockfile
|
||||
|
@ -38,12 +38,12 @@
|
||||
"pack-web": "yarn build-or-skip && webpack --mode development --config webpack.web.config.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@cosmwasm/sdk": "^0.0.1",
|
||||
"@iov/bcp": "^2.0.0-alpha.7",
|
||||
"@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",
|
||||
"axios": "^0.19.0",
|
||||
"fast-deep-equal": "^3.1.1",
|
||||
"readonly-date": "^1.0.0",
|
||||
"xstream": "^11.11.0"
|
||||
|
@ -9,7 +9,6 @@ import {
|
||||
SignableBytes,
|
||||
SignedTransaction,
|
||||
SigningJob,
|
||||
TokenTicker,
|
||||
TransactionId,
|
||||
TxCodec,
|
||||
UnsignedTransaction,
|
||||
@ -107,8 +106,7 @@ const defaultPrefix = "cosmos" as CosmosBech32Prefix;
|
||||
const defaultTokens: TokenInfos = [
|
||||
{
|
||||
fractionalDigits: 6,
|
||||
tokenName: "Atom (Cosmos Hub)",
|
||||
tokenTicker: "ATOM" as TokenTicker,
|
||||
ticker: "ATOM",
|
||||
denom: "uatom",
|
||||
},
|
||||
];
|
||||
|
@ -16,8 +16,8 @@ import { HdPaths, Secp256k1HdWallet, UserProfile } from "@iov/keycontrol";
|
||||
|
||||
import { CosmosBech32Prefix } from "./address";
|
||||
import { CosmWasmCodec, cosmWasmCodec } from "./cosmwasmcodec";
|
||||
import { CosmWasmConnection } from "./cosmwasmconnection";
|
||||
import { nonceToSequence, TokenInfos } from "./types";
|
||||
import { CosmWasmConnection, TokenConfiguration } from "./cosmwasmconnection";
|
||||
import { nonceToSequence } from "./types";
|
||||
|
||||
const { fromBase64, toHex } = Encoding;
|
||||
|
||||
@ -45,17 +45,17 @@ describe("CosmWasmConnection", () => {
|
||||
const defaultPrefix = "cosmos" as CosmosBech32Prefix;
|
||||
|
||||
// this is for wasmd blockchain
|
||||
const defaultTokens: TokenInfos = [
|
||||
const defaultTokens: TokenConfiguration = [
|
||||
{
|
||||
fractionalDigits: 6,
|
||||
tokenName: "Fee Token",
|
||||
tokenTicker: "COSM" as TokenTicker,
|
||||
name: "Fee Token",
|
||||
ticker: "COSM",
|
||||
denom: "ucosm",
|
||||
},
|
||||
{
|
||||
fractionalDigits: 6,
|
||||
tokenName: "Staking Token",
|
||||
tokenTicker: "STAKE" as TokenTicker,
|
||||
name: "Staking Token",
|
||||
ticker: "STAKE",
|
||||
denom: "ustake",
|
||||
},
|
||||
];
|
||||
|
@ -1,4 +1,5 @@
|
||||
/* eslint-disable @typescript-eslint/camelcase */
|
||||
import { RestClient, TokenInfo, TxsResponse } from "@cosmwasm/sdk";
|
||||
import {
|
||||
Account,
|
||||
AccountQuery,
|
||||
@ -37,8 +38,7 @@ import { Stream } from "xstream";
|
||||
import { CosmosBech32Prefix, decodeCosmosPubkey, pubkeyToAddress } from "./address";
|
||||
import { Caip5 } from "./caip5";
|
||||
import { decodeAmount, parseTxsResponse } from "./decode";
|
||||
import { RestClient, TxsResponse } from "./restclient";
|
||||
import { accountToNonce, TokenInfos } from "./types";
|
||||
import { accountToNonce } from "./types";
|
||||
|
||||
interface ChainData {
|
||||
readonly chainId: ChainId;
|
||||
@ -68,16 +68,18 @@ function buildQueryString({
|
||||
return components.filter(Boolean).join("&");
|
||||
}
|
||||
|
||||
export type TokenConfiguration = readonly (TokenInfo & { readonly name: string })[];
|
||||
|
||||
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,
|
||||
tokenInfo: TokenInfos,
|
||||
tokens: TokenConfiguration,
|
||||
): Promise<CosmWasmConnection> {
|
||||
const restClient = new RestClient(url);
|
||||
const chainData = await this.initialize(restClient);
|
||||
return new CosmWasmConnection(restClient, chainData, prefix, tokenInfo);
|
||||
return new CosmWasmConnection(restClient, chainData, prefix, tokens);
|
||||
}
|
||||
|
||||
private static async initialize(restClient: RestClient): Promise<ChainData> {
|
||||
@ -88,7 +90,7 @@ export class CosmWasmConnection implements BlockchainConnection {
|
||||
private readonly restClient: RestClient;
|
||||
private readonly chainData: ChainData;
|
||||
private readonly _prefix: CosmosBech32Prefix;
|
||||
private readonly tokenInfo: TokenInfos;
|
||||
private readonly tokenInfo: readonly TokenInfo[];
|
||||
|
||||
// these are derived from arguments (cached for use in multiple functions)
|
||||
private readonly primaryToken: Token;
|
||||
@ -102,16 +104,16 @@ export class CosmWasmConnection implements BlockchainConnection {
|
||||
restClient: RestClient,
|
||||
chainData: ChainData,
|
||||
prefix: CosmosBech32Prefix,
|
||||
tokenInfo: TokenInfos,
|
||||
tokens: TokenConfiguration,
|
||||
) {
|
||||
this.restClient = restClient;
|
||||
this.chainData = chainData;
|
||||
this._prefix = prefix;
|
||||
this.tokenInfo = tokenInfo;
|
||||
this.tokenInfo = tokens;
|
||||
|
||||
this.supportedTokens = this.tokenInfo.map(info => ({
|
||||
tokenTicker: info.tokenTicker,
|
||||
tokenName: info.tokenName,
|
||||
this.supportedTokens = tokens.map(info => ({
|
||||
tokenTicker: info.ticker as TokenTicker,
|
||||
tokenName: info.name,
|
||||
fractionalDigits: info.fractionalDigits,
|
||||
}));
|
||||
this.primaryToken = this.supportedTokens[0];
|
||||
@ -158,7 +160,7 @@ export class CosmWasmConnection implements BlockchainConnection {
|
||||
};
|
||||
return {
|
||||
address: address,
|
||||
balance: supportedCoins.map(decodeAmount(this.tokenInfo)),
|
||||
balance: supportedCoins.map(coin => decodeAmount(this.tokenInfo, coin)),
|
||||
pubkey: pubkey,
|
||||
};
|
||||
}
|
||||
|
@ -2,8 +2,7 @@ import { ChainConnector, ChainId } from "@iov/bcp";
|
||||
|
||||
import { CosmosBech32Prefix } from "./address";
|
||||
import { CosmWasmCodec } from "./cosmwasmcodec";
|
||||
import { CosmWasmConnection } from "./cosmwasmconnection";
|
||||
import { TokenInfo } from "./types";
|
||||
import { CosmWasmConnection, TokenConfiguration } from "./cosmwasmconnection";
|
||||
|
||||
/**
|
||||
* A helper to connect to a cosmos-based chain at a given url
|
||||
@ -11,12 +10,12 @@ import { TokenInfo } from "./types";
|
||||
export function createCosmWasmConnector(
|
||||
url: string,
|
||||
prefix: CosmosBech32Prefix,
|
||||
tokenInfo: readonly TokenInfo[],
|
||||
tokens: TokenConfiguration,
|
||||
expectedChainId?: ChainId,
|
||||
): ChainConnector<CosmWasmConnection> {
|
||||
const codec = new CosmWasmCodec(prefix, tokenInfo);
|
||||
const codec = new CosmWasmCodec(prefix, tokens);
|
||||
return {
|
||||
establishConnection: async () => CosmWasmConnection.establish(url, prefix, tokenInfo),
|
||||
establishConnection: async () => CosmWasmConnection.establish(url, prefix, tokens),
|
||||
codec: codec,
|
||||
expectedChainId: expectedChainId,
|
||||
};
|
||||
|
@ -55,8 +55,7 @@ describe("decode", () => {
|
||||
const defaultTokens: TokenInfos = [
|
||||
{
|
||||
fractionalDigits: 6,
|
||||
tokenName: "Atom (Cosmos Hub)",
|
||||
tokenTicker: "ATOM" as TokenTicker,
|
||||
ticker: "ATOM",
|
||||
denom: "uatom",
|
||||
},
|
||||
];
|
||||
@ -118,7 +117,7 @@ describe("decode", () => {
|
||||
denom: "uatom",
|
||||
amount: "11657995",
|
||||
};
|
||||
expect(decodeAmount(defaultTokens)(amount)).toEqual(defaultAmount);
|
||||
expect(decodeAmount(defaultTokens, amount)).toEqual(defaultAmount);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { coinToDecimal, isAminoStdTx, TxsResponse } from "@cosmwasm/sdk";
|
||||
import {
|
||||
Address,
|
||||
Algorithm,
|
||||
@ -12,14 +13,14 @@ import {
|
||||
SendTransaction,
|
||||
SignatureBytes,
|
||||
SignedTransaction,
|
||||
TokenTicker,
|
||||
TransactionId,
|
||||
UnsignedTransaction,
|
||||
} from "@iov/bcp";
|
||||
import { Encoding } from "@iov/encoding";
|
||||
import amino from "@tendermint/amino-js";
|
||||
|
||||
import { TxsResponse } from "./restclient";
|
||||
import { coinToAmount, isAminoStdTx, TokenInfos } from "./types";
|
||||
import { TokenInfos } from "./types";
|
||||
|
||||
const { fromBase64 } = Encoding;
|
||||
|
||||
@ -54,10 +55,14 @@ export function decodeFullSignature(signature: amino.StdSignature, nonce: number
|
||||
};
|
||||
}
|
||||
|
||||
// TODO: return null vs throw exception for undefined???
|
||||
export const decodeAmount = (tokens: TokenInfos) => (coin: amino.Coin): Amount => {
|
||||
return coinToAmount(tokens, coin);
|
||||
};
|
||||
export function decodeAmount(tokens: TokenInfos, coin: amino.Coin): Amount {
|
||||
const [value, ticker] = coinToDecimal(tokens, coin);
|
||||
return {
|
||||
quantity: value.atomics,
|
||||
fractionalDigits: value.fractionalDigits,
|
||||
tokenTicker: ticker as TokenTicker,
|
||||
};
|
||||
}
|
||||
|
||||
export function parseMsg(msg: amino.Msg, chainId: ChainId, tokens: TokenInfos): SendTransaction {
|
||||
if (msg.type !== "cosmos-sdk/MsgSend") {
|
||||
@ -75,7 +80,7 @@ export function parseMsg(msg: amino.Msg, chainId: ChainId, tokens: TokenInfos):
|
||||
chainId: chainId,
|
||||
sender: msgValue.from_address as Address,
|
||||
recipient: msgValue.to_address as Address,
|
||||
amount: decodeAmount(tokens)(msgValue.amount[0]),
|
||||
amount: decodeAmount(tokens, msgValue.amount[0]),
|
||||
};
|
||||
}
|
||||
|
||||
@ -84,7 +89,7 @@ export function parseFee(fee: amino.StdFee, tokens: TokenInfos): Fee {
|
||||
throw new Error("Only fee with one amount is supported");
|
||||
}
|
||||
return {
|
||||
tokens: decodeAmount(tokens)(fee.amount[0]),
|
||||
tokens: decodeAmount(tokens, fee.amount[0]),
|
||||
gasLimit: fee.gas,
|
||||
};
|
||||
}
|
||||
|
@ -44,8 +44,7 @@ describe("encode", () => {
|
||||
const defaultTokens: TokenInfos = [
|
||||
{
|
||||
fractionalDigits: 6,
|
||||
tokenName: "Atom (Cosmos Hub)",
|
||||
tokenTicker: "ATOM" as TokenTicker,
|
||||
ticker: "ATOM",
|
||||
denom: "uatom",
|
||||
},
|
||||
];
|
||||
|
@ -1,4 +1,5 @@
|
||||
/* eslint-disable @typescript-eslint/camelcase */
|
||||
import { AminoTx, decimalToCoin } from "@cosmwasm/sdk";
|
||||
import {
|
||||
Algorithm,
|
||||
Amount,
|
||||
@ -10,10 +11,10 @@ import {
|
||||
UnsignedTransaction,
|
||||
} from "@iov/bcp";
|
||||
import { Secp256k1 } from "@iov/crypto";
|
||||
import { Encoding } from "@iov/encoding";
|
||||
import { Decimal, Encoding } from "@iov/encoding";
|
||||
import amino from "@tendermint/amino-js";
|
||||
|
||||
import { AminoTx, amountToCoin, TokenInfos } from "./types";
|
||||
import { TokenInfos } from "./types";
|
||||
|
||||
const { toBase64 } = Encoding;
|
||||
|
||||
@ -35,7 +36,11 @@ export function encodePubkey(pubkey: PubkeyBundle): amino.PubKey {
|
||||
}
|
||||
|
||||
export function encodeAmount(amount: Amount, tokens: TokenInfos): amino.Coin {
|
||||
return amountToCoin(tokens, amount);
|
||||
return decimalToCoin(
|
||||
tokens,
|
||||
Decimal.fromAtomics(amount.quantity, amount.fractionalDigits),
|
||||
amount.tokenTicker,
|
||||
);
|
||||
}
|
||||
|
||||
export function encodeFee(fee: Fee, tokens: TokenInfos): amino.StdFee {
|
||||
|
@ -1,4 +1,3 @@
|
||||
export { CosmWasmCodec } from "./cosmwasmcodec";
|
||||
export { CosmWasmConnection } from "./cosmwasmconnection";
|
||||
export { CosmWasmConnection, TokenConfiguration } from "./cosmwasmconnection";
|
||||
export { createCosmWasmConnector } from "./cosmwasmconnector";
|
||||
export { TokenInfo } from "./types";
|
||||
|
@ -1,46 +1,8 @@
|
||||
import { Amount, Nonce, Token } from "@iov/bcp";
|
||||
import amino from "@tendermint/amino-js";
|
||||
|
||||
export type AminoTx = amino.Tx & { readonly value: amino.StdTx };
|
||||
|
||||
export function isAminoStdTx(txValue: amino.TxValue): txValue is amino.StdTx {
|
||||
const { memo, msg, fee, signatures } = txValue as amino.StdTx;
|
||||
return (
|
||||
typeof memo === "string" && Array.isArray(msg) && typeof fee === "object" && Array.isArray(signatures)
|
||||
);
|
||||
}
|
||||
|
||||
export interface TokenInfo extends Token {
|
||||
readonly denom: string;
|
||||
}
|
||||
import { TokenInfo } from "@cosmwasm/sdk";
|
||||
import { Nonce } from "@iov/bcp";
|
||||
|
||||
export type TokenInfos = ReadonlyArray<TokenInfo>;
|
||||
|
||||
// TODO: return null vs throw exception for undefined???
|
||||
export function amountToCoin(lookup: ReadonlyArray<TokenInfo>, amount: Amount): amino.Coin {
|
||||
const match = lookup.find(({ tokenTicker }) => tokenTicker === amount.tokenTicker);
|
||||
if (!match) {
|
||||
throw Error(`unknown ticker: ${amount.tokenTicker}`);
|
||||
}
|
||||
return {
|
||||
denom: match.denom,
|
||||
amount: amount.quantity,
|
||||
};
|
||||
}
|
||||
|
||||
// TODO: return null vs throw exception for undefined???
|
||||
export function coinToAmount(tokens: TokenInfos, coin: amino.Coin): Amount {
|
||||
const match = tokens.find(({ denom }) => denom === coin.denom);
|
||||
if (!match) {
|
||||
throw Error(`unknown denom: ${coin.denom}`);
|
||||
}
|
||||
return {
|
||||
tokenTicker: match.tokenTicker,
|
||||
fractionalDigits: match.fractionalDigits,
|
||||
quantity: coin.amount,
|
||||
};
|
||||
}
|
||||
|
||||
// tslint:disable-next-line:no-bitwise
|
||||
const maxAcct = 1 << 23;
|
||||
// tslint:disable-next-line:no-bitwise
|
||||
|
7
packages/bcp/types/cosmwasmconnection.d.ts
vendored
7
packages/bcp/types/cosmwasmconnection.d.ts
vendored
@ -1,3 +1,4 @@
|
||||
import { TokenInfo } from "@cosmwasm/sdk";
|
||||
import {
|
||||
Account,
|
||||
AccountQuery,
|
||||
@ -21,12 +22,14 @@ import {
|
||||
} from "@iov/bcp";
|
||||
import { Stream } from "xstream";
|
||||
import { CosmosBech32Prefix } from "./address";
|
||||
import { TokenInfos } from "./types";
|
||||
export declare type TokenConfiguration = readonly (TokenInfo & {
|
||||
readonly name: string;
|
||||
})[];
|
||||
export declare class CosmWasmConnection implements BlockchainConnection {
|
||||
static establish(
|
||||
url: string,
|
||||
prefix: CosmosBech32Prefix,
|
||||
tokenInfo: TokenInfos,
|
||||
tokens: TokenConfiguration,
|
||||
): Promise<CosmWasmConnection>;
|
||||
private static initialize;
|
||||
private readonly restClient;
|
||||
|
5
packages/bcp/types/cosmwasmconnector.d.ts
vendored
5
packages/bcp/types/cosmwasmconnector.d.ts
vendored
@ -1,13 +1,12 @@
|
||||
import { ChainConnector, ChainId } from "@iov/bcp";
|
||||
import { CosmosBech32Prefix } from "./address";
|
||||
import { CosmWasmConnection } from "./cosmwasmconnection";
|
||||
import { TokenInfo } from "./types";
|
||||
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,
|
||||
tokenInfo: readonly TokenInfo[],
|
||||
tokens: TokenConfiguration,
|
||||
expectedChainId?: ChainId,
|
||||
): ChainConnector<CosmWasmConnection>;
|
||||
|
4
packages/bcp/types/decode.d.ts
vendored
4
packages/bcp/types/decode.d.ts
vendored
@ -1,3 +1,4 @@
|
||||
import { TxsResponse } from "@cosmwasm/sdk";
|
||||
import {
|
||||
Amount,
|
||||
ChainId,
|
||||
@ -12,12 +13,11 @@ import {
|
||||
UnsignedTransaction,
|
||||
} from "@iov/bcp";
|
||||
import amino from "@tendermint/amino-js";
|
||||
import { TxsResponse } from "./restclient";
|
||||
import { TokenInfos } from "./types";
|
||||
export declare function decodePubkey(pubkey: amino.PubKey): PubkeyBundle;
|
||||
export declare function decodeSignature(signature: string): SignatureBytes;
|
||||
export declare function decodeFullSignature(signature: amino.StdSignature, nonce: number): FullSignature;
|
||||
export declare const decodeAmount: (tokens: TokenInfos) => (coin: amino.Coin) => Amount;
|
||||
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 parseTx(
|
||||
|
3
packages/bcp/types/encode.d.ts
vendored
3
packages/bcp/types/encode.d.ts
vendored
@ -1,6 +1,7 @@
|
||||
import { AminoTx } from "@cosmwasm/sdk";
|
||||
import { Amount, Fee, FullSignature, PubkeyBundle, SignedTransaction, UnsignedTransaction } from "@iov/bcp";
|
||||
import amino from "@tendermint/amino-js";
|
||||
import { AminoTx, TokenInfos } from "./types";
|
||||
import { TokenInfos } from "./types";
|
||||
export declare function encodePubkey(pubkey: PubkeyBundle): amino.PubKey;
|
||||
export declare function encodeAmount(amount: Amount, tokens: TokenInfos): amino.Coin;
|
||||
export declare function encodeFee(fee: Fee, tokens: TokenInfos): amino.StdFee;
|
||||
|
3
packages/bcp/types/index.d.ts
vendored
3
packages/bcp/types/index.d.ts
vendored
@ -1,4 +1,3 @@
|
||||
export { CosmWasmCodec } from "./cosmwasmcodec";
|
||||
export { CosmWasmConnection } from "./cosmwasmconnection";
|
||||
export { CosmWasmConnection, TokenConfiguration } from "./cosmwasmconnection";
|
||||
export { createCosmWasmConnector } from "./cosmwasmconnector";
|
||||
export { TokenInfo } from "./types";
|
||||
|
13
packages/bcp/types/types.d.ts
vendored
13
packages/bcp/types/types.d.ts
vendored
@ -1,15 +1,6 @@
|
||||
import { Amount, Nonce, Token } from "@iov/bcp";
|
||||
import amino from "@tendermint/amino-js";
|
||||
export declare type AminoTx = amino.Tx & {
|
||||
readonly value: amino.StdTx;
|
||||
};
|
||||
export declare function isAminoStdTx(txValue: amino.TxValue): txValue is amino.StdTx;
|
||||
export interface TokenInfo extends Token {
|
||||
readonly denom: string;
|
||||
}
|
||||
import { TokenInfo } from "@cosmwasm/sdk";
|
||||
import { Nonce } from "@iov/bcp";
|
||||
export declare type TokenInfos = ReadonlyArray<TokenInfo>;
|
||||
export declare function amountToCoin(lookup: ReadonlyArray<TokenInfo>, amount: Amount): amino.Coin;
|
||||
export declare function coinToAmount(tokens: TokenInfos, coin: amino.Coin): Amount;
|
||||
export interface NonceInfo {
|
||||
readonly account_number: string;
|
||||
readonly sequence: string;
|
||||
|
@ -1,18 +1,18 @@
|
||||
import { CosmWasmCodec, CosmWasmConnection, TokenInfo } from "@cosmwasm/bcp";
|
||||
import { TokenTicker, TxCodec } from "@iov/bcp";
|
||||
import { CosmWasmCodec, CosmWasmConnection, TokenConfiguration } from "@cosmwasm/bcp";
|
||||
import { TxCodec } from "@iov/bcp";
|
||||
|
||||
const prefix = "cosmos";
|
||||
const tokens: readonly TokenInfo[] = [
|
||||
const tokens: TokenConfiguration = [
|
||||
{
|
||||
fractionalDigits: 6,
|
||||
tokenName: "Fee Token",
|
||||
tokenTicker: "COSM" as TokenTicker,
|
||||
name: "Fee Token",
|
||||
ticker: "COSM",
|
||||
denom: "cosm",
|
||||
},
|
||||
{
|
||||
fractionalDigits: 6,
|
||||
tokenName: "Staking Token",
|
||||
tokenTicker: "STAKE" as TokenTicker,
|
||||
name: "Staking Token",
|
||||
ticker: "STAKE",
|
||||
denom: "stake",
|
||||
},
|
||||
];
|
||||
|
1
packages/sdk/.eslintignore
Symbolic link
1
packages/sdk/.eslintignore
Symbolic link
@ -0,0 +1 @@
|
||||
../../.eslintignore
|
3
packages/sdk/.gitignore
vendored
Normal file
3
packages/sdk/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
build/
|
||||
dist/
|
||||
docs/
|
12
packages/sdk/jasmine-spec-reporter.config.json
Normal file
12
packages/sdk/jasmine-spec-reporter.config.json
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"suite": {
|
||||
"displayNumber": true
|
||||
},
|
||||
"spec": {
|
||||
"displayDuration": true
|
||||
},
|
||||
"summary": {
|
||||
"displayPending": false,
|
||||
"displayStacktrace": true
|
||||
}
|
||||
}
|
26
packages/sdk/jasmine-testrunner.js
Executable file
26
packages/sdk/jasmine-testrunner.js
Executable file
@ -0,0 +1,26 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
require("source-map-support").install();
|
||||
const defaultSpecReporterConfig = require("./jasmine-spec-reporter.config.json");
|
||||
|
||||
// setup Jasmine
|
||||
const Jasmine = require("jasmine");
|
||||
const jasmine = new Jasmine();
|
||||
jasmine.loadConfig({
|
||||
spec_dir: "build",
|
||||
spec_files: ["**/*.spec.js"],
|
||||
helpers: [],
|
||||
random: false,
|
||||
seed: null,
|
||||
stopSpecOnExpectationFailure: false,
|
||||
});
|
||||
jasmine.jasmine.DEFAULT_TIMEOUT_INTERVAL = 15 * 1000;
|
||||
|
||||
// setup reporter
|
||||
const { SpecReporter } = require("jasmine-spec-reporter");
|
||||
const reporter = new SpecReporter({ ...defaultSpecReporterConfig });
|
||||
|
||||
// initialize and execute
|
||||
jasmine.env.clearReporters();
|
||||
jasmine.addReporter(reporter);
|
||||
jasmine.execute();
|
54
packages/sdk/karma.conf.js
Normal file
54
packages/sdk/karma.conf.js
Normal file
@ -0,0 +1,54 @@
|
||||
module.exports = function(config) {
|
||||
config.set({
|
||||
// base path that will be used to resolve all patterns (eg. files, exclude)
|
||||
basePath: ".",
|
||||
|
||||
// frameworks to use
|
||||
// available frameworks: https://npmjs.org/browse/keyword/karma-adapter
|
||||
frameworks: ["jasmine"],
|
||||
|
||||
// list of files / patterns to load in the browser
|
||||
files: ["dist/web/tests.js"],
|
||||
|
||||
client: {
|
||||
jasmine: {
|
||||
random: false,
|
||||
timeoutInterval: 15000,
|
||||
},
|
||||
},
|
||||
|
||||
// test results reporter to use
|
||||
// possible values: 'dots', 'progress'
|
||||
// available reporters: https://npmjs.org/browse/keyword/karma-reporter
|
||||
reporters: ["progress", "kjhtml"],
|
||||
|
||||
// web server port
|
||||
port: 9876,
|
||||
|
||||
// enable / disable colors in the output (reporters and logs)
|
||||
colors: true,
|
||||
|
||||
// level of logging
|
||||
// possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
|
||||
logLevel: config.LOG_INFO,
|
||||
|
||||
// enable / disable watching file and executing tests whenever any file changes
|
||||
autoWatch: false,
|
||||
|
||||
// start these browsers
|
||||
// available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
|
||||
browsers: ["Firefox"],
|
||||
|
||||
browserNoActivityTimeout: 90000,
|
||||
|
||||
// Keep brower open for debugging. This is overridden by yarn scripts
|
||||
singleRun: false,
|
||||
|
||||
customLaunchers: {
|
||||
ChromeHeadlessInsecure: {
|
||||
base: "ChromeHeadless",
|
||||
flags: ["--disable-web-security"],
|
||||
},
|
||||
},
|
||||
});
|
||||
};
|
1
packages/sdk/nonces/README.txt
Normal file
1
packages/sdk/nonces/README.txt
Normal file
@ -0,0 +1 @@
|
||||
Directory used to trigger lerna package updates for all packages
|
47
packages/sdk/package.json
Normal file
47
packages/sdk/package.json
Normal file
@ -0,0 +1,47 @@
|
||||
{
|
||||
"name": "@cosmwasm/sdk",
|
||||
"version": "0.0.1",
|
||||
"description": "CosmWasm SDK",
|
||||
"author": "Ethan Frey <ethanfrey@users.noreply.github.com>",
|
||||
"license": "Apache-2.0",
|
||||
"main": "build/index.js",
|
||||
"types": "types/index.d.ts",
|
||||
"files": [
|
||||
"build/",
|
||||
"types/",
|
||||
"*.md",
|
||||
"!*.spec.*",
|
||||
"!**/testdata/"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/confio/cosm-js/tree/master/packages/sdk"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"scripts": {
|
||||
"docs": "shx rm -rf docs && typedoc --options typedoc.js",
|
||||
"format": "prettier --write --loglevel warn \"./src/**/*.ts\"",
|
||||
"lint": "eslint --max-warnings 0 \"**/*.{js,ts}\" && tslint -t verbose --project .",
|
||||
"lint-fix": "eslint --max-warnings 0 \"**/*.{js,ts}\" --fix",
|
||||
"move-types": "shx rm -rf ./types/* && shx mv build/types/* ./types && rm -rf ./types/testdata && shx rm -f ./types/*.spec.d.ts",
|
||||
"format-types": "prettier --write --loglevel warn \"./types/**/*.d.ts\"",
|
||||
"build": "shx rm -rf ./build && tsc && yarn move-types && yarn format-types",
|
||||
"build-or-skip": "[ -n \"$SKIP_BUILD\" ] || yarn build",
|
||||
"test-node": "node jasmine-testrunner.js",
|
||||
"test-edge": "yarn pack-web && karma start --single-run --browsers Edge",
|
||||
"test-firefox": "yarn pack-web && karma start --single-run --browsers Firefox",
|
||||
"test-chrome": "yarn pack-web && karma start --single-run --browsers ChromeHeadlessInsecure",
|
||||
"test-safari": "yarn pack-web && karma start --single-run --browsers Safari",
|
||||
"test": "yarn build-or-skip && yarn test-node",
|
||||
"pack-web": "yarn build-or-skip && webpack --mode development --config webpack.web.config.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@iov/encoding": "^2.0.0-alpha.7",
|
||||
"@tendermint/amino-js": "^0.7.0-alpha.1",
|
||||
"axios": "^0.19.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
}
|
||||
}
|
13
packages/sdk/src/decoding.ts
Normal file
13
packages/sdk/src/decoding.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import { Decimal } from "@iov/encoding";
|
||||
import amino from "@tendermint/amino-js";
|
||||
|
||||
import { TokenInfo } from "./types";
|
||||
|
||||
export function coinToDecimal(tokens: readonly TokenInfo[], coin: amino.Coin): readonly [Decimal, string] {
|
||||
const match = tokens.find(({ denom }) => denom === coin.denom);
|
||||
if (!match) {
|
||||
throw Error(`unknown denom: ${coin.denom}`);
|
||||
}
|
||||
const value = Decimal.fromAtomics(coin.amount, match.fractionalDigits);
|
||||
return [value, match.ticker];
|
||||
}
|
20
packages/sdk/src/encoding.ts
Normal file
20
packages/sdk/src/encoding.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import { Decimal } from "@iov/encoding";
|
||||
import amino from "@tendermint/amino-js";
|
||||
|
||||
import { TokenInfo } from "./types";
|
||||
|
||||
export function decimalToCoin(lookup: readonly TokenInfo[], value: Decimal, ticker: string): amino.Coin {
|
||||
const match = lookup.find(token => token.ticker === ticker);
|
||||
if (!match) {
|
||||
throw Error(`unknown ticker: ${ticker}`);
|
||||
}
|
||||
if (match.fractionalDigits !== value.fractionalDigits) {
|
||||
throw new Error(
|
||||
"Mismatch in fractional digits between token and value. If you really want, implement a conversion here. However, this indicates a bug in the caller code.",
|
||||
);
|
||||
}
|
||||
return {
|
||||
denom: match.denom,
|
||||
amount: value.atomics,
|
||||
};
|
||||
}
|
4
packages/sdk/src/index.ts
Normal file
4
packages/sdk/src/index.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export { coinToDecimal } from "./decoding";
|
||||
export { decimalToCoin } from "./encoding";
|
||||
export { RestClient, TxsResponse } from "./restclient";
|
||||
export { AminoTx, isAminoStdTx, TokenInfo } from "./types";
|
10
packages/sdk/src/restclient.spec.ts
Normal file
10
packages/sdk/src/restclient.spec.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import { RestClient } from "./restclient";
|
||||
|
||||
const httpUrl = "http://localhost:1317";
|
||||
|
||||
describe("RestClient", () => {
|
||||
it("can be constructed", () => {
|
||||
const client = new RestClient(httpUrl);
|
||||
expect(client).toBeTruthy();
|
||||
});
|
||||
});
|
@ -1,4 +1,3 @@
|
||||
import { Address, PostableBytes, TransactionId } from "@iov/bcp";
|
||||
import amino, { unmarshalTx } from "@tendermint/amino-js";
|
||||
import axios, { AxiosInstance } from "axios";
|
||||
|
||||
@ -132,7 +131,7 @@ export class RestClient {
|
||||
return responseData as BlocksResponse;
|
||||
}
|
||||
|
||||
public async authAccounts(address: Address, height?: string): Promise<AuthAccountsResponse> {
|
||||
public async authAccounts(address: string, height?: string): Promise<AuthAccountsResponse> {
|
||||
const path =
|
||||
height === undefined ? `/auth/accounts/${address}` : `/auth/accounts/${address}?tx.height=${height}`;
|
||||
const responseData = await this.get(path);
|
||||
@ -150,7 +149,7 @@ export class RestClient {
|
||||
return responseData as SearchTxsResponse;
|
||||
}
|
||||
|
||||
public async txsById(id: TransactionId): Promise<TxsResponse> {
|
||||
public async txsById(id: string): Promise<TxsResponse> {
|
||||
const responseData = await this.get(`/txs/${id}`);
|
||||
if (!(responseData as any).tx) {
|
||||
throw new Error("Unexpected response data format");
|
||||
@ -158,7 +157,7 @@ export class RestClient {
|
||||
return responseData as TxsResponse;
|
||||
}
|
||||
|
||||
public async postTx(tx: PostableBytes): Promise<PostTxsResponse> {
|
||||
public async postTx(tx: Uint8Array): Promise<PostTxsResponse> {
|
||||
const unmarshalled = unmarshalTx(tx, true);
|
||||
const params = {
|
||||
tx: unmarshalled.value,
|
25
packages/sdk/src/types.ts
Normal file
25
packages/sdk/src/types.ts
Normal file
@ -0,0 +1,25 @@
|
||||
import amino from "@tendermint/amino-js";
|
||||
|
||||
export type AminoTx = amino.Tx & { readonly value: amino.StdTx };
|
||||
|
||||
export function isAminoStdTx(txValue: amino.TxValue): txValue is amino.StdTx {
|
||||
const { memo, msg, fee, signatures } = txValue as amino.StdTx;
|
||||
return (
|
||||
typeof memo === "string" && Array.isArray(msg) && typeof fee === "object" && Array.isArray(signatures)
|
||||
);
|
||||
}
|
||||
|
||||
export interface TokenInfo {
|
||||
readonly denom: string;
|
||||
readonly ticker: string;
|
||||
/**
|
||||
* The number of fractional digits the token supports.
|
||||
*
|
||||
* A quantity is expressed as atomic units. 10^fractionalDigits of those
|
||||
* atomic units make up 1 token.
|
||||
*
|
||||
* E.g. in Ethereum 10^18 wei are 1 ETH and from the quantity 123000000000000000000
|
||||
* the last 18 digits are the fractional part and the rest the wole part.
|
||||
*/
|
||||
readonly fractionalDigits: number;
|
||||
}
|
12
packages/sdk/tsconfig.json
Normal file
12
packages/sdk/tsconfig.json
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"outDir": "build",
|
||||
"declarationDir": "build/types",
|
||||
"rootDir": "src"
|
||||
},
|
||||
"include": [
|
||||
"src/**/*"
|
||||
]
|
||||
}
|
3
packages/sdk/tslint.json
Normal file
3
packages/sdk/tslint.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"extends": "../../tslint.json"
|
||||
}
|
14
packages/sdk/typedoc.js
Normal file
14
packages/sdk/typedoc.js
Normal file
@ -0,0 +1,14 @@
|
||||
const packageJson = require("./package.json");
|
||||
|
||||
module.exports = {
|
||||
src: ["./src"],
|
||||
out: "docs",
|
||||
exclude: "**/*.spec.ts",
|
||||
target: "es6",
|
||||
name: `${packageJson.name} Documentation`,
|
||||
readme: "README.md",
|
||||
mode: "file",
|
||||
excludeExternals: true,
|
||||
excludeNotExported: true,
|
||||
excludePrivate: true,
|
||||
};
|
7
packages/sdk/types/decoding.d.ts
vendored
Normal file
7
packages/sdk/types/decoding.d.ts
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
import { Decimal } from "@iov/encoding";
|
||||
import amino from "@tendermint/amino-js";
|
||||
import { TokenInfo } from "./types";
|
||||
export declare function coinToDecimal(
|
||||
tokens: readonly TokenInfo[],
|
||||
coin: amino.Coin,
|
||||
): readonly [Decimal, string];
|
8
packages/sdk/types/encoding.d.ts
vendored
Normal file
8
packages/sdk/types/encoding.d.ts
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
import { Decimal } from "@iov/encoding";
|
||||
import amino from "@tendermint/amino-js";
|
||||
import { TokenInfo } from "./types";
|
||||
export declare function decimalToCoin(
|
||||
lookup: readonly TokenInfo[],
|
||||
value: Decimal,
|
||||
ticker: string,
|
||||
): amino.Coin;
|
4
packages/sdk/types/index.d.ts
vendored
Normal file
4
packages/sdk/types/index.d.ts
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
export { coinToDecimal } from "./decoding";
|
||||
export { decimalToCoin } from "./encoding";
|
||||
export { RestClient, TxsResponse } from "./restclient";
|
||||
export { AminoTx, isAminoStdTx, TokenInfo } from "./types";
|
@ -1,4 +1,3 @@
|
||||
import { Address, PostableBytes, TransactionId } from "@iov/bcp";
|
||||
import amino from "@tendermint/amino-js";
|
||||
import { AminoTx } from "./types";
|
||||
interface NodeInfo {
|
||||
@ -69,9 +68,9 @@ export declare class RestClient {
|
||||
nodeInfo(): Promise<NodeInfoResponse>;
|
||||
blocksLatest(): Promise<BlocksResponse>;
|
||||
blocks(height: number): Promise<BlocksResponse>;
|
||||
authAccounts(address: Address, height?: string): Promise<AuthAccountsResponse>;
|
||||
authAccounts(address: string, height?: string): Promise<AuthAccountsResponse>;
|
||||
txs(query: string): Promise<SearchTxsResponse>;
|
||||
txsById(id: TransactionId): Promise<TxsResponse>;
|
||||
postTx(tx: PostableBytes): Promise<PostTxsResponse>;
|
||||
txsById(id: string): Promise<TxsResponse>;
|
||||
postTx(tx: Uint8Array): Promise<PostTxsResponse>;
|
||||
}
|
||||
export {};
|
19
packages/sdk/types/types.d.ts
vendored
Normal file
19
packages/sdk/types/types.d.ts
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
import amino from "@tendermint/amino-js";
|
||||
export declare type AminoTx = amino.Tx & {
|
||||
readonly value: amino.StdTx;
|
||||
};
|
||||
export declare function isAminoStdTx(txValue: amino.TxValue): txValue is amino.StdTx;
|
||||
export interface TokenInfo {
|
||||
readonly denom: string;
|
||||
readonly ticker: string;
|
||||
/**
|
||||
* The number of fractional digits the token supports.
|
||||
*
|
||||
* A quantity is expressed as atomic units. 10^fractionalDigits of those
|
||||
* atomic units make up 1 token.
|
||||
*
|
||||
* E.g. in Ethereum 10^18 wei are 1 ETH and from the quantity 123000000000000000000
|
||||
* the last 18 digits are the fractional part and the rest the wole part.
|
||||
*/
|
||||
readonly fractionalDigits: number;
|
||||
}
|
19
packages/sdk/webpack.web.config.js
Normal file
19
packages/sdk/webpack.web.config.js
Normal file
@ -0,0 +1,19 @@
|
||||
const glob = require("glob");
|
||||
const path = require("path");
|
||||
const webpack = require("webpack");
|
||||
|
||||
const target = "web";
|
||||
const distdir = path.join(__dirname, "dist", "web");
|
||||
|
||||
module.exports = [
|
||||
{
|
||||
// bundle used for Karma tests
|
||||
target: target,
|
||||
entry: glob.sync("./build/**/*.spec.js"),
|
||||
output: {
|
||||
path: distdir,
|
||||
filename: "tests.js",
|
||||
},
|
||||
plugins: [new webpack.EnvironmentPlugin(["COSMOS_ENABLED"])],
|
||||
},
|
||||
];
|
Loading…
x
Reference in New Issue
Block a user