Merge pull request #295 from CosmWasm/276-sdk38-distribution-module

Add LCD support for distribution module
This commit is contained in:
Simon Warta 2020-07-16 12:50:34 +02:00 committed by GitHub
commit 161fc84981
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 410 additions and 4 deletions

View File

@ -27,6 +27,15 @@ export {
BankExtension,
BlockResponse,
BroadcastMode,
DistributionCommunityPoolResponse,
DistributionDelegatorRewardResponse,
DistributionDelegatorRewardsResponse,
DistributionExtension,
DistributionParametersResponse,
DistributionValidatorOutstandingRewardsResponse,
DistributionValidatorResponse,
DistributionValidatorRewardsResponse,
DistributionWithdrawAddressResponse,
EncodeTxResponse,
GovExtension,
GovParametersResponse,
@ -50,6 +59,7 @@ export {
SearchTxsResponse,
setupAuthExtension,
setupBankExtension,
setupDistributionExtension,
setupGovExtension,
setupMintExtension,
setupSlashingExtension,

View File

@ -0,0 +1,193 @@
/* eslint-disable @typescript-eslint/naming-convention */
import { Bech32 } from "@cosmjs/encoding";
import { assert, sleep } from "@cosmjs/utils";
import { coin, coins } from "../coins";
import { isPostTxFailure } from "../cosmosclient";
import { makeSignBytes } from "../encoding";
import { MsgDelegate } from "../msgs";
import { SigningCosmosClient } from "../signingcosmosclient";
import {
bigDecimalMatcher,
faucet,
nonNegativeIntegerMatcher,
pendingWithoutWasmd,
validatorAddress,
wasmd,
wasmdEnabled,
} from "../testutils.spec";
import { Secp256k1Wallet } from "../wallet";
import { DistributionExtension, setupDistributionExtension } from "./distribution";
import { LcdClient } from "./lcdclient";
function makeDistributionClient(apiUrl: string): LcdClient & DistributionExtension {
return LcdClient.withExtensions({ apiUrl }, setupDistributionExtension);
}
describe("DistributionExtension", () => {
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.getNonce();
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("delegatorRewards", () => {
it("works", async () => {
pendingWithoutWasmd();
const client = makeDistributionClient(wasmd.endpoint);
const response = await client.distribution.delegatorRewards(faucet.address);
expect(response).toEqual({
height: jasmine.stringMatching(nonNegativeIntegerMatcher),
result: {
rewards: [
{
validator_address: validatorAddress,
reward: null,
},
],
total: null,
},
});
});
});
describe("delegatorReward", () => {
it("works", async () => {
pendingWithoutWasmd();
const client = makeDistributionClient(wasmd.endpoint);
const response = await client.distribution.delegatorReward(faucet.address, validatorAddress);
expect(response).toEqual({
height: jasmine.stringMatching(nonNegativeIntegerMatcher),
result: [],
});
});
});
describe("withdrawAddress", () => {
it("works", async () => {
pendingWithoutWasmd();
const client = makeDistributionClient(wasmd.endpoint);
const response = await client.distribution.withdrawAddress(faucet.address);
expect(response).toEqual({
height: jasmine.stringMatching(nonNegativeIntegerMatcher),
result: faucet.address,
});
});
});
describe("validator", () => {
it("works", async () => {
pendingWithoutWasmd();
const client = makeDistributionClient(wasmd.endpoint);
const response = await client.distribution.validator(validatorAddress);
expect(response).toEqual({
height: jasmine.stringMatching(nonNegativeIntegerMatcher),
result: {
// TODO: This smells like a bug in the backend to me
operator_address: Bech32.encode("cosmos", Bech32.decode(validatorAddress).data),
self_bond_rewards: [
{ denom: "ucosm", amount: jasmine.stringMatching(bigDecimalMatcher) },
{ denom: "ustake", amount: jasmine.stringMatching(bigDecimalMatcher) },
],
val_commission: [
{ denom: "ucosm", amount: jasmine.stringMatching(bigDecimalMatcher) },
{ denom: "ustake", amount: jasmine.stringMatching(bigDecimalMatcher) },
],
},
});
});
});
describe("validatorRewards", () => {
it("works", async () => {
pendingWithoutWasmd();
const client = makeDistributionClient(wasmd.endpoint);
const response = await client.distribution.validatorRewards(validatorAddress);
expect(response).toEqual({
height: jasmine.stringMatching(nonNegativeIntegerMatcher),
result: [
{ denom: "ucosm", amount: jasmine.stringMatching(bigDecimalMatcher) },
{ denom: "ustake", amount: jasmine.stringMatching(bigDecimalMatcher) },
],
});
});
});
describe("validatorOutstandingRewards", () => {
it("works", async () => {
pendingWithoutWasmd();
const client = makeDistributionClient(wasmd.endpoint);
const response = await client.distribution.validatorOutstandingRewards(validatorAddress);
expect(response).toEqual({
height: jasmine.stringMatching(nonNegativeIntegerMatcher),
result: [
{ denom: "ucosm", amount: jasmine.stringMatching(bigDecimalMatcher) },
{ denom: "ustake", amount: jasmine.stringMatching(bigDecimalMatcher) },
],
});
});
});
describe("parameters", () => {
it("works", async () => {
pendingWithoutWasmd();
const client = makeDistributionClient(wasmd.endpoint);
const response = await client.distribution.parameters();
expect(response).toEqual({
height: jasmine.stringMatching(nonNegativeIntegerMatcher),
result: {
community_tax: "0.020000000000000000",
base_proposer_reward: "0.010000000000000000",
bonus_proposer_reward: "0.040000000000000000",
withdraw_addr_enabled: true,
},
});
});
});
describe("communityPool", () => {
it("works", async () => {
pendingWithoutWasmd();
const client = makeDistributionClient(wasmd.endpoint);
const response = await client.distribution.communityPool();
expect(response).toEqual({
height: jasmine.stringMatching(nonNegativeIntegerMatcher),
result: [
{ denom: "ucosm", amount: jasmine.stringMatching(bigDecimalMatcher) },
{ denom: "ustake", amount: jasmine.stringMatching(bigDecimalMatcher) },
],
});
});
});
});

View File

@ -0,0 +1,99 @@
/* eslint-disable @typescript-eslint/naming-convention */
import { Coin } from "../coins";
import { LcdClient } from "./lcdclient";
export interface RewardContainer {
readonly validator_address: string;
readonly reward: readonly Coin[] | null;
}
export interface DistributionDelegatorRewardsResponse {
readonly height: string;
readonly result: {
readonly rewards: readonly RewardContainer[] | null;
readonly total: readonly Coin[] | null;
};
}
export interface DistributionDelegatorRewardResponse {
readonly height: string;
readonly result: readonly Coin[];
}
export interface DistributionWithdrawAddressResponse {
readonly height: string;
readonly result: string;
}
export interface DistributionValidatorResponse {
readonly height: string;
readonly result: {
readonly operator_address: string;
readonly self_bond_rewards: readonly Coin[];
readonly val_commission: readonly Coin[];
};
}
export interface DistributionValidatorRewardsResponse {
readonly height: string;
readonly result: readonly Coin[];
}
export interface DistributionValidatorOutstandingRewardsResponse {
readonly height: string;
readonly result: readonly Coin[];
}
export interface DistributionParametersResponse {
readonly height: string;
readonly result: {
readonly community_tax: string;
readonly base_proposer_reward: string;
readonly bonus_proposer_reward: string;
readonly withdraw_addr_enabled: boolean;
};
}
export interface DistributionCommunityPoolResponse {
readonly height: string;
readonly result: readonly Coin[];
}
export interface DistributionExtension {
readonly distribution: {
readonly delegatorRewards: (delegatorAddress: string) => Promise<DistributionDelegatorRewardsResponse>;
readonly delegatorReward: (
delegatorAddress: string,
validatorAddress: string,
) => Promise<DistributionDelegatorRewardResponse>;
readonly withdrawAddress: (delegatorAddress: string) => Promise<DistributionWithdrawAddressResponse>;
readonly validator: (validatorAddress: string) => Promise<DistributionValidatorResponse>;
readonly validatorRewards: (validatorAddress: string) => Promise<DistributionValidatorRewardsResponse>;
readonly validatorOutstandingRewards: (
validatorAddress: string,
) => Promise<DistributionValidatorOutstandingRewardsResponse>;
readonly parameters: () => Promise<DistributionParametersResponse>;
readonly communityPool: () => Promise<DistributionCommunityPoolResponse>;
};
}
export function setupDistributionExtension(base: LcdClient): DistributionExtension {
return {
distribution: {
delegatorRewards: async (delegatorAddress: string) =>
base.get(`/distribution/delegators/${delegatorAddress}/rewards`),
delegatorReward: async (delegatorAddress: string, validatorAddress: string) =>
base.get(`/distribution/delegators/${delegatorAddress}/rewards/${validatorAddress}`),
withdrawAddress: async (delegatorAddress: string) =>
base.get(`/distribution/delegators/${delegatorAddress}/withdraw_address`),
validator: async (validatorAddress: string) => base.get(`/distribution/validators/${validatorAddress}`),
validatorRewards: async (validatorAddress: string) =>
base.get(`/distribution/validators/${validatorAddress}/rewards`),
validatorOutstandingRewards: async (validatorAddress: string) =>
base.get(`/distribution/validators/${validatorAddress}/outstanding_rewards`),
parameters: async () => base.get(`/distribution/parameters`),
communityPool: async () => base.get(`/distribution/community_pool`),
},
};
}

View File

@ -259,10 +259,10 @@ describe("GovExtension", () => {
expect(response).toEqual({
height: jasmine.stringMatching(nonNegativeIntegerMatcher),
result: {
yes: "0",
abstain: "0",
no: "0",
no_with_veto: "0",
yes: jasmine.stringMatching(nonNegativeIntegerMatcher),
abstain: jasmine.stringMatching(nonNegativeIntegerMatcher),
no: jasmine.stringMatching(nonNegativeIntegerMatcher),
no_with_veto: jasmine.stringMatching(nonNegativeIntegerMatcher),
},
});
});

View File

@ -4,6 +4,18 @@
export { AuthExtension, AuthAccountsResponse, setupAuthExtension } from "./auth";
export { BankBalancesResponse, BankExtension, setupBankExtension } from "./bank";
export {
DistributionCommunityPoolResponse,
DistributionDelegatorRewardResponse,
DistributionDelegatorRewardsResponse,
DistributionExtension,
DistributionParametersResponse,
DistributionValidatorOutstandingRewardsResponse,
DistributionValidatorResponse,
DistributionValidatorRewardsResponse,
DistributionWithdrawAddressResponse,
setupDistributionExtension,
} from "./distribution";
export {
GovExtension,
GovParametersResponse,

View File

@ -38,6 +38,8 @@ export const faucet = {
address: "cosmos1pkptre7fdkl6gfrzlesjjvhxhlc3r4gmmk8rs6",
};
export const validatorAddress = "cosmosvaloper1gjvanqxc774u6ed9thj4gpn9gj5zus5u32enqn";
/** Unused account */
export const unused = {
pubkey: {

View File

@ -25,6 +25,15 @@ export {
BankExtension,
BlockResponse,
BroadcastMode,
DistributionCommunityPoolResponse,
DistributionDelegatorRewardResponse,
DistributionDelegatorRewardsResponse,
DistributionExtension,
DistributionParametersResponse,
DistributionValidatorOutstandingRewardsResponse,
DistributionValidatorResponse,
DistributionValidatorRewardsResponse,
DistributionWithdrawAddressResponse,
EncodeTxResponse,
GovExtension,
GovParametersResponse,
@ -48,6 +57,7 @@ export {
SearchTxsResponse,
setupAuthExtension,
setupBankExtension,
setupDistributionExtension,
setupGovExtension,
setupMintExtension,
setupSlashingExtension,

View File

@ -0,0 +1,68 @@
import { Coin } from "../coins";
import { LcdClient } from "./lcdclient";
export interface RewardContainer {
readonly validator_address: string;
readonly reward: readonly Coin[] | null;
}
export interface DistributionDelegatorRewardsResponse {
readonly height: string;
readonly result: {
readonly rewards: readonly RewardContainer[] | null;
readonly total: readonly Coin[] | null;
};
}
export interface DistributionDelegatorRewardResponse {
readonly height: string;
readonly result: readonly Coin[];
}
export interface DistributionWithdrawAddressResponse {
readonly height: string;
readonly result: string;
}
export interface DistributionValidatorResponse {
readonly height: string;
readonly result: {
readonly operator_address: string;
readonly self_bond_rewards: readonly Coin[];
readonly val_commission: readonly Coin[];
};
}
export interface DistributionValidatorRewardsResponse {
readonly height: string;
readonly result: readonly Coin[];
}
export interface DistributionValidatorOutstandingRewardsResponse {
readonly height: string;
readonly result: readonly Coin[];
}
export interface DistributionParametersResponse {
readonly height: string;
readonly result: {
readonly community_tax: string;
readonly base_proposer_reward: string;
readonly bonus_proposer_reward: string;
readonly withdraw_addr_enabled: boolean;
};
}
export interface DistributionCommunityPoolResponse {
readonly height: string;
readonly result: readonly Coin[];
}
export interface DistributionExtension {
readonly distribution: {
readonly delegatorRewards: (delegatorAddress: string) => Promise<DistributionDelegatorRewardsResponse>;
readonly delegatorReward: (
delegatorAddress: string,
validatorAddress: string,
) => Promise<DistributionDelegatorRewardResponse>;
readonly withdrawAddress: (delegatorAddress: string) => Promise<DistributionWithdrawAddressResponse>;
readonly validator: (validatorAddress: string) => Promise<DistributionValidatorResponse>;
readonly validatorRewards: (validatorAddress: string) => Promise<DistributionValidatorRewardsResponse>;
readonly validatorOutstandingRewards: (
validatorAddress: string,
) => Promise<DistributionValidatorOutstandingRewardsResponse>;
readonly parameters: () => Promise<DistributionParametersResponse>;
readonly communityPool: () => Promise<DistributionCommunityPoolResponse>;
};
}
export declare function setupDistributionExtension(base: LcdClient): DistributionExtension;

View File

@ -1,5 +1,17 @@
export { AuthExtension, AuthAccountsResponse, setupAuthExtension } from "./auth";
export { BankBalancesResponse, BankExtension, setupBankExtension } from "./bank";
export {
DistributionCommunityPoolResponse,
DistributionDelegatorRewardResponse,
DistributionDelegatorRewardsResponse,
DistributionExtension,
DistributionParametersResponse,
DistributionValidatorOutstandingRewardsResponse,
DistributionValidatorResponse,
DistributionValidatorRewardsResponse,
DistributionWithdrawAddressResponse,
setupDistributionExtension,
} from "./distribution";
export {
GovExtension,
GovParametersResponse,