Add support for MsgVoteWeighted

This commit is contained in:
Simon Warta 2022-08-02 13:48:28 +02:00
parent 21f8fd497e
commit 65d86d0cd8
7 changed files with 202 additions and 4 deletions

View File

@ -20,10 +20,13 @@ and this project adheres to
([#1072]).
- @cosmjs/math: Add `{Uint32,Int53,Uint53,Uint64}.toBigInt` converter methods.
- @cosmjs/stargate: Add missing exports `AminoMsgTransfer`/`isAminoMsgTransfer`.
- @cosmjs/stargate: Add support for `MsgVoteWeighted` (register by default and
create Amino JSON converters) ([#1224]).
[#1072]: https://github.com/cosmos/cosmjs/issues/1072
[#1154]: https://github.com/cosmos/cosmjs/issues/1154
[#1176]: https://github.com/cosmos/cosmjs/pull/1176
[#1224]: https://github.com/cosmos/cosmjs/pull/1224
### Fixed

View File

@ -19,6 +19,7 @@ export {
AminoMsgUnjail,
AminoMsgVerifyInvariant,
AminoMsgVote,
AminoMsgVoteWeighted,
AminoMsgWithdrawDelegatorReward,
AminoMsgWithdrawValidatorCommission,
AuthExtension,
@ -44,6 +45,7 @@ export {
isAminoMsgUnjail,
isAminoMsgVerifyInvariant,
isAminoMsgVote,
isAminoMsgVoteWeighted,
isAminoMsgWithdrawDelegatorReward,
isAminoMsgWithdrawValidatorCommission,
isMsgDelegateEncodeObject,
@ -53,6 +55,7 @@ export {
isMsgTransferEncodeObject,
isMsgUndelegateEncodeObject,
isMsgVoteEncodeObject,
isMsgVoteWeightedEncodeObject,
isMsgWithdrawDelegatorRewardEncodeObject,
MintExtension,
MintParams,
@ -63,6 +66,7 @@ export {
MsgTransferEncodeObject,
MsgUndelegateEncodeObject,
MsgVoteEncodeObject,
MsgVoteWeightedEncodeObject,
MsgWithdrawDelegatorRewardEncodeObject,
setupAuthExtension,
setupBankExtension,

View File

@ -1,6 +1,6 @@
/* eslint-disable @typescript-eslint/naming-convention */
import { TextProposal, VoteOption } from "cosmjs-types/cosmos/gov/v1beta1/gov";
import { MsgDeposit, MsgSubmitProposal, MsgVote } from "cosmjs-types/cosmos/gov/v1beta1/tx";
import { MsgDeposit, MsgSubmitProposal, MsgVote, MsgVoteWeighted } from "cosmjs-types/cosmos/gov/v1beta1/tx";
import Long from "long";
import { AminoTypes } from "../../aminotypes";
@ -8,6 +8,7 @@ import {
AminoMsgDeposit,
AminoMsgSubmitProposal,
AminoMsgVote,
AminoMsgVoteWeighted,
createGovAminoConverters,
} from "./aminomessages";
@ -90,6 +91,34 @@ describe("AminoTypes", () => {
};
expect(aminoMsg).toEqual(expected);
});
it("works for MsgVoteWeighted", () => {
const msg: MsgVoteWeighted = {
proposalId: Long.fromNumber(5),
voter: "cosmos1xy4yqngt0nlkdcenxymg8tenrghmek4nmqm28k",
options: [
{ option: VoteOption.VOTE_OPTION_NO_WITH_VETO, weight: "700000000000000000" /* 0.7 */ },
{ option: VoteOption.VOTE_OPTION_NO, weight: "300000000000000000" /* 0.3 */ },
],
};
const aminoTypes = new AminoTypes(createGovAminoConverters());
const aminoMsg = aminoTypes.toAmino({
typeUrl: "/cosmos.gov.v1beta1.MsgVoteWeighted",
value: msg,
});
const expected: AminoMsgVoteWeighted = {
type: "cosmos-sdk/MsgVoteWeighted",
value: {
proposal_id: "5",
voter: "cosmos1xy4yqngt0nlkdcenxymg8tenrghmek4nmqm28k",
options: [
{ option: VoteOption.VOTE_OPTION_NO_WITH_VETO, weight: "0.700000000000000000" },
{ option: VoteOption.VOTE_OPTION_NO, weight: "0.300000000000000000" },
],
},
};
expect(aminoMsg).toEqual(expected);
});
});
describe("fromAmino", () => {
@ -167,5 +196,32 @@ describe("AminoTypes", () => {
value: expectedValue,
});
});
it("works for MsgVoteWeighted", () => {
const aminoMsg: AminoMsgVoteWeighted = {
type: "cosmos-sdk/MsgVoteWeighted",
value: {
proposal_id: "5",
voter: "cosmos1xy4yqngt0nlkdcenxymg8tenrghmek4nmqm28k",
options: [
{ option: 4, weight: "0.750000000000000000" },
{ option: 3, weight: "0.250000000000000000" },
],
},
};
const msg = new AminoTypes(createGovAminoConverters()).fromAmino(aminoMsg);
const expectedValue: MsgVoteWeighted = {
proposalId: Long.fromNumber(5),
voter: "cosmos1xy4yqngt0nlkdcenxymg8tenrghmek4nmqm28k",
options: [
{ option: VoteOption.VOTE_OPTION_NO_WITH_VETO, weight: "750000000000000000" },
{ option: VoteOption.VOTE_OPTION_NO, weight: "250000000000000000" },
],
};
expect(msg).toEqual({
typeUrl: "/cosmos.gov.v1beta1.MsgVoteWeighted",
value: expectedValue,
});
});
});
});

View File

@ -1,12 +1,14 @@
/* eslint-disable @typescript-eslint/naming-convention */
import { AminoMsg, Coin } from "@cosmjs/amino";
import { Decimal } from "@cosmjs/math";
import { assert, assertDefinedAndNotNull, isNonNullObject } from "@cosmjs/utils";
import { TextProposal, voteOptionFromJSON } from "cosmjs-types/cosmos/gov/v1beta1/gov";
import { MsgDeposit, MsgSubmitProposal, MsgVote } from "cosmjs-types/cosmos/gov/v1beta1/tx";
import { MsgDeposit, MsgSubmitProposal, MsgVote, MsgVoteWeighted } from "cosmjs-types/cosmos/gov/v1beta1/tx";
import { Any } from "cosmjs-types/google/protobuf/any";
import Long from "long";
import { AminoConverters } from "../../aminotypes";
import { decodeCosmosSdkDecFromProto } from "../../queryclient";
/** Supports submitting arbitrary proposal content. */
export interface AminoMsgSubmitProposal extends AminoMsg {
@ -59,6 +61,32 @@ export function isAminoMsgVote(msg: AminoMsg): msg is AminoMsgVote {
return msg.type === "cosmos-sdk/MsgVote";
}
/**
* @see https://github.com/cosmos/cosmos-sdk/blob/v0.44.5/x/gov/types/tx.pb.go#L196-L203
* @see https://github.com/cosmos/cosmos-sdk/blob/v0.44.5/x/gov/types/gov.pb.go#L124-L130
*/
export interface AminoMsgVoteWeighted extends AminoMsg {
readonly type: "cosmos-sdk/MsgVoteWeighted";
readonly value: {
readonly proposal_id: string;
/** Bech32 account address */
readonly voter: string;
readonly options: Array<{
/**
* VoteOption as integer from 0 to 4 🤷
*
* @see https://github.com/cosmos/cosmos-sdk/blob/v0.44.5/x/gov/types/gov.pb.go#L35-L49
*/
readonly option: number;
readonly weight: string;
}>;
};
}
export function isAminoMsgVoteWeighted(msg: AminoMsg): msg is AminoMsgVoteWeighted {
return (msg as AminoMsgVoteWeighted).type === "cosmos-sdk/MsgVoteWeighted";
}
/** Submits a deposit to an existing proposal */
export interface AminoMsgDeposit extends AminoMsg {
readonly type: "cosmos-sdk/MsgDeposit";
@ -110,6 +138,31 @@ export function createGovAminoConverters(): AminoConverters {
};
},
},
"/cosmos.gov.v1beta1.MsgVoteWeighted": {
aminoType: "cosmos-sdk/MsgVoteWeighted",
toAmino: ({ options, proposalId, voter }: MsgVoteWeighted): AminoMsgVoteWeighted["value"] => {
return {
options: options.map((o) => ({
option: o.option,
// Weight is between 0 and 1, so we always have 20 characters when printing all trailing
// zeros (e.g. "0.700000000000000000" or "1.000000000000000000")
weight: decodeCosmosSdkDecFromProto(o.weight).toString().padEnd(20, "0"),
})),
proposal_id: proposalId.toString(),
voter: voter,
};
},
fromAmino: ({ options, proposal_id, voter }: AminoMsgVoteWeighted["value"]): MsgVoteWeighted => {
return {
proposalId: Long.fromString(proposal_id),
voter: voter,
options: options.map((o) => ({
option: voteOptionFromJSON(o.option),
weight: Decimal.fromUserInput(o.weight, 18).atomics,
})),
};
},
},
"/cosmos.gov.v1beta1.MsgSubmitProposal": {
aminoType: "cosmos-sdk/MsgSubmitProposal",
toAmino: ({

View File

@ -1,4 +1,4 @@
import { coin, coins, makeCosmoshubPath } from "@cosmjs/amino";
import { coin, coins, makeCosmoshubPath, Secp256k1HdWallet } from "@cosmjs/amino";
import { DirectSecp256k1HdWallet } from "@cosmjs/proto-signing";
import { assert, sleep } from "@cosmjs/utils";
import { TextProposal, VoteOption } from "cosmjs-types/cosmos/gov/v1beta1/gov";
@ -17,6 +17,7 @@ import {
validator,
} from "../../testutils.spec";
import { MsgDelegateEncodeObject, MsgSubmitProposalEncodeObject, MsgVoteEncodeObject } from "../";
import { MsgVoteWeightedEncodeObject } from "./messages";
describe("gov messages", () => {
const defaultFee = {
@ -166,5 +167,72 @@ describe("gov messages", () => {
client.disconnect();
});
});
describe("MsgVoteWeighted", () => {
it("works", async () => {
pendingWithoutSimapp();
assert(voterWallet);
assert(proposalId, "Missing proposal ID");
const client = await SigningStargateClient.connectWithSigner(simapp.tendermintUrl, voterWallet);
const voteMsg: MsgVoteWeightedEncodeObject = {
typeUrl: "/cosmos.gov.v1beta1.MsgVoteWeighted",
value: {
proposalId: longify(proposalId),
voter: voter1Address,
options: [
{
option: VoteOption.VOTE_OPTION_YES,
weight: "700000000000000000", // 0.7
},
{
option: VoteOption.VOTE_OPTION_NO,
weight: "200000000000000000", // 0.2
},
{
option: VoteOption.VOTE_OPTION_ABSTAIN,
weight: "100000000000000000", // 0.1
},
],
},
};
const voteResult = await client.signAndBroadcast(voter1Address, [voteMsg], defaultFee);
assertIsDeliverTxSuccess(voteResult);
client.disconnect();
});
it("works with Amino JSON sign mode", async () => {
pendingWithoutSimapp();
assert(voterWalletAmino);
assert(proposalId, "Missing proposal ID");
const client = await SigningStargateClient.connectWithSigner(simapp.tendermintUrl, voterWalletAmino);
const voteMsg: MsgVoteWeightedEncodeObject = {
typeUrl: "/cosmos.gov.v1beta1.MsgVoteWeighted",
value: {
proposalId: longify(proposalId),
voter: voter1Address,
options: [
{
option: VoteOption.VOTE_OPTION_YES,
weight: "700000000000000000", // 0.7
},
{
option: VoteOption.VOTE_OPTION_NO,
weight: "200000000000000000", // 0.2
},
{
option: VoteOption.VOTE_OPTION_ABSTAIN,
weight: "100000000000000000", // 0.1
},
],
},
};
const voteResult = await client.signAndBroadcast(voter1Address, [voteMsg], defaultFee);
assertIsDeliverTxSuccess(voteResult);
client.disconnect();
});
});
});

View File

@ -1,10 +1,11 @@
import { EncodeObject, GeneratedType } from "@cosmjs/proto-signing";
import { MsgDeposit, MsgSubmitProposal, MsgVote } from "cosmjs-types/cosmos/gov/v1beta1/tx";
import { MsgDeposit, MsgSubmitProposal, MsgVote, MsgVoteWeighted } from "cosmjs-types/cosmos/gov/v1beta1/tx";
export const govTypes: ReadonlyArray<[string, GeneratedType]> = [
["/cosmos.gov.v1beta1.MsgDeposit", MsgDeposit],
["/cosmos.gov.v1beta1.MsgSubmitProposal", MsgSubmitProposal],
["/cosmos.gov.v1beta1.MsgVote", MsgVote],
["/cosmos.gov.v1beta1.MsgVoteWeighted", MsgVoteWeighted],
];
export interface MsgDepositEncodeObject extends EncodeObject {
@ -35,3 +36,12 @@ export interface MsgVoteEncodeObject extends EncodeObject {
export function isMsgVoteEncodeObject(object: EncodeObject): object is MsgVoteEncodeObject {
return (object as MsgVoteEncodeObject).typeUrl === "/cosmos.gov.v1beta1.MsgVote";
}
export interface MsgVoteWeightedEncodeObject extends EncodeObject {
readonly typeUrl: "/cosmos.gov.v1beta1.MsgVoteWeighted";
readonly value: Partial<MsgVoteWeighted>;
}
export function isMsgVoteWeightedEncodeObject(object: EncodeObject): object is MsgVoteWeightedEncodeObject {
return (object as MsgVoteWeightedEncodeObject).typeUrl === "/cosmos.gov.v1beta1.MsgVoteWeighted";
}

View File

@ -43,19 +43,23 @@ export {
AminoMsgDeposit,
AminoMsgSubmitProposal,
AminoMsgVote,
AminoMsgVoteWeighted,
createGovAminoConverters,
isAminoMsgDeposit,
isAminoMsgSubmitProposal,
isAminoMsgVote,
isAminoMsgVoteWeighted,
} from "./gov/aminomessages";
export {
govTypes,
isMsgDepositEncodeObject,
isMsgSubmitProposalEncodeObject,
isMsgVoteEncodeObject,
isMsgVoteWeightedEncodeObject,
MsgDepositEncodeObject,
MsgSubmitProposalEncodeObject,
MsgVoteEncodeObject,
MsgVoteWeightedEncodeObject,
} from "./gov/messages";
export { GovExtension, GovParamsType, GovProposalId, setupGovExtension } from "./gov/queries";
export { AminoMsgTransfer, createIbcAminoConverters, isAminoMsgTransfer } from "./ibc/aminomessages";