diff --git a/packages/sdk38/src/index.ts b/packages/sdk38/src/index.ts index ff94bed9..81ddccea 100644 --- a/packages/sdk38/src/index.ts +++ b/packages/sdk38/src/index.ts @@ -63,10 +63,14 @@ export { setupGovExtension, setupMintExtension, setupSlashingExtension, + setupStakingExtension, setupSupplyExtension, SlashingExtension, SlashingParametersResponse, SlashingSigningInfosResponse, + StakingExtension, + StakingParametersResponse, + StakingPoolResponse, SupplyExtension, TxsResponse, } from "./lcdapi"; diff --git a/packages/sdk38/src/lcdapi/base.ts b/packages/sdk38/src/lcdapi/base.ts index 2b7bd112..2e31b20a 100644 --- a/packages/sdk38/src/lcdapi/base.ts +++ b/packages/sdk38/src/lcdapi/base.ts @@ -63,7 +63,7 @@ interface BlockId { // } } -interface BlockHeader { +export interface BlockHeader { readonly version: { readonly block: string; readonly app: string; diff --git a/packages/sdk38/src/lcdapi/index.ts b/packages/sdk38/src/lcdapi/index.ts index 742a2a1b..5a3fc580 100644 --- a/packages/sdk38/src/lcdapi/index.ts +++ b/packages/sdk38/src/lcdapi/index.ts @@ -42,6 +42,25 @@ export { SlashingParametersResponse, SlashingSigningInfosResponse, } from "./slashing"; +export { + setupStakingExtension, + StakingDelegatorDelegationsResponse, + StakingDelegatorUnbondingDelegationsResponse, + StakingDelegatorTransactionsResponse, + StakingDelegatorValidatorsResponse, + StakingDelegatorValidatorResponse, + StakingDelegationResponse, + StakingUnbondingDelegationResponse, + StakingRedelegationsResponse, + StakingValidatorsResponse, + StakingValidatorResponse, + StakingValidatorDelegationsResponse, + StakingValidatorUnbondingDelegationsResponse, + StakingHistoricalInfoResponse, + StakingExtension, + StakingParametersResponse, + StakingPoolResponse, +} from "./staking"; export { setupSupplyExtension, SupplyExtension, TotalSupplyAllResponse, TotalSupplyResponse } from "./supply"; // diff --git a/packages/sdk38/src/lcdapi/lcdclient.ts b/packages/sdk38/src/lcdapi/lcdclient.ts index 3ea8d844..f62b14a1 100644 --- a/packages/sdk38/src/lcdapi/lcdclient.ts +++ b/packages/sdk38/src/lcdapi/lcdclient.ts @@ -219,8 +219,8 @@ export class LcdClient { this.broadcastMode = broadcastMode; } - public async get(path: string): Promise { - const { data } = await this.client.get(path).catch(parseAxiosError); + public async get(path: string, params?: Record): Promise { + const { data } = await this.client.get(path, { params }).catch(parseAxiosError); if (data === null) { throw new Error("Received null response from server"); } diff --git a/packages/sdk38/src/lcdapi/staking.spec.ts b/packages/sdk38/src/lcdapi/staking.spec.ts new file mode 100644 index 00000000..dfe91717 --- /dev/null +++ b/packages/sdk38/src/lcdapi/staking.spec.ts @@ -0,0 +1,490 @@ +/* eslint-disable @typescript-eslint/naming-convention */ +import { assert, sleep } from "@cosmjs/utils"; + +import { coin, coins } from "../coins"; +import { isPostTxFailure } from "../cosmosclient"; +import { makeSignBytes } from "../encoding"; +import { MsgDelegate, MsgUndelegate } from "../msgs"; +import { SigningCosmosClient } from "../signingcosmosclient"; +import { + bigDecimalMatcher, + dateTimeStampMatcher, + faucet, + nonNegativeIntegerMatcher, + pendingWithoutWasmd, + validatorAddress, + wasmd, + wasmdEnabled, +} from "../testutils.spec"; +import { Secp256k1Wallet } from "../wallet"; +import { LcdClient } from "./lcdclient"; +import { BondStatus, setupStakingExtension, StakingExtension } from "./staking"; + +function makeStakingClient(apiUrl: string): LcdClient & StakingExtension { + return LcdClient.withExtensions({ apiUrl }, setupStakingExtension); +} + +describe("StakingExtension", () => { + const defaultFee = { + amount: coins(25000, "ucosm"), + gas: "1500000", // 1.5 million + }; + + beforeAll(async () => { + if (wasmdEnabled()) { + const wallet = await Secp256k1Wallet.fromMnemonic(faucet.mnemonic); + const client = new SigningCosmosClient(wasmd.endpoint, faucet.address, wallet, {}); + + const chainId = await client.getChainId(); + { + const msg: MsgDelegate = { + type: "cosmos-sdk/MsgDelegate", + value: { + delegator_address: faucet.address, + validator_address: validatorAddress, + amount: coin(25000, "ustake"), + }, + }; + const memo = "Test delegation for wasmd"; + const { accountNumber, sequence } = await client.getSequence(); + const signBytes = makeSignBytes([msg], defaultFee, chainId, memo, accountNumber, sequence); + const signature = await wallet.sign(faucet.address, signBytes); + const tx = { + msg: [msg], + fee: defaultFee, + memo: memo, + signatures: [signature], + }; + + const receipt = await client.postTx(tx); + assert(!isPostTxFailure(receipt)); + } + { + const msg: MsgUndelegate = { + type: "cosmos-sdk/MsgUndelegate", + value: { + delegator_address: faucet.address, + validator_address: validatorAddress, + amount: coin(100, "ustake"), + }, + }; + const memo = "Test undelegation for wasmd"; + const { accountNumber, sequence } = await client.getSequence(); + const signBytes = makeSignBytes([msg], defaultFee, chainId, memo, accountNumber, sequence); + const signature = await wallet.sign(faucet.address, signBytes); + const tx = { + msg: [msg], + fee: defaultFee, + memo: memo, + signatures: [signature], + }; + + const receipt = await client.postTx(tx); + assert(!isPostTxFailure(receipt)); + } + + await sleep(75); // wait until transactions are indexed + } + }); + + describe("delegatorDelegations", () => { + it("works", async () => { + pendingWithoutWasmd(); + const client = makeStakingClient(wasmd.endpoint); + const response = await client.staking.delegatorDelegations(faucet.address); + expect(response).toEqual({ + height: jasmine.stringMatching(nonNegativeIntegerMatcher), + result: [ + { + delegator_address: faucet.address, + validator_address: validatorAddress, + shares: jasmine.stringMatching(bigDecimalMatcher), + balance: { denom: "ustake", amount: jasmine.stringMatching(nonNegativeIntegerMatcher) }, + }, + ], + }); + }); + }); + + describe("delegatorUnbondingDelegations", () => { + it("works", async () => { + pendingWithoutWasmd(); + const client = makeStakingClient(wasmd.endpoint); + const { height, result } = await client.staking.delegatorUnbondingDelegations(faucet.address); + expect(height).toMatch(nonNegativeIntegerMatcher); + assert(result); + expect(result).toEqual([ + { + delegator_address: faucet.address, + validator_address: validatorAddress, + entries: jasmine.arrayContaining([ + { + creation_height: jasmine.stringMatching(nonNegativeIntegerMatcher), + completion_time: jasmine.stringMatching(dateTimeStampMatcher), + initial_balance: "100", + balance: "100", + }, + ]), + }, + ]); + }); + }); + + describe("delegatorTransactions", () => { + it("works", async () => { + pendingWithoutWasmd(); + const client = makeStakingClient(wasmd.endpoint); + const response = await client.staking.delegatorTransactions(faucet.address); + expect(response.length).toEqual(3); + }); + }); + + describe("delegatorValidators", () => { + it("works", async () => { + pendingWithoutWasmd(); + const client = makeStakingClient(wasmd.endpoint); + const response = await client.staking.delegatorValidators(faucet.address); + expect(response).toEqual({ + height: jasmine.stringMatching(nonNegativeIntegerMatcher), + result: [ + { + operator_address: validatorAddress, + consensus_pubkey: + "cosmosvalconspub1zcjduepqau36ht2r742jh230pxlu4wjmwcmkwpeqava80acphsu87vt5xlpqx6g7qh", + jailed: false, + status: BondStatus.Bonded, + tokens: jasmine.stringMatching(nonNegativeIntegerMatcher), + delegator_shares: jasmine.stringMatching(bigDecimalMatcher), + description: { + moniker: "testing", + identity: "", + website: "", + security_contact: "", + details: "", + }, + unbonding_height: "0", + unbonding_time: "1970-01-01T00:00:00Z", + commission: { + commission_rates: { + rate: "0.100000000000000000", + max_rate: "0.200000000000000000", + max_change_rate: "0.010000000000000000", + }, + update_time: "2020-06-03T06:01:17.4747987Z", + }, + min_self_delegation: "1", + }, + ], + }); + }); + }); + + describe("delegatorValidator", () => { + it("works", async () => { + pendingWithoutWasmd(); + const client = makeStakingClient(wasmd.endpoint); + const response = await client.staking.delegatorValidator(faucet.address, validatorAddress); + expect(response).toEqual({ + height: jasmine.stringMatching(nonNegativeIntegerMatcher), + result: { + operator_address: validatorAddress, + consensus_pubkey: + "cosmosvalconspub1zcjduepqau36ht2r742jh230pxlu4wjmwcmkwpeqava80acphsu87vt5xlpqx6g7qh", + jailed: false, + status: BondStatus.Bonded, + tokens: jasmine.stringMatching(nonNegativeIntegerMatcher), + delegator_shares: jasmine.stringMatching(bigDecimalMatcher), + description: { + moniker: "testing", + identity: "", + website: "", + security_contact: "", + details: "", + }, + unbonding_height: "0", + unbonding_time: "1970-01-01T00:00:00Z", + commission: { + commission_rates: { + rate: "0.100000000000000000", + max_rate: "0.200000000000000000", + max_change_rate: "0.010000000000000000", + }, + update_time: "2020-06-03T06:01:17.4747987Z", + }, + min_self_delegation: "1", + }, + }); + }); + }); + + describe("delegation", () => { + it("works", async () => { + pendingWithoutWasmd(); + const client = makeStakingClient(wasmd.endpoint); + const response = await client.staking.delegation(faucet.address, validatorAddress); + expect(response).toEqual({ + height: jasmine.stringMatching(nonNegativeIntegerMatcher), + result: { + delegator_address: faucet.address, + validator_address: validatorAddress, + shares: jasmine.stringMatching(bigDecimalMatcher), + balance: { denom: "ustake", amount: jasmine.stringMatching(nonNegativeIntegerMatcher) }, + }, + }); + }); + }); + + describe("unbondingDelegation", () => { + it("works", async () => { + pendingWithoutWasmd(); + const client = makeStakingClient(wasmd.endpoint); + const { height, result } = await client.staking.unbondingDelegation(faucet.address, validatorAddress); + expect(height).toMatch(nonNegativeIntegerMatcher); + assert(result); + expect(result).toEqual({ + delegator_address: faucet.address, + validator_address: validatorAddress, + entries: jasmine.arrayContaining([ + { + creation_height: jasmine.stringMatching(nonNegativeIntegerMatcher), + completion_time: jasmine.stringMatching(dateTimeStampMatcher), + initial_balance: "100", + balance: "100", + }, + ]), + }); + }); + }); + + describe("redelegations", () => { + it("works", async () => { + // TODO: Set up a result for this test + pendingWithoutWasmd(); + const client = makeStakingClient(wasmd.endpoint); + const response = await client.staking.redelegations(); + expect(response).toEqual({ + height: jasmine.stringMatching(nonNegativeIntegerMatcher), + result: [], + }); + }); + }); + + describe("validators", () => { + it("works", async () => { + pendingWithoutWasmd(); + const client = makeStakingClient(wasmd.endpoint); + const response = await client.staking.validators(); + expect(response).toEqual({ + height: jasmine.stringMatching(nonNegativeIntegerMatcher), + result: [ + { + operator_address: validatorAddress, + consensus_pubkey: + "cosmosvalconspub1zcjduepqau36ht2r742jh230pxlu4wjmwcmkwpeqava80acphsu87vt5xlpqx6g7qh", + jailed: false, + status: BondStatus.Bonded, + tokens: jasmine.stringMatching(nonNegativeIntegerMatcher), + delegator_shares: jasmine.stringMatching(bigDecimalMatcher), + description: { + moniker: "testing", + identity: "", + website: "", + security_contact: "", + details: "", + }, + unbonding_height: "0", + unbonding_time: "1970-01-01T00:00:00Z", + commission: { + commission_rates: { + rate: "0.100000000000000000", + max_rate: "0.200000000000000000", + max_change_rate: "0.010000000000000000", + }, + update_time: "2020-06-03T06:01:17.4747987Z", + }, + min_self_delegation: "1", + }, + ], + }); + }); + + it("can filter by status with no results", async () => { + pendingWithoutWasmd(); + const client = makeStakingClient(wasmd.endpoint); + const response = await client.staking.validators({ status: "unbonded" }); + expect(response).toEqual({ + height: jasmine.stringMatching(nonNegativeIntegerMatcher), + result: [], + }); + }); + + it("can filter by status with some results", async () => { + pendingWithoutWasmd(); + const client = makeStakingClient(wasmd.endpoint); + const response = await client.staking.validators({ status: "bonded" }); + expect(response).toEqual({ + height: jasmine.stringMatching(nonNegativeIntegerMatcher), + result: [ + { + operator_address: validatorAddress, + consensus_pubkey: + "cosmosvalconspub1zcjduepqau36ht2r742jh230pxlu4wjmwcmkwpeqava80acphsu87vt5xlpqx6g7qh", + jailed: false, + status: BondStatus.Bonded, + tokens: jasmine.stringMatching(nonNegativeIntegerMatcher), + delegator_shares: jasmine.stringMatching(bigDecimalMatcher), + description: { + moniker: "testing", + identity: "", + website: "", + security_contact: "", + details: "", + }, + unbonding_height: "0", + unbonding_time: "1970-01-01T00:00:00Z", + commission: { + commission_rates: { + rate: "0.100000000000000000", + max_rate: "0.200000000000000000", + max_change_rate: "0.010000000000000000", + }, + update_time: "2020-06-03T06:01:17.4747987Z", + }, + min_self_delegation: "1", + }, + ], + }); + }); + }); + + describe("validator", () => { + it("works", async () => { + pendingWithoutWasmd(); + const client = makeStakingClient(wasmd.endpoint); + const response = await client.staking.validator(validatorAddress); + expect(response).toEqual({ + height: jasmine.stringMatching(nonNegativeIntegerMatcher), + result: { + operator_address: validatorAddress, + consensus_pubkey: + "cosmosvalconspub1zcjduepqau36ht2r742jh230pxlu4wjmwcmkwpeqava80acphsu87vt5xlpqx6g7qh", + jailed: false, + status: BondStatus.Bonded, + tokens: jasmine.stringMatching(nonNegativeIntegerMatcher), + delegator_shares: jasmine.stringMatching(bigDecimalMatcher), + description: { + moniker: "testing", + identity: "", + website: "", + security_contact: "", + details: "", + }, + unbonding_height: "0", + unbonding_time: "1970-01-01T00:00:00Z", + commission: { + commission_rates: { + rate: "0.100000000000000000", + max_rate: "0.200000000000000000", + max_change_rate: "0.010000000000000000", + }, + update_time: "2020-06-03T06:01:17.4747987Z", + }, + min_self_delegation: "1", + }, + }); + }); + }); + + describe("validatorDelegations", () => { + it("works", async () => { + pendingWithoutWasmd(); + const client = makeStakingClient(wasmd.endpoint); + const response = await client.staking.validatorDelegations(validatorAddress); + expect(response).toEqual({ + height: jasmine.stringMatching(nonNegativeIntegerMatcher), + result: [ + { + delegator_address: faucet.address, + validator_address: validatorAddress, + shares: jasmine.stringMatching(bigDecimalMatcher), + balance: { denom: "ustake", amount: jasmine.stringMatching(nonNegativeIntegerMatcher) }, + }, + { + delegator_address: "cosmos1gjvanqxc774u6ed9thj4gpn9gj5zus5u57dxvq", + validator_address: validatorAddress, + shares: "250000000.000000000000000000", + balance: { denom: "ustake", amount: "250000000" }, + }, + ], + }); + }); + }); + + describe("validatorUnbondingDelegations", () => { + it("works", async () => { + pendingWithoutWasmd(); + const client = makeStakingClient(wasmd.endpoint); + const { height, result } = await client.staking.validatorUnbondingDelegations(validatorAddress); + expect(height).toMatch(nonNegativeIntegerMatcher); + assert(result); + expect(result).toEqual([ + { + delegator_address: faucet.address, + validator_address: validatorAddress, + entries: jasmine.arrayContaining([ + { + creation_height: jasmine.stringMatching(nonNegativeIntegerMatcher), + completion_time: jasmine.stringMatching(dateTimeStampMatcher), + initial_balance: "100", + balance: "100", + }, + ]), + }, + ]); + }); + }); + + describe("historicalInfo", () => { + it("doesn't work yet", async () => { + pendingWithoutWasmd(); + const client = makeStakingClient(wasmd.endpoint); + const currentHeight = (await client.blocksLatest()).block.header.height; + return expectAsync(client.staking.historicalInfo(currentHeight)).toBeRejectedWithError( + /no historical info found \(HTTP 400\)/i, + ); + }); + }); + + describe("pool", () => { + it("works", async () => { + pendingWithoutWasmd(); + const client = makeStakingClient(wasmd.endpoint); + const response = await client.staking.pool(); + expect(response).toEqual({ + height: jasmine.stringMatching(nonNegativeIntegerMatcher), + result: { + not_bonded_tokens: jasmine.stringMatching(nonNegativeIntegerMatcher), + bonded_tokens: jasmine.stringMatching(nonNegativeIntegerMatcher), + }, + }); + }); + }); + + describe("parameters", () => { + it("works", async () => { + pendingWithoutWasmd(); + const client = makeStakingClient(wasmd.endpoint); + const response = await client.staking.parameters(); + expect(response).toEqual({ + height: jasmine.stringMatching(nonNegativeIntegerMatcher), + result: { + unbonding_time: "1814400000000000", + max_validators: 100, + max_entries: 7, + historical_entries: 0, + bond_denom: "ustake", + }, + }); + }); + }); +}); diff --git a/packages/sdk38/src/lcdapi/staking.ts b/packages/sdk38/src/lcdapi/staking.ts new file mode 100644 index 00000000..604e7047 --- /dev/null +++ b/packages/sdk38/src/lcdapi/staking.ts @@ -0,0 +1,250 @@ +/* eslint-disable @typescript-eslint/naming-convention */ +import { Coin } from "../coins"; +import { BlockHeader, SearchTxsResponse } from "./base"; +import { LcdClient } from "./lcdclient"; + +/** + * Numeric bonding status + * + * @see https://github.com/cosmos/cosmos-sdk/blob/v0.38.5/types/staking.go#L43-L49 + */ +export enum BondStatus { + Unbonded = 0, + Unbonding = 1, + Bonded = 2, +} + +interface Validator { + readonly operator_address: string; + readonly consensus_pubkey: string; + readonly jailed: boolean; + readonly status: BondStatus; + readonly tokens: string; + readonly delegator_shares: string; + readonly description: { + readonly moniker: string; + readonly identity: string; + readonly website: string; + readonly security_contact: string; + readonly details: string; + }; + readonly unbonding_height: string; + readonly unbonding_time: string; + readonly commission: { + readonly commission_rates: { + readonly rate: string; + readonly max_rate: string; + readonly max_change_rate: string; + }; + readonly update_time: string; + }; + readonly min_self_delegation: string; +} + +interface Delegation { + readonly delegator_address: string; + readonly validator_address: string; + readonly shares: string; + readonly balance: Coin; +} + +export interface StakingDelegatorDelegationsResponse { + readonly height: string; + readonly result: readonly Delegation[]; +} + +interface UnbondingDelegationEntry { + readonly creation_height: string; + readonly completion_time: string; + readonly initial_balance: string; + readonly balance: string; +} + +interface UnbondingDelegation { + readonly delegator_address: string; + readonly validator_address: string; + readonly entries: readonly UnbondingDelegationEntry[]; +} + +export interface StakingDelegatorUnbondingDelegationsResponse { + readonly height: string; + readonly result: readonly UnbondingDelegation[]; +} + +export type StakingDelegatorTransactionsResponse = readonly SearchTxsResponse[]; + +export interface StakingDelegatorValidatorsResponse { + readonly height: string; + readonly result: readonly Validator[]; +} + +export interface StakingDelegatorValidatorResponse { + readonly height: string; + readonly result: Validator; +} + +export interface StakingDelegationResponse { + readonly height: string; + readonly result: Delegation; +} + +export interface StakingUnbondingDelegationResponse { + readonly height: string; + readonly result: UnbondingDelegation | null; +} + +interface RedelegationEntry { + readonly creation_height: string; + readonly completion_time: string; + readonly initial_balance: Coin; + readonly shares_dst: string; +} + +interface Redelegation { + readonly delegator_address: string; + readonly validator_src_address: string; + readonly validator_dst_address: string; + readonly entries: readonly RedelegationEntry[]; +} + +export interface StakingRedelegationsResponse { + readonly height: string; + readonly result: readonly Redelegation[]; +} + +export interface StakingValidatorsParams { + /** @see https://github.com/cosmos/cosmos-sdk/blob/v0.38.5/types/staking.go#L43-L49 */ + readonly status?: "bonded" | "unbonded" | "unbonding"; + readonly page?: number; + readonly limit?: number; +} + +export interface StakingValidatorsResponse { + readonly height: string; + readonly result: readonly Validator[]; +} + +export interface StakingValidatorResponse { + readonly height: string; + readonly result: Validator; +} + +export interface StakingValidatorDelegationsResponse { + readonly height: string; + readonly result: readonly Delegation[]; +} + +export interface StakingValidatorUnbondingDelegationsResponse { + readonly height: string; + readonly result: readonly UnbondingDelegation[]; +} + +interface HistoricalInfo { + readonly header: BlockHeader; + readonly validators: readonly Validator[]; +} + +export interface StakingHistoricalInfoResponse { + readonly height: string; + readonly result: HistoricalInfo; +} + +export interface StakingPoolResponse { + readonly height: string; + readonly result: { + readonly not_bonded_tokens: string; + readonly bonded_tokens: string; + }; +} + +export interface StakingParametersResponse { + readonly height: string; + readonly result: { + readonly unbonding_time: string; + readonly max_validators: number; + readonly max_entries: number; + readonly historical_entries: number; + readonly bond_denom: string; + }; +} + +export interface StakingExtension { + readonly staking: { + /** Get all delegations from a delegator */ + readonly delegatorDelegations: (delegatorAddress: string) => Promise; + /** Get all unbonding delegations from a delegator */ + readonly delegatorUnbondingDelegations: ( + delegatorAddress: string, + ) => Promise; + /** Get all staking txs (i.e msgs) from a delegator */ + readonly delegatorTransactions: ( + delegatorAddress: string, + ) => Promise; + /** Query all validators that a delegator is bonded to */ + readonly delegatorValidators: (delegatorAddress: string) => Promise; + /** Query a validator that a delegator is bonded to */ + readonly delegatorValidator: ( + delegatorAddress: string, + validatorAddress: string, + ) => Promise; + /** Query a delegation between a delegator and a validator */ + readonly delegation: ( + delegatorAddress: string, + validatorAddress: string, + ) => Promise; + /** Query all unbonding delegations between a delegator and a validator */ + readonly unbondingDelegation: ( + delegatorAddress: string, + validatorAddress: string, + ) => Promise; + /** Query redelegations (filters in query params) */ + readonly redelegations: () => Promise; + /** Get all validators */ + readonly validators: (options?: StakingValidatorsParams) => Promise; + /** Get a single validator info */ + readonly validator: (validatorAddress: string) => Promise; + // Get all delegations to a validator + readonly validatorDelegations: (validatorAddress: string) => Promise; + /** Get all unbonding delegations from a validator */ + readonly validatorUnbondingDelegations: ( + validatorAddress: string, + ) => Promise; + /** Get HistoricalInfo at a given height */ + readonly historicalInfo: (height: string) => Promise; + /** Get the current state of the staking pool */ + readonly pool: () => Promise; + /** Get the current staking parameter values */ + readonly parameters: () => Promise; + }; +} + +export function setupStakingExtension(base: LcdClient): StakingExtension { + return { + staking: { + delegatorDelegations: async (delegatorAddress: string) => + base.get(`/staking/delegators/${delegatorAddress}/delegations`), + delegatorUnbondingDelegations: async (delegatorAddress: string) => + base.get(`/staking/delegators/${delegatorAddress}/unbonding_delegations`), + delegatorTransactions: async (delegatorAddress: string) => + base.get(`/staking/delegators/${delegatorAddress}/txs`), + delegatorValidators: async (delegatorAddress: string) => + base.get(`/staking/delegators/${delegatorAddress}/validators`), + delegatorValidator: async (delegatorAddress: string, validatorAddress: string) => + base.get(`/staking/delegators/${delegatorAddress}/validators/${validatorAddress}`), + delegation: async (delegatorAddress: string, validatorAddress: string) => + base.get(`/staking/delegators/${delegatorAddress}/delegations/${validatorAddress}`), + unbondingDelegation: async (delegatorAddress: string, validatorAddress: string) => + base.get(`/staking/delegators/${delegatorAddress}/unbonding_delegations/${validatorAddress}`), + redelegations: async () => base.get(`/staking/redelegations`), + validators: async (params?: StakingValidatorsParams) => base.get(`/staking/validators`, params), + validator: async (validatorAddress: string) => base.get(`/staking/validators/${validatorAddress}`), + validatorDelegations: async (validatorAddress: string) => + base.get(`/staking/validators/${validatorAddress}/delegations`), + validatorUnbondingDelegations: async (validatorAddress: string) => + base.get(`/staking/validators/${validatorAddress}/unbonding_delegations`), + historicalInfo: async (height: string) => base.get(`/staking/historical_info/${height}`), + pool: async () => base.get(`/staking/pool`), + parameters: async () => base.get(`/staking/parameters`), + }, + }; +} diff --git a/packages/sdk38/types/index.d.ts b/packages/sdk38/types/index.d.ts index 07e7a554..7aaafa40 100644 --- a/packages/sdk38/types/index.d.ts +++ b/packages/sdk38/types/index.d.ts @@ -61,10 +61,14 @@ export { setupGovExtension, setupMintExtension, setupSlashingExtension, + setupStakingExtension, setupSupplyExtension, SlashingExtension, SlashingParametersResponse, SlashingSigningInfosResponse, + StakingExtension, + StakingParametersResponse, + StakingPoolResponse, SupplyExtension, TxsResponse, } from "./lcdapi"; diff --git a/packages/sdk38/types/lcdapi/base.d.ts b/packages/sdk38/types/lcdapi/base.d.ts index 8771acf4..437d252f 100644 --- a/packages/sdk38/types/lcdapi/base.d.ts +++ b/packages/sdk38/types/lcdapi/base.d.ts @@ -50,7 +50,7 @@ export interface NodeInfoResponse { interface BlockId { readonly hash: string; } -interface BlockHeader { +export interface BlockHeader { readonly version: { readonly block: string; readonly app: string; diff --git a/packages/sdk38/types/lcdapi/index.d.ts b/packages/sdk38/types/lcdapi/index.d.ts index 77819d6c..6a06331d 100644 --- a/packages/sdk38/types/lcdapi/index.d.ts +++ b/packages/sdk38/types/lcdapi/index.d.ts @@ -38,6 +38,25 @@ export { SlashingParametersResponse, SlashingSigningInfosResponse, } from "./slashing"; +export { + setupStakingExtension, + StakingDelegatorDelegationsResponse, + StakingDelegatorUnbondingDelegationsResponse, + StakingDelegatorTransactionsResponse, + StakingDelegatorValidatorsResponse, + StakingDelegatorValidatorResponse, + StakingDelegationResponse, + StakingUnbondingDelegationResponse, + StakingRedelegationsResponse, + StakingValidatorsResponse, + StakingValidatorResponse, + StakingValidatorDelegationsResponse, + StakingValidatorUnbondingDelegationsResponse, + StakingHistoricalInfoResponse, + StakingExtension, + StakingParametersResponse, + StakingPoolResponse, +} from "./staking"; export { setupSupplyExtension, SupplyExtension, TotalSupplyAllResponse, TotalSupplyResponse } from "./supply"; export { BlockResponse, diff --git a/packages/sdk38/types/lcdapi/lcdclient.d.ts b/packages/sdk38/types/lcdapi/lcdclient.d.ts index ce67cc38..7b275b02 100644 --- a/packages/sdk38/types/lcdapi/lcdclient.d.ts +++ b/packages/sdk38/types/lcdapi/lcdclient.d.ts @@ -143,7 +143,7 @@ export declare class LcdClient { * @param broadcastMode Defines at which point of the transaction processing the postTx method (i.e. transaction broadcasting) returns */ constructor(apiUrl: string, broadcastMode?: BroadcastMode); - get(path: string): Promise; + get(path: string, params?: Record): Promise; post(path: string, params: any): Promise; blocksLatest(): Promise; blocks(height: number): Promise; diff --git a/packages/sdk38/types/lcdapi/staking.d.ts b/packages/sdk38/types/lcdapi/staking.d.ts new file mode 100644 index 00000000..bb046fad --- /dev/null +++ b/packages/sdk38/types/lcdapi/staking.d.ts @@ -0,0 +1,194 @@ +import { Coin } from "../coins"; +import { BlockHeader, SearchTxsResponse } from "./base"; +import { LcdClient } from "./lcdclient"; +/** + * Numeric bonding status + * + * @see https://github.com/cosmos/cosmos-sdk/blob/v0.38.5/types/staking.go#L43-L49 + */ +export declare enum BondStatus { + Unbonded = 0, + Unbonding = 1, + Bonded = 2, +} +interface Validator { + readonly operator_address: string; + readonly consensus_pubkey: string; + readonly jailed: boolean; + readonly status: BondStatus; + readonly tokens: string; + readonly delegator_shares: string; + readonly description: { + readonly moniker: string; + readonly identity: string; + readonly website: string; + readonly security_contact: string; + readonly details: string; + }; + readonly unbonding_height: string; + readonly unbonding_time: string; + readonly commission: { + readonly commission_rates: { + readonly rate: string; + readonly max_rate: string; + readonly max_change_rate: string; + }; + readonly update_time: string; + }; + readonly min_self_delegation: string; +} +interface Delegation { + readonly delegator_address: string; + readonly validator_address: string; + readonly shares: string; + readonly balance: Coin; +} +export interface StakingDelegatorDelegationsResponse { + readonly height: string; + readonly result: readonly Delegation[]; +} +interface UnbondingDelegationEntry { + readonly creation_height: string; + readonly completion_time: string; + readonly initial_balance: string; + readonly balance: string; +} +interface UnbondingDelegation { + readonly delegator_address: string; + readonly validator_address: string; + readonly entries: readonly UnbondingDelegationEntry[]; +} +export interface StakingDelegatorUnbondingDelegationsResponse { + readonly height: string; + readonly result: readonly UnbondingDelegation[]; +} +export declare type StakingDelegatorTransactionsResponse = readonly SearchTxsResponse[]; +export interface StakingDelegatorValidatorsResponse { + readonly height: string; + readonly result: readonly Validator[]; +} +export interface StakingDelegatorValidatorResponse { + readonly height: string; + readonly result: Validator; +} +export interface StakingDelegationResponse { + readonly height: string; + readonly result: Delegation; +} +export interface StakingUnbondingDelegationResponse { + readonly height: string; + readonly result: UnbondingDelegation | null; +} +interface RedelegationEntry { + readonly creation_height: string; + readonly completion_time: string; + readonly initial_balance: Coin; + readonly shares_dst: string; +} +interface Redelegation { + readonly delegator_address: string; + readonly validator_src_address: string; + readonly validator_dst_address: string; + readonly entries: readonly RedelegationEntry[]; +} +export interface StakingRedelegationsResponse { + readonly height: string; + readonly result: readonly Redelegation[]; +} +export interface StakingValidatorsParams { + /** @see https://github.com/cosmos/cosmos-sdk/blob/v0.38.5/types/staking.go#L43-L49 */ + readonly status?: "bonded" | "unbonded" | "unbonding"; + readonly page?: number; + readonly limit?: number; +} +export interface StakingValidatorsResponse { + readonly height: string; + readonly result: readonly Validator[]; +} +export interface StakingValidatorResponse { + readonly height: string; + readonly result: Validator; +} +export interface StakingValidatorDelegationsResponse { + readonly height: string; + readonly result: readonly Delegation[]; +} +export interface StakingValidatorUnbondingDelegationsResponse { + readonly height: string; + readonly result: readonly UnbondingDelegation[]; +} +interface HistoricalInfo { + readonly header: BlockHeader; + readonly validators: readonly Validator[]; +} +export interface StakingHistoricalInfoResponse { + readonly height: string; + readonly result: HistoricalInfo; +} +export interface StakingPoolResponse { + readonly height: string; + readonly result: { + readonly not_bonded_tokens: string; + readonly bonded_tokens: string; + }; +} +export interface StakingParametersResponse { + readonly height: string; + readonly result: { + readonly unbonding_time: string; + readonly max_validators: number; + readonly max_entries: number; + readonly historical_entries: number; + readonly bond_denom: string; + }; +} +export interface StakingExtension { + readonly staking: { + /** Get all delegations from a delegator */ + readonly delegatorDelegations: (delegatorAddress: string) => Promise; + /** Get all unbonding delegations from a delegator */ + readonly delegatorUnbondingDelegations: ( + delegatorAddress: string, + ) => Promise; + /** Get all staking txs (i.e msgs) from a delegator */ + readonly delegatorTransactions: ( + delegatorAddress: string, + ) => Promise; + /** Query all validators that a delegator is bonded to */ + readonly delegatorValidators: (delegatorAddress: string) => Promise; + /** Query a validator that a delegator is bonded to */ + readonly delegatorValidator: ( + delegatorAddress: string, + validatorAddress: string, + ) => Promise; + /** Query a delegation between a delegator and a validator */ + readonly delegation: ( + delegatorAddress: string, + validatorAddress: string, + ) => Promise; + /** Query all unbonding delegations between a delegator and a validator */ + readonly unbondingDelegation: ( + delegatorAddress: string, + validatorAddress: string, + ) => Promise; + /** Query redelegations (filters in query params) */ + readonly redelegations: () => Promise; + /** Get all validators */ + readonly validators: (options?: StakingValidatorsParams) => Promise; + /** Get a single validator info */ + readonly validator: (validatorAddress: string) => Promise; + readonly validatorDelegations: (validatorAddress: string) => Promise; + /** Get all unbonding delegations from a validator */ + readonly validatorUnbondingDelegations: ( + validatorAddress: string, + ) => Promise; + /** Get HistoricalInfo at a given height */ + readonly historicalInfo: (height: string) => Promise; + /** Get the current state of the staking pool */ + readonly pool: () => Promise; + /** Get the current staking parameter values */ + readonly parameters: () => Promise; + }; +} +export declare function setupStakingExtension(base: LcdClient): StakingExtension; +export {}; diff --git a/scripts/wasmd/cli.sh b/scripts/wasmd/cli.sh index 804f8f31..4b8e2474 100755 --- a/scripts/wasmd/cli.sh +++ b/scripts/wasmd/cli.sh @@ -16,6 +16,6 @@ docker run \ --mount type=volume,source=wasmcli_data,target=/root/.wasmcli \ -w "$HOME_DIR" \ --env "HOME=$HOME_DIR" \ - --net "container:$BLOCKCHAIN_CONTAINER_NAME" \ + --net "container:$CONTAINER_NAME" \ "$REPOSITORY:$VERSION" \ wasmcli "$@" diff --git a/scripts/wasmd/env b/scripts/wasmd/env index 738980b3..02ca613f 100644 --- a/scripts/wasmd/env +++ b/scripts/wasmd/env @@ -1,5 +1,5 @@ # Choose from https://hub.docker.com/r/cosmwasm/wasmd/tags REPOSITORY="cosmwasm/wasmd" -VERSION="v0.9.0-beta" +VERSION="v0.9.1" CONTAINER_NAME="wasmd"