Merge pull request #353 from CosmWasm/stargate-client

Add initial setup for @cosmjs/stargate and StargateClient.getSequence
This commit is contained in:
Simon Warta 2020-08-06 15:29:10 +02:00 committed by GitHub
commit 6f58e7c355
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
55 changed files with 448 additions and 92 deletions

View File

@ -1,7 +1,7 @@
# This is a hand written dependencies file for depsight
# Render via `depsight --format png --output stargate-dependencies.png docs/stargate-dependencies.yml`
"@cosmjs/sdk40":
"@cosmjs/stargate":
- "@cosmjs/tendermint-rpc"
- "@cosmjs/proto-signing"

View File

@ -0,0 +1,18 @@
/* eslint-disable @typescript-eslint/naming-convention */
import { Message } from "protobufjs";
import { cosmosField } from "./decorator";
export class BaseAccount extends Message {
@cosmosField.bytes(1)
public readonly address?: Uint8Array;
@cosmosField.bytes(2)
public readonly pub_key?: Uint8Array;
@cosmosField.uint64(3)
public readonly account_number?: Long | number;
@cosmosField.uint64(4)
public readonly sequence?: Long | number;
}

View File

@ -0,0 +1,13 @@
import { google } from "./generated/codecimpl";
/**
* Decodes a serialized [google.protobuf.Any](https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/any.proto)
* and returns the components.
*/
export function decodeAny(serialized: Uint8Array): { readonly typeUrl: string; readonly value: Uint8Array } {
const envelope = google.protobuf.Any.decode(serialized);
return {
typeUrl: envelope.type_url,
value: envelope.value,
};
}

View File

@ -2,7 +2,7 @@
import { assert } from "@cosmjs/utils";
import { Message } from "protobufjs";
import { cosmosField, cosmosMessage } from "./decorator";
import { cosmosField, registered } from "./decorator";
import { cosmos, google } from "./generated/codecimpl";
import { Registry } from "./registry";
@ -15,13 +15,13 @@ describe("decorator demo", () => {
const typeUrl = "/demo.MsgDemo";
const myRegistry = new Registry();
@cosmosMessage(myRegistry, nestedTypeUrl)
@registered(myRegistry, nestedTypeUrl)
class MsgNestedDemo extends Message {
@cosmosField.string(1)
public readonly foo?: string;
}
@cosmosMessage(myRegistry, typeUrl)
@registered(myRegistry, typeUrl)
// eslint-disable-next-line @typescript-eslint/no-unused-vars
class MsgDemo extends Message {
@cosmosField.boolean(1)

View File

@ -7,7 +7,11 @@ function getTypeName(typeUrl: string): string {
return parts[parts.length - 1];
}
export function cosmosMessage(registry: Registry, typeUrl: string): TypeDecorator<any> {
/**
* A class decorator to register this type under the given type URL
* in the given registry.
*/
export function registered(registry: Registry, typeUrl: string): TypeDecorator<any> {
return (ctor: Constructor<Message<any>>) => {
const typeName = getTypeName(typeUrl);
const generatedType = util.decorateType(ctor, typeName);

View File

@ -0,0 +1,3 @@
export { BaseAccount } from "./accounts";
export { decodeAny } from "./any";
export { Coin } from "./msgs";

View File

@ -1,7 +1,7 @@
/* eslint-disable @typescript-eslint/naming-convention */
import { Message } from "protobufjs";
import { cosmosField, cosmosMessage } from "./decorator";
import { cosmosField, registered } from "./decorator";
import { Registry } from "./registry";
describe("registry magic demo", () => {
@ -10,13 +10,13 @@ describe("registry magic demo", () => {
const typeUrl = "/demo.MsgMagic";
const myRegistry = new Registry();
@cosmosMessage(myRegistry, nestedTypeUrl)
@registered(myRegistry, nestedTypeUrl)
class MsgNestedMagic extends Message {
@cosmosField.string(1)
public readonly foo?: string;
}
@cosmosMessage(myRegistry, typeUrl)
@registered(myRegistry, typeUrl)
class MsgMagic extends Message {
@cosmosField.boolean(1)
public readonly booleanDemo?: boolean;

View File

@ -1,12 +1,12 @@
/* eslint-disable @typescript-eslint/naming-convention */
import { Message } from "protobufjs";
import { cosmosField, cosmosMessage } from "./decorator";
import { cosmosField, registered } from "./decorator";
import { Registry } from "./registry";
export const defaultRegistry = new Registry();
@cosmosMessage(defaultRegistry, "/cosmos.Coin")
@registered(defaultRegistry, "/cosmos.Coin")
export class Coin extends Message {
@cosmosField.string(1)
public readonly denom?: string;
@ -15,7 +15,7 @@ export class Coin extends Message {
public readonly amount?: string;
}
@cosmosMessage(defaultRegistry, "/cosmos.bank.MsgSend")
@registered(defaultRegistry, "/cosmos.bank.MsgSend")
export class MsgSend extends Message {
@cosmosField.bytes(1)
public readonly from_address?: Uint8Array;

View File

@ -0,0 +1,8 @@
/// <reference types="long" />
import { Message } from "protobufjs";
export declare class BaseAccount extends Message {
readonly address?: Uint8Array;
readonly pub_key?: Uint8Array;
readonly account_number?: Long | number;
readonly sequence?: Long | number;
}

10
packages/proto-signing/types/any.d.ts vendored Normal file
View File

@ -0,0 +1,10 @@
/**
* Decodes a serialized [google.protobuf.Any](https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/any.proto)
* and returns the components.
*/
export declare function decodeAny(
serialized: Uint8Array,
): {
readonly typeUrl: string;
readonly value: Uint8Array;
};

View File

@ -1,6 +1,10 @@
import { Constructor, Message, TypeDecorator } from "protobufjs";
import { Registry } from "./registry";
export declare function cosmosMessage(registry: Registry, typeUrl: string): TypeDecorator<any>;
/**
* A class decorator to register this type under the given type URL
* in the given registry.
*/
export declare function registered(registry: Registry, typeUrl: string): TypeDecorator<any>;
/**
* Like PropertyDecorator from lib.es5.d.ts but without symbol support in propertyKey.
*/

View File

@ -0,0 +1,3 @@
export { BaseAccount } from "./accounts";
export { decodeAny } from "./any";
export { Coin } from "./msgs";

View File

@ -14,6 +14,6 @@ module.exports = [
path: distdir,
filename: "tests.js",
},
plugins: [new webpack.EnvironmentPlugin(["WASMD_ENABLED"])],
plugins: [new webpack.EnvironmentPlugin(["SIMAPP_ENABLED"])],
},
];

View File

@ -1,5 +0,0 @@
describe("dummy", () => {
it("has at least one test", () => {
expect(2).toEqual(2);
});
});

View File

View File

@ -1,6 +1,6 @@
# @cosmjs/sdk40
# @cosmjs/stargate
[![npm version](https://img.shields.io/npm/v/@cosmjs/sdk40.svg)](https://www.npmjs.com/package/@cosmjs/sdk40)
[![npm version](https://img.shields.io/npm/v/@cosmjs/stargate.svg)](https://www.npmjs.com/package/@cosmjs/stargate)
A client library for the Cosmos SDK 0.40.

View File

@ -1,5 +1,5 @@
{
"name": "@cosmjs/sdk40",
"name": "@cosmjs/stargate",
"private": true,
"version": "0.22.0",
"description": "Utilities for Cosmos SDK 0.40",
@ -18,7 +18,7 @@
],
"repository": {
"type": "git",
"url": "https://github.com/CosmWasm/cosmjs/tree/master/packages/sdk40"
"url": "https://github.com/CosmWasm/cosmjs/tree/master/packages/stargate"
},
"scripts": {
"docs": "typedoc --options typedoc.js",
@ -38,7 +38,10 @@
"pack-web": "yarn build-or-skip && webpack --mode development --config webpack.web.config.js"
},
"dependencies": {
"@cosmjs/encoding": "^0.22.0",
"@cosmjs/math": "^0.22.0",
"@cosmjs/proto-signing": "^0.22.0",
"@cosmjs/tendermint-rpc": "^0.22.0"
"@cosmjs/tendermint-rpc": "^0.22.0",
"@cosmjs/utils": "^0.22.0"
}
}

View File

@ -0,0 +1 @@
export { StargateClient } from "./stargateclient";

View File

@ -0,0 +1,56 @@
import { StargateClient } from "./stargateclient";
import { pendingWithoutSimapp, simapp, unused } from "./testutils.spec";
describe("StargateClient", () => {
describe("connect", () => {
it("works", async () => {
pendingWithoutSimapp();
const client = await StargateClient.connect(simapp.tendermintUrl);
expect(client).toBeTruthy();
client.disconnect();
});
});
describe("getSequence", () => {
it("works for unused account", async () => {
pendingWithoutSimapp();
const client = await StargateClient.connect(simapp.tendermintUrl);
const { accountNumber, sequence } = await client.getSequence(unused.address);
expect(accountNumber).toEqual(unused.accountNumber);
expect(sequence).toEqual(unused.sequence);
client.disconnect();
});
});
describe("getBalance", () => {
it("works for different existing balances", async () => {
pendingWithoutSimapp();
const client = await StargateClient.connect(simapp.tendermintUrl);
const response1 = await client.getBalance(unused.address, simapp.denomFee);
expect(response1).toEqual({
amount: unused.balanceFee,
denom: simapp.denomFee,
});
const response2 = await client.getBalance(unused.address, simapp.denomStaking);
expect(response2).toEqual({
amount: unused.balanceStaking,
denom: simapp.denomStaking,
});
client.disconnect();
});
it("returns null for non-existent balance", async () => {
pendingWithoutSimapp();
const client = await StargateClient.connect(simapp.tendermintUrl);
const response = await client.getBalance(unused.address, "gintonic");
expect(response).toBeNull();
client.disconnect();
});
});
});

View File

@ -0,0 +1,110 @@
/* eslint-disable @typescript-eslint/naming-convention */
import { Bech32, toAscii, toHex } from "@cosmjs/encoding";
import { Uint64 } from "@cosmjs/math";
import { BaseAccount, Coin, decodeAny } from "@cosmjs/proto-signing";
import { Client as TendermintClient } from "@cosmjs/tendermint-rpc";
import { assertDefined } from "@cosmjs/utils";
import Long from "long";
export interface GetSequenceResult {
readonly accountNumber: number;
readonly sequence: number;
}
function uint64FromProto(input: number | Long): Uint64 {
return Uint64.fromString(input.toString());
}
export class StargateClient {
private readonly tmClient: TendermintClient;
public static async connect(endpoint: string): Promise<StargateClient> {
const tmClient = await TendermintClient.connect(endpoint);
return new StargateClient(tmClient);
}
private constructor(tmClient: TendermintClient) {
this.tmClient = tmClient;
}
public async getSequence(address: string): Promise<GetSequenceResult> {
const binAddress = Bech32.decode(address).data;
// https://github.com/cosmos/cosmos-sdk/blob/8cab43c8120fec5200c3459cbf4a92017bb6f287/x/auth/types/keys.go#L29-L32
const accountKey = Uint8Array.from([0x01, ...binAddress]);
const responseData = await this.queryVerified("acc", accountKey);
const { typeUrl, value } = decodeAny(responseData);
switch (typeUrl) {
case "/cosmos.auth.BaseAccount": {
const { account_number, sequence } = BaseAccount.decode(value);
assertDefined(account_number);
assertDefined(sequence);
return {
accountNumber: uint64FromProto(account_number).toNumber(),
sequence: uint64FromProto(sequence).toNumber(),
};
}
default:
throw new Error(`Unsupported type: ${typeUrl}`);
}
}
public async getBalance(
address: string,
searchDenom: string,
): Promise<{
readonly denom: string;
readonly amount: string;
} | null> {
// balance key is a bit tricker, using some prefix stores
// https://github.com/cosmwasm/cosmos-sdk/blob/80f7ff62f79777a487d0c7a53c64b0f7e43c47b9/x/bank/keeper/view.go#L74-L77
// ("balances", binAddress, denom)
// it seem like prefix stores just do a dumb concat with the keys (no tricks to avoid overlap)
// https://github.com/cosmos/cosmos-sdk/blob/2879c0702c87dc9dd828a8c42b9224dc054e28ad/store/prefix/store.go#L61-L64
// https://github.com/cosmos/cosmos-sdk/blob/2879c0702c87dc9dd828a8c42b9224dc054e28ad/store/prefix/store.go#L37-L43
const binAddress = Bech32.decode(address).data;
const bankKey = Uint8Array.from([...toAscii("balances"), ...binAddress, ...toAscii(searchDenom)]);
const responseData = await this.queryVerified("bank", bankKey);
const { amount, denom } = Coin.decode(responseData);
assertDefined(amount);
assertDefined(denom);
if (denom === "") {
return null;
} else {
return {
amount: amount,
denom: denom,
};
}
}
public disconnect(): void {
this.tmClient.disconnect();
}
private async queryVerified(store: string, key: Uint8Array): Promise<Uint8Array> {
const response = await this.tmClient.abciQuery({
// we need the StoreKey for the module, not the module name
// https://github.com/cosmos/cosmos-sdk/blob/8cab43c8120fec5200c3459cbf4a92017bb6f287/x/auth/types/keys.go#L12
path: `/store/${store}/key`,
data: key,
prove: true,
});
if (response.code) {
throw new Error(`Query failed with (${response.code}): ${response.log}`);
}
// TODO: better way to compare?
if (toHex(response.key) !== toHex(key)) {
throw new Error(`Response key ${toHex(response.key)} doesn't match query key ${toHex(key)}`);
}
// TODO: implement proof verification
// https://github.com/CosmWasm/cosmjs/issues/347
return response.value;
}
}

View File

@ -0,0 +1,25 @@
export function pendingWithoutSimapp(): void {
if (!process.env.SIMAPP_ENABLED) {
return pending("Set SIMAPP_ENABLED to enable Simapp based tests");
}
}
export const simapp = {
tendermintUrl: "localhost:26657",
chainId: "simd-testing",
denomStaking: "ustake",
denomFee: "ucosm",
};
/** Unused account */
export const unused = {
pubkey: {
type: "tendermint/PubKeySecp256k1",
value: "ArkCaFUJ/IH+vKBmNRCdUVl3mCAhbopk9jjW4Ko4OfRQ",
},
address: "cosmos1cjsxept9rkggzxztslae9ndgpdyt2408lk850u",
accountNumber: 16,
sequence: 0,
balanceStaking: "10000000", // 10 STAKE
balanceFee: "1000000000", // 1000 COSM
};

1
packages/stargate/types/index.d.ts vendored Normal file
View File

@ -0,0 +1 @@
export { StargateClient } from "./stargateclient";

View File

@ -0,0 +1,19 @@
export interface GetSequenceResult {
readonly accountNumber: number;
readonly sequence: number;
}
export declare class StargateClient {
private readonly tmClient;
static connect(endpoint: string): Promise<StargateClient>;
private constructor();
getSequence(address: string): Promise<GetSequenceResult>;
getBalance(
address: string,
searchDenom: string,
): Promise<{
readonly denom: string;
readonly amount: string;
} | null>;
disconnect(): void;
private queryVerified;
}

View File

@ -14,6 +14,6 @@ module.exports = [
path: distdir,
filename: "tests.js",
},
plugins: [new webpack.EnvironmentPlugin(["WASMD_ENABLED"])],
plugins: [new webpack.EnvironmentPlugin(["SIMAPP_ENABLED"])],
},
];

View File

@ -0,0 +1,52 @@
import { assertDefined } from "./assert";
describe("assert", () => {
describe("assertDefined", () => {
it("passes for simple values", () => {
{
const value: number | undefined = 123;
assertDefined(value);
expect(value).toEqual(123);
}
{
const value: string | undefined = "abc";
assertDefined(value);
expect(value).toEqual("abc");
}
});
it("passes for falsy values", () => {
{
const value: number | undefined = 0;
assertDefined(value);
expect(value).toEqual(0);
}
{
const value: string | undefined = "";
assertDefined(value);
expect(value).toEqual("");
}
{
const value: null | undefined = null;
assertDefined(value);
expect(value).toEqual(null);
}
});
it("throws for undefined values", () => {
{
const value: number | undefined = undefined;
expect(() => assertDefined(value)).toThrowError("value is undefined");
}
{
let value: string | undefined;
expect(() => assertDefined(value)).toThrowError("value is undefined");
}
});
it("throws with custom message", () => {
const value: number | undefined = undefined;
expect(() => assertDefined(value, "Bug in the data source")).toThrowError("Bug in the data source");
});
});
});

View File

@ -4,3 +4,9 @@ export function assert(condition: any, msg?: string): asserts condition {
throw new Error(msg || "condition is not truthy");
}
}
export function assertDefined<T>(value: T | undefined, msg?: string): asserts value is T {
if (value === undefined) {
throw new Error(msg || "value is undefined");
}
}

View File

@ -1,3 +1,3 @@
export { assert } from "./assert";
export { assert, assertDefined } from "./assert";
export { sleep } from "./sleep";
export { isNonNullObject, isUint8Array } from "./typechecks";

View File

@ -1 +1,2 @@
export declare function assert(condition: any, msg?: string): asserts condition;
export declare function assertDefined<T>(value: T | undefined, msg?: string): asserts value is T;

View File

@ -1,3 +1,3 @@
export { assert } from "./assert";
export { assert, assertDefined } from "./assert";
export { sleep } from "./sleep";
export { isNonNullObject, isUint8Array } from "./typechecks";

View File

@ -3,11 +3,16 @@ set -o errexit -o nounset
command -v shellcheck > /dev/null && shellcheck "$0"
PASSWORD=${PASSWORD:-1234567890}
STAKE=${STAKE_TOKEN:-ustake}
FEE=${FEE_TOKEN:-ucosm}
CHAIN_ID=${CHAIN_ID:-simd-testing}
MONIKER=${MONIKER:-simd-moniker}
# The staking and the fee tokens. The supply of the staking token is low compared to the fee token (factor 100).
STAKE=${STAKE_TOKEN:-ustake}
FEE=${FEE_TOKEN:-ucosm}
# 10 STAKE and 1000 COSM
START_BALANCE="10000000$STAKE,1000000000$FEE"
echo "Creating genesis ..."
simd init --chain-id "$CHAIN_ID" "$MONIKER"
sed -i "s/\"stake\"/\"$STAKE\"/" "$HOME"/.simapp/config/genesis.json # staking/governance token is hardcoded in config, change this
@ -18,15 +23,16 @@ if ! simd keys show validator 2> /dev/null; then
(echo "$PASSWORD"; echo "$PASSWORD") | simd keys add validator
fi
# hardcode the validator account for this instance
echo "$PASSWORD" | simd add-genesis-account validator "1000000000$STAKE,1000000000$FEE"
echo "$PASSWORD" | simd add-genesis-account validator "$START_BALANCE"
echo "Setting up accounts ..."
# (optionally) add a few more genesis accounts
for addr in "$@"; do
echo "$addr"
simd add-genesis-account "$addr" "1000000000$STAKE,1000000000$FEE"
simd add-genesis-account "$addr" "$START_BALANCE"
done
echo "Creating genesis tx ..."
(echo "$PASSWORD"; echo "$PASSWORD"; echo "$PASSWORD") | simd gentx validator --offline --amount "250000000$STAKE" --chain-id "$CHAIN_ID" --moniker="$MONIKER"
SELF_DELEGATION="3000000$STAKE" # 3 STAKE (leads to a voting power of 3)
(echo "$PASSWORD"; echo "$PASSWORD"; echo "$PASSWORD") | simd gentx validator --offline --amount "$SELF_DELEGATION" --chain-id "$CHAIN_ID" --moniker="$MONIKER"
simd collect-gentxs

View File

@ -1 +0,0 @@
eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjcmVhdGVkIjoiMjAyMC0wOC0wNSAxMDoxOTo0Ni42NTgyNTg5ICswMDAwIFVUQyBtPSswLjE3NDU1MDUwMSIsImVuYyI6IkEyNTZHQ00iLCJwMmMiOjgxOTIsInAycyI6IlNXQmdBYzlDVkw2YVdFNloifQ.1WcD0GRVorQbC7411RbZwvZdtSG9ZcipAXCgXzMCORWq4tE4ke8lJA.UHmYdum53TSPA169.HW0l0KFZS4GQ9_ss_4tSt7d_cv3qjixehXxAtXEVUEUhAV8JViouQYD1-VELy1mtd7r5Ld1L9q6l0X6B2OGmc6I9bQZSB1G3KSH9WCvTvigiTnYeOrGwtTy8ZxkrC5vWj0rkaADqd3Hmc3hZsovxhlUqMcLxP7ZXET0NjNWu9auNVEevt_jgKyqttqc2zMEER3wYXVTVSm0vHo723vhFIRJNF6hp1p0u1KmyaZ7q1Di_2wb1fUrubxzU.dr7x1R5fIfDzjGgU-w7PAg

View File

@ -43,7 +43,7 @@ inter-block-cache = true
[telemetry]
# Prefixed with keys to separate services
# Prefixed with keys to separate services.
service-name = ""
# Enabled enables the application telemetry functionality. When enabled,
@ -51,13 +51,13 @@ service-name = ""
# other sinks such as Prometheus.
enabled = false
# Enable prefixing gauge values with hostname
# Enable prefixing gauge values with hostname.
enable-hostname = false
# Enable adding hostname to labels
# Enable adding hostname to labels.
enable-hostname-label = false
# Enable adding service to labels
# Enable adding service to labels.
enable-service-label = false
# PrometheusRetentionTime, when positive, enables a Prometheus metrics sink.
@ -83,20 +83,32 @@ enable = true
# Swagger defines if swagger documentation should automatically be registered.
swagger = false
# Address defines the API server to listen on
# Address defines the API server to listen on.
address = "tcp://0.0.0.0:1317"
# MaxOpenConnections defines the number of maximum open connections
# MaxOpenConnections defines the number of maximum open connections.
max-open-connections = 1000
# RPCReadTimeout defines the Tendermint RPC read timeout (in seconds)
# RPCReadTimeout defines the Tendermint RPC read timeout (in seconds).
rpc-read-timeout = 10
# RPCWriteTimeout defines the Tendermint RPC write timeout (in seconds)
# RPCWriteTimeout defines the Tendermint RPC write timeout (in seconds).
rpc-write-timeout = 0
# RPCMaxBodyBytes defines the Tendermint maximum response body (in bytes)
# RPCMaxBodyBytes defines the Tendermint maximum response body (in bytes).
rpc-max-body-bytes = 1000000
# EnableUnsafeCORS defines if CORS should be enabled (unsafe - use it at your own risk)
# EnableUnsafeCORS defines if CORS should be enabled (unsafe - use it at your own risk).
enabled-unsafe-cors = true
###############################################################################
### gRPC Configuration ###
###############################################################################
[grpc]
# Enable defines if the gRPC server should be enabled.
enable = true
# Address defines the gRPC server address to bind to.
address = "0.0.0.0:9090"

View File

@ -6,7 +6,7 @@
{
"type": "cosmos-sdk/BaseAccount",
"value": {
"address": "cosmos1320amqmuysc88vuf6unrdprft0kvqdshapg46s"
"address": "cosmos1lv5lq7qjr42attsdma622whwa7v0rc2d4pful8"
}
},
{
@ -130,7 +130,7 @@
"denom": "ucosm"
},
{
"amount": "1000000000",
"amount": "10000000",
"denom": "ustake"
}
]
@ -143,7 +143,7 @@
"denom": "ucosm"
},
{
"amount": "1000000000",
"amount": "10000000",
"denom": "ustake"
}
]
@ -156,7 +156,7 @@
"denom": "ucosm"
},
{
"amount": "1000000000",
"amount": "10000000",
"denom": "ustake"
}
]
@ -169,7 +169,7 @@
"denom": "ucosm"
},
{
"amount": "1000000000",
"amount": "10000000",
"denom": "ustake"
}
]
@ -182,7 +182,7 @@
"denom": "ucosm"
},
{
"amount": "1000000000",
"amount": "10000000",
"denom": "ustake"
}
]
@ -195,7 +195,7 @@
"denom": "ucosm"
},
{
"amount": "1000000000",
"amount": "10000000",
"denom": "ustake"
}
]
@ -208,20 +208,7 @@
"denom": "ucosm"
},
{
"amount": "1000000000",
"denom": "ustake"
}
]
},
{
"address": "cosmos1320amqmuysc88vuf6unrdprft0kvqdshapg46s",
"coins": [
{
"amount": "1000000000",
"denom": "ucosm"
},
{
"amount": "1000000000",
"amount": "10000000",
"denom": "ustake"
}
]
@ -234,7 +221,7 @@
"denom": "ucosm"
},
{
"amount": "1000000000",
"amount": "10000000",
"denom": "ustake"
}
]
@ -247,7 +234,7 @@
"denom": "ucosm"
},
{
"amount": "1000000000",
"amount": "10000000",
"denom": "ustake"
}
]
@ -260,7 +247,7 @@
"denom": "ucosm"
},
{
"amount": "1000000000",
"amount": "10000000",
"denom": "ustake"
}
]
@ -273,7 +260,7 @@
"denom": "ucosm"
},
{
"amount": "1000000000",
"amount": "10000000",
"denom": "ustake"
}
]
@ -286,7 +273,7 @@
"denom": "ucosm"
},
{
"amount": "1000000000",
"amount": "10000000",
"denom": "ustake"
}
]
@ -299,7 +286,7 @@
"denom": "ucosm"
},
{
"amount": "1000000000",
"amount": "10000000",
"denom": "ustake"
}
]
@ -312,7 +299,7 @@
"denom": "ucosm"
},
{
"amount": "1000000000",
"amount": "10000000",
"denom": "ustake"
}
]
@ -325,7 +312,7 @@
"denom": "ucosm"
},
{
"amount": "1000000000",
"amount": "10000000",
"denom": "ustake"
}
]
@ -338,7 +325,7 @@
"denom": "ucosm"
},
{
"amount": "1000000000",
"amount": "10000000",
"denom": "ustake"
}
]
@ -350,8 +337,21 @@
"amount": "1000000000",
"denom": "ucosm"
},
{
"amount": "10000000",
"denom": "ustake"
}
]
},
{
"address": "cosmos1lv5lq7qjr42attsdma622whwa7v0rc2d4pful8",
"coins": [
{
"amount": "1000000000",
"denom": "ucosm"
},
{
"amount": "10000000",
"denom": "ustake"
}
]
@ -407,13 +407,13 @@
}
},
"public_key": {
"secp256k1": "AmT77hhRkycGp9kUxEwOhlHsNl6owW7X7g+nJtrFTlQO"
"secp256k1": "A7bPBNzzcLkg9D6sSUIpq6qOhtWTKnJELef/5yZfr4xH"
}
}
]
},
"body": {
"memo": "dc544239a7cbbf5cdde8bbde243fcd9a4195eb70@172.17.0.2:26656",
"memo": "d593cd9e2f88b70d57ffc8c28768b555b9acb5fc@172.17.0.3:26656",
"messages": [
{
"@type": "/cosmos.staking.MsgCreateValidator",
@ -422,22 +422,22 @@
"max_rate": "0.200000000000000000",
"rate": "0.100000000000000000"
},
"delegator_address": "cosmos1320amqmuysc88vuf6unrdprft0kvqdshapg46s",
"delegator_address": "cosmos1lv5lq7qjr42attsdma622whwa7v0rc2d4pful8",
"description": {
"moniker": "simd-moniker"
},
"min_self_delegation": "1",
"pubkey": "cosmosvalconspub1zcjduepqeg7s6rcwmnsquupys6a8cd4402drnvzyv84nfakvyzdgzz6qzumqkavfer",
"validator_address": "cosmosvaloper1320amqmuysc88vuf6unrdprft0kvqdshc4uqkr",
"pubkey": "cosmosvalconspub1zcjduepqv3sruyer5xmurpxyptu4ll3efjan3lmaajf3fxg9axe895ppj9kqtyk2vf",
"validator_address": "cosmosvaloper1lv5lq7qjr42attsdma622whwa7v0rc2ds4afn5",
"value": {
"amount": "250000000",
"amount": "3000000",
"denom": "ustake"
}
}
]
},
"signatures": [
"yqsTm7NZStlzxEUnVQCFxZErdba2r5Slf2/Gf/DTpSNUg+EzhUqWD75c9ynAXPgDz4XSP9ys7PCATegvACkxEQ=="
"5gBipu7M14zMjn2t6pBxM+DprcDR44RW4Eylc1wVp4Ikem0duRVnvWDE+B0gZ9+LY0QrgPcEmm6aXzPGiN3SKQ=="
]
}
]
@ -547,5 +547,5 @@
]
}
},
"genesis_time": "2020-08-05T10:19:46.2922652Z"
"genesis_time": "2020-08-06T13:08:49.5288713Z"
}

View File

@ -0,0 +1 @@
{"body":{"messages":[{"@type":"/cosmos.staking.MsgCreateValidator","description":{"moniker":"simd-moniker"},"commission":{"rate":"0.100000000000000000","max_rate":"0.200000000000000000","max_change_rate":"0.010000000000000000"},"min_self_delegation":"1","delegator_address":"cosmos1lv5lq7qjr42attsdma622whwa7v0rc2d4pful8","validator_address":"cosmosvaloper1lv5lq7qjr42attsdma622whwa7v0rc2ds4afn5","pubkey":"cosmosvalconspub1zcjduepqv3sruyer5xmurpxyptu4ll3efjan3lmaajf3fxg9axe895ppj9kqtyk2vf","value":{"denom":"ustake","amount":"3000000"}}],"memo":"d593cd9e2f88b70d57ffc8c28768b555b9acb5fc@172.17.0.3:26656"},"auth_info":{"signer_infos":[{"public_key":{"secp256k1":"A7bPBNzzcLkg9D6sSUIpq6qOhtWTKnJELef/5yZfr4xH"},"mode_info":{"single":{"mode":"SIGN_MODE_DIRECT"}}}],"fee":{"gas_limit":"200000"}},"signatures":["5gBipu7M14zMjn2t6pBxM+DprcDR44RW4Eylc1wVp4Ikem0duRVnvWDE+B0gZ9+LY0QrgPcEmm6aXzPGiN3SKQ=="]}

View File

@ -1 +0,0 @@
{"body":{"messages":[{"@type":"/cosmos.staking.MsgCreateValidator","description":{"moniker":"simd-moniker"},"commission":{"rate":"0.100000000000000000","max_rate":"0.200000000000000000","max_change_rate":"0.010000000000000000"},"min_self_delegation":"1","delegator_address":"cosmos1320amqmuysc88vuf6unrdprft0kvqdshapg46s","validator_address":"cosmosvaloper1320amqmuysc88vuf6unrdprft0kvqdshc4uqkr","pubkey":"cosmosvalconspub1zcjduepqeg7s6rcwmnsquupys6a8cd4402drnvzyv84nfakvyzdgzz6qzumqkavfer","value":{"denom":"ustake","amount":"250000000"}}],"memo":"dc544239a7cbbf5cdde8bbde243fcd9a4195eb70@172.17.0.2:26656"},"auth_info":{"signer_infos":[{"public_key":{"secp256k1":"AmT77hhRkycGp9kUxEwOhlHsNl6owW7X7g+nJtrFTlQO"},"mode_info":{"single":{"mode":"SIGN_MODE_DIRECT"}}}],"fee":{"gas_limit":"200000"}},"signatures":["yqsTm7NZStlzxEUnVQCFxZErdba2r5Slf2/Gf/DTpSNUg+EzhUqWD75c9ynAXPgDz4XSP9ys7PCATegvACkxEQ=="]}

View File

@ -1 +1 @@
{"priv_key":{"type":"tendermint/PrivKeyEd25519","value":"R89SQVGfuYzV/14lfUPXYCIMkNJW+EtnuHOCurizEFtu6xO3ooXongYxM4C6qYqBu9NnIDefYhOqWu6Yfm1/CA=="}}
{"priv_key":{"type":"tendermint/PrivKeyEd25519","value":"GibkBGABoqDhct1gyZLYgUQ3q9afc7jSzBEZKYV3/Rql7r3LMmDVuXZgwdeDitunnWIm6KTJ9/yrdIbOnxGryg=="}}

View File

@ -1,11 +1,11 @@
{
"address": "B1CF8F1750F16AC21D47A6B601B60366C72D6453",
"address": "774A0C3FA22BFB35E7A62C33A1C58697CADE1427",
"pub_key": {
"type": "tendermint/PubKeyEd25519",
"value": "yj0NDw7c4A5wJIa6fDa1epo5sERh6zT2zCCagQtAFzY="
"value": "ZGA+EyOht8GExAr5X/45TLs4/33skxSZBemyctAhkWw="
},
"priv_key": {
"type": "tendermint/PrivKeyEd25519",
"value": "uOMarp66JsGXM7ZjNStlghSvEQ1ZIWyPif9c9OCTguvKPQ0PDtzgDnAkhrp8NrV6mjmwRGHrNPbMIJqBC0AXNg=="
"value": "4rVHumai2XQZ+hSsUphYlJNkcjQCTguaZ2e7LPXNoCZkYD4TI6G3wYTECvlf/jlMuzj/feyTFJkF6bJy0CGRbA=="
}
}

View File

@ -0,0 +1 @@
eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjcmVhdGVkIjoiMjAyMC0wOC0wNiAxMzowODo1MC40MzYzMjQ2ICswMDAwIFVUQyBtPSswLjUzMzMxNTYwMSIsImVuYyI6IkEyNTZHQ00iLCJwMmMiOjgxOTIsInAycyI6IjlYak9JRDJHMkZMM2VXcDkifQ.ZVjb1WogjVvyIXk5IkrZclppwwc0MExREIrkRFqxkjyE4k0V68APMQ.NJdR86VIEOZ0cVLL.7PukY7zG6I0gDzhjvkY8QbQfofLAVJEcVFjRkxodcrxH4UNiCkURbklOuyOgcKEJcY12TYSBXUjoWUMy15i0_O4uMhWwx_xVWgaTRyjBB6UVC6fchYpwHiYnJStrMTsTTIEd_PMg01M2G8IR4QyhJtDju9W3AEbnnBdKktDuseAe0hyr7BwJHFXm9CU-sXU3JzFQ62szLpu-CaUBV_7xJusFjwDosfyom4r-keH3Y7CmPqF_-W3VY8DU.HMvilHIyoRuJGKvKNsfX3A

View File

@ -1 +1 @@
$2a$10$ErqhOjVIXPK3JrM8uP0sNeaknxSAfD4pfcjJx3IITELAHeWcU06b.
$2a$10$.3rbMOvLm5FQrKE5eNnNB.GC6N8/klYIQpJjLIl2K6DsBkGPkytWe

View File

@ -1 +1 @@
eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjcmVhdGVkIjoiMjAyMC0wOC0wNSAxMDoxOTo0Ni42NDYyNDUyICswMDAwIFVUQyBtPSswLjE2MjUzNTgwMSIsImVuYyI6IkEyNTZHQ00iLCJwMmMiOjgxOTIsInAycyI6IlB3X1RBYkRxR2tXZWZHU0kifQ.HtxQbkSoUXhddjkf94sYO3CmLbPXn2FonMQZrsLJJqKgZb_4Ghm5kg.ky6uwdJhGhAhBMDD.6FCMDj06Lk6xVT1Lpz2ls-gpWDT_F5kOAB_KNeef6zhXbjDEa0VGWY97R_Yy-_NXOFkxz4juQKrPm2IDsFucmhWrtk4A2DzKQ81FP5Ev8K9_a2vDoS5eL28EWm0h5eIoPhVbbDx5mw04lKwD_8mBX5KqvacWCJo0GrD3B1W2ts_n_osHI_Pts6FolMRM5Hp3X3BEJiN1qshE39-0q2MWkh3b2VP4Wn2UE5sFR2UA0ChBRLzVl4Ie5YuPOJMSDL7xFsRFhVNVp5BNn6bv03gHyz2fX2qwOC1xMUu9memlc_Auj818WrLNWxVUqIfKvVuwtNVTpLTBoK7Lqo17dNy44WDt_Wn-eA6wtkP7j2bu2Dq2iwZu.QoGCOja4LFZ90nZJUcUNzA
eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjcmVhdGVkIjoiMjAyMC0wOC0wNiAxMzowODo1MC40MTQ5MTA1ICswMDAwIFVUQyBtPSswLjUxMTkwMjAwMSIsImVuYyI6IkEyNTZHQ00iLCJwMmMiOjgxOTIsInAycyI6IkxiNS1RblpLdlFBaDVmUHEifQ.shxbGlGbejxdwAuUWE729l71nOLUtBqnE-1nDqc3bf-qzZ-ZvFP6rg.B-M7fYzRF9A91x4q.XWjXdGvP-CsRxFwrolUdq6bY5cz2i5lqSggCPdUyYuXn6WVglEEdsxbyl_Et7fZ8ppAgFsWaj19ELxYr4ewwvA4r2TReShcDk51jz8tFLTO6aCOh2F6rjn-fi5DUfcimfsipzu-x-FvCSKpQ3XB6PlwfJ5lLkoSoeqX_WJS6Zq0v7VI9D_WvSD5Q6FX1LnhrchndlZ33sBVwCjsp0GbEAOeDaYnnRexfh05k90_jc7DXHdKNI3o8a8q5pQR3CfnkHpIVlRairnrt68GEWMrCT-DhILGUP7KVJsYIadfODU_rOUqkJaAmlAMHPoWOncWaaCnk2hASwfbG8yNyREJ9UxdaXhih8ZwT1IWSTp2NkHcb1uZf.aXzyufH2vuWPQms3wVMuug

View File

@ -3,11 +3,16 @@ set -o errexit -o nounset
command -v shellcheck > /dev/null && shellcheck "$0"
PASSWORD=${PASSWORD:-1234567890}
STAKE=${STAKE_TOKEN:-ustake}
FEE=${FEE_TOKEN:-ucosm}
CHAIN_ID=${CHAIN_ID:-simd-testing}
MONIKER=${MONIKER:-simd-moniker}
# The staking and the fee tokens. The supply of the staking token is low compared to the fee token (factor 100).
STAKE=${STAKE_TOKEN:-ustake}
FEE=${FEE_TOKEN:-ucosm}
# 10 STAKE and 1000 COSM
START_BALANCE="10000000$STAKE,1000000000$FEE"
echo "Creating genesis ..."
simd init --chain-id "$CHAIN_ID" "$MONIKER"
sed -i "s/\"stake\"/\"$STAKE\"/" "$HOME"/.simapp/config/genesis.json # staking/governance token is hardcoded in config, change this
@ -18,15 +23,16 @@ if ! simd keys show validator 2> /dev/null; then
(echo "$PASSWORD"; echo "$PASSWORD") | simd keys add validator
fi
# hardcode the validator account for this instance
echo "$PASSWORD" | simd add-genesis-account validator "1000000000$STAKE,1000000000$FEE"
echo "$PASSWORD" | simd add-genesis-account validator "$START_BALANCE"
echo "Setting up accounts ..."
# (optionally) add a few more genesis accounts
for addr in "$@"; do
echo "$addr"
simd add-genesis-account "$addr" "1000000000$STAKE,1000000000$FEE"
simd add-genesis-account "$addr" "$START_BALANCE"
done
echo "Creating genesis tx ..."
(echo "$PASSWORD"; echo "$PASSWORD"; echo "$PASSWORD") | simd gentx validator --offline --amount "250000000$STAKE" --chain-id "$CHAIN_ID" --moniker="$MONIKER"
SELF_DELEGATION="3000000$STAKE" # 3 STAKE (leads to a voting power of 3)
(echo "$PASSWORD"; echo "$PASSWORD"; echo "$PASSWORD") | simd gentx validator --offline --amount "$SELF_DELEGATION" --chain-id "$CHAIN_ID" --moniker="$MONIKER"
simd collect-gentxs