From 30a2ed74af267d7b283e0d80b92921e10399a6c7 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Thu, 13 Oct 2022 14:57:26 +0200 Subject: [PATCH 1/7] Add MsgBeginRedelegateEncodeObject, MsgCreateValidatorEncodeObject, MsgEditValidatorEncodeObject --- CHANGELOG.md | 2 ++ packages/stargate/src/index.ts | 6 +++++ packages/stargate/src/modules/index.ts | 6 +++++ .../stargate/src/modules/staking/messages.ts | 27 +++++++++++++++++++ 4 files changed, 41 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 50d7dd73b7..f90446211f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,8 @@ and this project adheres to `anyToSinglePubkey`. Export `anyToSinglePubkey`. - @cosmjs/utils: Add `isDefined` which checks for `undefined` in a TypeScript-friendly way. +- @cosmjs/stargate: Add missing `{is,}MsgBeginRedelegateEncodeObject`, + `{is,MsgCreateValidatorEncodeObject}` and `{is,MsgEditValidatorEncodeObject}`. ### Fixed diff --git a/packages/stargate/src/index.ts b/packages/stargate/src/index.ts index b6054fcff0..5b2145068f 100644 --- a/packages/stargate/src/index.ts +++ b/packages/stargate/src/index.ts @@ -61,8 +61,11 @@ export { isAminoMsgVoteWeighted, isAminoMsgWithdrawDelegatorReward, isAminoMsgWithdrawValidatorCommission, + isMsgBeginRedelegateEncodeObject, + isMsgCreateValidatorEncodeObject, isMsgDelegateEncodeObject, isMsgDepositEncodeObject, + isMsgEditValidatorEncodeObject, isMsgSendEncodeObject, isMsgSubmitProposalEncodeObject, isMsgTransferEncodeObject, @@ -72,8 +75,11 @@ export { isMsgWithdrawDelegatorRewardEncodeObject, MintExtension, MintParams, + MsgBeginRedelegateEncodeObject, + MsgCreateValidatorEncodeObject, MsgDelegateEncodeObject, MsgDepositEncodeObject, + MsgEditValidatorEncodeObject, MsgSendEncodeObject, MsgSubmitProposalEncodeObject, MsgTransferEncodeObject, diff --git a/packages/stargate/src/modules/index.ts b/packages/stargate/src/modules/index.ts index fb45f8e882..3a63f0b067 100644 --- a/packages/stargate/src/modules/index.ts +++ b/packages/stargate/src/modules/index.ts @@ -84,9 +84,15 @@ export { isAminoMsgUndelegate, } from "./staking/aminomessages"; export { + isMsgBeginRedelegateEncodeObject, + isMsgCreateValidatorEncodeObject, isMsgDelegateEncodeObject, + isMsgEditValidatorEncodeObject, isMsgUndelegateEncodeObject, + MsgBeginRedelegateEncodeObject, + MsgCreateValidatorEncodeObject, MsgDelegateEncodeObject, + MsgEditValidatorEncodeObject, MsgUndelegateEncodeObject, stakingTypes, } from "./staking/messages"; diff --git a/packages/stargate/src/modules/staking/messages.ts b/packages/stargate/src/modules/staking/messages.ts index e514f7fd4a..7973adc3b8 100644 --- a/packages/stargate/src/modules/staking/messages.ts +++ b/packages/stargate/src/modules/staking/messages.ts @@ -15,6 +15,24 @@ export const stakingTypes: ReadonlyArray<[string, GeneratedType]> = [ ["/cosmos.staking.v1beta1.MsgUndelegate", MsgUndelegate], ]; +export interface MsgBeginRedelegateEncodeObject extends EncodeObject { + readonly typeUrl: "/cosmos.staking.v1beta1.MsgBeginRedelegate"; + readonly value: Partial; +} + +export function isMsgBeginRedelegateEncodeObject(o: EncodeObject): o is MsgBeginRedelegateEncodeObject { + return (o as MsgBeginRedelegateEncodeObject).typeUrl === "/cosmos.staking.v1beta1.MsgBeginRedelegate"; +} + +export interface MsgCreateValidatorEncodeObject extends EncodeObject { + readonly typeUrl: "/cosmos.staking.v1beta1.MsgCreateValidator"; + readonly value: Partial; +} + +export function isMsgCreateValidatorEncodeObject(o: EncodeObject): o is MsgCreateValidatorEncodeObject { + return (o as MsgCreateValidatorEncodeObject).typeUrl === "/cosmos.staking.v1beta1.MsgCreateValidator"; +} + export interface MsgDelegateEncodeObject extends EncodeObject { readonly typeUrl: "/cosmos.staking.v1beta1.MsgDelegate"; readonly value: Partial; @@ -24,6 +42,15 @@ export function isMsgDelegateEncodeObject(object: EncodeObject): object is MsgDe return (object as MsgDelegateEncodeObject).typeUrl === "/cosmos.staking.v1beta1.MsgDelegate"; } +export interface MsgEditValidatorEncodeObject extends EncodeObject { + readonly typeUrl: "/cosmos.staking.v1beta1.MsgEditValidator"; + readonly value: Partial; +} + +export function isMsgEditValidatorEncodeObject(o: EncodeObject): o is MsgEditValidatorEncodeObject { + return (o as MsgEditValidatorEncodeObject).typeUrl === "/cosmos.staking.v1beta1.MsgEditValidator"; +} + export interface MsgUndelegateEncodeObject extends EncodeObject { readonly typeUrl: "/cosmos.staking.v1beta1.MsgUndelegate"; readonly value: Partial; From 672e05f15fd1484141280dd112b7158a19b391d9 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Thu, 13 Oct 2022 15:19:16 +0200 Subject: [PATCH 2/7] Test MsgCreateValidator --- .../src/modules/staking/messages.spec.ts | 81 +++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 packages/stargate/src/modules/staking/messages.spec.ts diff --git a/packages/stargate/src/modules/staking/messages.spec.ts b/packages/stargate/src/modules/staking/messages.spec.ts new file mode 100644 index 0000000000..d5acab46d5 --- /dev/null +++ b/packages/stargate/src/modules/staking/messages.spec.ts @@ -0,0 +1,81 @@ +import { coin } from "@cosmjs/amino"; +import { Random } from "@cosmjs/crypto"; +import { fromBech32, toBase64, toBech32 } from "@cosmjs/encoding"; +import { DirectSecp256k1HdWallet, encodePubkey } from "@cosmjs/proto-signing"; + +import { SigningStargateClient } from "../../signingstargateclient"; +import { assertIsDeliverTxSuccess } from "../../stargateclient"; +import { defaultSigningClientOptions, faucet, pendingWithoutSimapp, simapp } from "../../testutils.spec"; +import { MsgCreateValidatorEncodeObject } from "./messages"; + +function changePrefix(address: string, newPrefix: string): string { + return toBech32(newPrefix, fromBech32(address).data); +} + +describe("staking messages", () => { + describe("MsgCreateValidator", () => { + it("works", async () => { + pendingWithoutSimapp(); + const wallet = await DirectSecp256k1HdWallet.fromMnemonic(faucet.mnemonic); + const [firstAccount] = await wallet.getAccounts(); + const client1 = await SigningStargateClient.connectWithSigner( + simapp.tendermintUrl, + wallet, + defaultSigningClientOptions, + ); + + const valWallet = await DirectSecp256k1HdWallet.generate(); + const [valAccount] = await valWallet.getAccounts(); + + const sendR = await client1.sendTokens( + firstAccount.address, + valAccount.address, + [coin(5000, simapp.denomFee), coin(28, simapp.denomStaking)], + "auto", + ); + assertIsDeliverTxSuccess(sendR); + + const client2 = await SigningStargateClient.connectWithSigner( + simapp.tendermintUrl, + valWallet, + defaultSigningClientOptions, + ); + + const createMsg: MsgCreateValidatorEncodeObject = { + typeUrl: "/cosmos.staking.v1beta1.MsgCreateValidator", + value: { + description: { + moniker: "That's me", + identity: "AABB1234", + website: "http://example.com/me", + details: "What should I write?", + securityContact: "DM on Twitter", + }, + commission: { + maxChangeRate: "10000000000000000", // 0.01 + maxRate: "200000000000000000", // 0.2 + rate: "100000000000000000", // 0.1 + }, + minSelfDelegation: "1", + // Those two addresses need to be the same with different prefix 🤷‍♂️ + delegatorAddress: valAccount.address, + validatorAddress: changePrefix(valAccount.address, "cosmosvaloper"), + pubkey: encodePubkey({ + type: "tendermint/PubKeyEd25519", + value: toBase64(Random.getBytes(32)), + }), + value: { + amount: "1", + denom: simapp.denomStaking, + }, + }, + }; + const result = await client2.signAndBroadcast(valAccount.address, [createMsg], "auto"); + + assertIsDeliverTxSuccess(result); + + client1.disconnect(); + client2.disconnect(); + }); + }); +}); From e92534dcbf6146460241cb3b0bd557b1f620c72a Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Thu, 13 Oct 2022 03:22:02 +0200 Subject: [PATCH 3/7] Pull out sendFeeAndStakingTokens --- .../src/modules/staking/messages.spec.ts | 41 +++++++++++-------- 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/packages/stargate/src/modules/staking/messages.spec.ts b/packages/stargate/src/modules/staking/messages.spec.ts index d5acab46d5..6046ac00c7 100644 --- a/packages/stargate/src/modules/staking/messages.spec.ts +++ b/packages/stargate/src/modules/staking/messages.spec.ts @@ -12,30 +12,36 @@ function changePrefix(address: string, newPrefix: string): string { return toBech32(newPrefix, fromBech32(address).data); } +async function sendFeeAndStakingTokens(address: string): Promise { + const wallet = await DirectSecp256k1HdWallet.fromMnemonic(faucet.mnemonic); + const [firstAccount] = await wallet.getAccounts(); + const client = await SigningStargateClient.connectWithSigner( + simapp.tendermintUrl, + wallet, + defaultSigningClientOptions, + ); + + const res = await client.sendTokens( + firstAccount.address, + address, + [coin(5000, simapp.denomFee), coin(28, simapp.denomStaking)], + "auto", + ); + assertIsDeliverTxSuccess(res); + client.disconnect(); +} + describe("staking messages", () => { describe("MsgCreateValidator", () => { it("works", async () => { pendingWithoutSimapp(); - const wallet = await DirectSecp256k1HdWallet.fromMnemonic(faucet.mnemonic); - const [firstAccount] = await wallet.getAccounts(); - const client1 = await SigningStargateClient.connectWithSigner( - simapp.tendermintUrl, - wallet, - defaultSigningClientOptions, - ); const valWallet = await DirectSecp256k1HdWallet.generate(); const [valAccount] = await valWallet.getAccounts(); - const sendR = await client1.sendTokens( - firstAccount.address, - valAccount.address, - [coin(5000, simapp.denomFee), coin(28, simapp.denomStaking)], - "auto", - ); - assertIsDeliverTxSuccess(sendR); + await sendFeeAndStakingTokens(valAccount.address); - const client2 = await SigningStargateClient.connectWithSigner( + const client = await SigningStargateClient.connectWithSigner( simapp.tendermintUrl, valWallet, defaultSigningClientOptions, @@ -70,12 +76,11 @@ describe("staking messages", () => { }, }, }; - const result = await client2.signAndBroadcast(valAccount.address, [createMsg], "auto"); + const result = await client.signAndBroadcast(valAccount.address, [createMsg], "auto"); assertIsDeliverTxSuccess(result); - client1.disconnect(); - client2.disconnect(); + client.disconnect(); }); }); }); From dbd54f9e24928f35401c161a3a95fa2b2cc3ed52 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Thu, 13 Oct 2022 13:49:30 +0200 Subject: [PATCH 4/7] Fix decimal handling for Amino JSON of MsgCreateValidator and MsgEditValidator --- .../src/modules/staking/aminomessages.spec.ts | 32 +++++++++---------- .../src/modules/staking/aminomessages.ts | 28 +++++++++++----- 2 files changed, 36 insertions(+), 24 deletions(-) diff --git a/packages/stargate/src/modules/staking/aminomessages.spec.ts b/packages/stargate/src/modules/staking/aminomessages.spec.ts index ca8699d863..3a2291463e 100644 --- a/packages/stargate/src/modules/staking/aminomessages.spec.ts +++ b/packages/stargate/src/modules/staking/aminomessages.spec.ts @@ -56,9 +56,9 @@ describe("AminoTypes", () => { details: "...", }, commission: { - rate: "0.2", - maxRate: "0.3", - maxChangeRate: "0.1", + rate: "200000000000000000", // 0.2 + maxRate: "300000000000000000", // 0.3 + maxChangeRate: "100000000000000000", // 0.1 }, minSelfDelegation: "123", delegatorAddress: "cosmos1pkptre7fdkl6gfrzlesjjvhxhlc3r4gmmk8rs6", @@ -85,9 +85,9 @@ describe("AminoTypes", () => { details: "...", }, commission: { - rate: "0.2", - max_rate: "0.3", - max_change_rate: "0.1", + rate: "0.200000000000000000", + max_rate: "0.300000000000000000", + max_change_rate: "0.100000000000000000", }, min_self_delegation: "123", delegator_address: "cosmos1pkptre7fdkl6gfrzlesjjvhxhlc3r4gmmk8rs6", @@ -133,7 +133,7 @@ describe("AminoTypes", () => { securityContact: "Hamburglar", details: "...", }, - commissionRate: "0.2", + commissionRate: "21000000000000000", // 0.021 minSelfDelegation: "123", validatorAddress: "cosmos10dyr9899g6t0pelew4nvf4j5c3jcgv0r73qga5", }; @@ -152,7 +152,7 @@ describe("AminoTypes", () => { security_contact: "Hamburglar", details: "...", }, - commission_rate: "0.2", + commission_rate: "0.021000000000000000", min_self_delegation: "123", validator_address: "cosmos10dyr9899g6t0pelew4nvf4j5c3jcgv0r73qga5", }, @@ -219,9 +219,9 @@ describe("AminoTypes", () => { details: "...", }, commission: { - rate: "0.2", - max_rate: "0.3", - max_change_rate: "0.1", + rate: "0.200000000000000000", + max_rate: "0.300000000000000000", + max_change_rate: "0.100000000000000000", }, min_self_delegation: "123", delegator_address: "cosmos1pkptre7fdkl6gfrzlesjjvhxhlc3r4gmmk8rs6", @@ -243,9 +243,9 @@ describe("AminoTypes", () => { details: "...", }, commission: { - rate: "0.2", - maxRate: "0.3", - maxChangeRate: "0.1", + rate: "200000000000000000", // 0.2 + maxRate: "300000000000000000", // 0.3 + maxChangeRate: "100000000000000000", // 0.1 }, minSelfDelegation: "123", delegatorAddress: "cosmos1pkptre7fdkl6gfrzlesjjvhxhlc3r4gmmk8rs6", @@ -294,7 +294,7 @@ describe("AminoTypes", () => { security_contact: "Hamburglar", details: "...", }, - commission_rate: "0.2", + commission_rate: "0.050000000000000000", // 0.05 min_self_delegation: "123", validator_address: "cosmos10dyr9899g6t0pelew4nvf4j5c3jcgv0r73qga5", }, @@ -308,7 +308,7 @@ describe("AminoTypes", () => { securityContact: "Hamburglar", details: "...", }, - commissionRate: "0.2", + commissionRate: "50000000000000000", // 0.05 minSelfDelegation: "123", validatorAddress: "cosmos10dyr9899g6t0pelew4nvf4j5c3jcgv0r73qga5", }; diff --git a/packages/stargate/src/modules/staking/aminomessages.ts b/packages/stargate/src/modules/staking/aminomessages.ts index 97904b0265..9a4723e9eb 100644 --- a/packages/stargate/src/modules/staking/aminomessages.ts +++ b/packages/stargate/src/modules/staking/aminomessages.ts @@ -1,6 +1,7 @@ /* eslint-disable @typescript-eslint/naming-convention */ import { AminoMsg, Coin, decodeBech32Pubkey, encodeBech32Pubkey } from "@cosmjs/amino"; import { fromBase64, toBase64 } from "@cosmjs/encoding"; +import { Decimal } from "@cosmjs/math"; import { assertDefinedAndNotNull } from "@cosmjs/utils"; import { MsgBeginRedelegate, @@ -28,6 +29,17 @@ interface Description { readonly details: string; } +function protoDecimalToJson(decimal: string): string { + const parsed = Decimal.fromAtomics(decimal, 18); + const [whole, fractional] = parsed.toString().split("."); + return `${whole}.${fractional.padEnd(18, "0")}`; +} + +function jsonDecimalToProto(decimal: string): string { + const parsed = Decimal.fromUserInput(decimal, 18); + return parsed.atomics; +} + /** Creates a new validator. */ export interface AminoMsgCreateValidator extends AminoMsg { readonly type: "cosmos-sdk/MsgCreateValidator"; @@ -175,9 +187,9 @@ export function createStakingAminoConverters( details: description.details, }, commission: { - rate: commission.rate, - max_rate: commission.maxRate, - max_change_rate: commission.maxChangeRate, + rate: protoDecimalToJson(commission.rate), + max_rate: protoDecimalToJson(commission.maxRate), + max_change_rate: protoDecimalToJson(commission.maxChangeRate), }, min_self_delegation: minSelfDelegation, delegator_address: delegatorAddress, @@ -214,9 +226,9 @@ export function createStakingAminoConverters( details: description.details, }, commission: { - rate: commission.rate, - maxRate: commission.max_rate, - maxChangeRate: commission.max_change_rate, + rate: jsonDecimalToProto(commission.rate), + maxRate: jsonDecimalToProto(commission.max_rate), + maxChangeRate: jsonDecimalToProto(commission.max_change_rate), }, minSelfDelegation: min_self_delegation, delegatorAddress: delegator_address, @@ -266,7 +278,7 @@ export function createStakingAminoConverters( security_contact: description.securityContact, details: description.details, }, - commission_rate: commissionRate, + commission_rate: protoDecimalToJson(commissionRate), min_self_delegation: minSelfDelegation, validator_address: validatorAddress, }; @@ -284,7 +296,7 @@ export function createStakingAminoConverters( securityContact: description.security_contact, details: description.details, }, - commissionRate: commission_rate, + commissionRate: jsonDecimalToProto(commission_rate), minSelfDelegation: min_self_delegation, validatorAddress: validator_address, }), From 857270db491a259d388be9176ebffae00fbe8657 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Thu, 13 Oct 2022 15:02:23 +0200 Subject: [PATCH 5/7] Fix pubkey type in AminoMsgCreateValidator and test --- .../src/modules/staking/aminomessages.spec.ts | 34 ++++++++---- .../src/modules/staking/aminomessages.ts | 27 +++------- .../src/modules/staking/messages.spec.ts | 52 ++++++++++++++++++- 3 files changed, 81 insertions(+), 32 deletions(-) diff --git a/packages/stargate/src/modules/staking/aminomessages.spec.ts b/packages/stargate/src/modules/staking/aminomessages.spec.ts index 3a2291463e..53927b2451 100644 --- a/packages/stargate/src/modules/staking/aminomessages.spec.ts +++ b/packages/stargate/src/modules/staking/aminomessages.spec.ts @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/naming-convention */ -import { encodeBech32Pubkey } from "@cosmjs/amino"; import { fromBase64 } from "@cosmjs/encoding"; import { coin } from "@cosmjs/proto-signing"; +import { PubKey as CosmosCryptoSecp256k1Pubkey } from "cosmjs-types/cosmos/crypto/secp256k1/keys"; import { MsgBeginRedelegate, MsgCreateValidator, @@ -65,7 +65,13 @@ describe("AminoTypes", () => { validatorAddress: "cosmos10dyr9899g6t0pelew4nvf4j5c3jcgv0r73qga5", pubkey: { typeUrl: "/cosmos.crypto.secp256k1.PubKey", - value: fromBase64("A08EGB7ro1ORuFhjOnZcSgwYlpe0DSFjVNUIkNNQxwKQ"), + value: Uint8Array.from( + CosmosCryptoSecp256k1Pubkey.encode( + CosmosCryptoSecp256k1Pubkey.fromPartial({ + key: fromBase64("A08EGB7ro1ORuFhjOnZcSgwYlpe0DSFjVNUIkNNQxwKQ"), + }), + ).finish(), + ), }, value: coin(1234, "ucosm"), }; @@ -92,10 +98,10 @@ describe("AminoTypes", () => { min_self_delegation: "123", delegator_address: "cosmos1pkptre7fdkl6gfrzlesjjvhxhlc3r4gmmk8rs6", validator_address: "cosmos10dyr9899g6t0pelew4nvf4j5c3jcgv0r73qga5", - pubkey: encodeBech32Pubkey( - { type: "tendermint/PubKeySecp256k1", value: "A08EGB7ro1ORuFhjOnZcSgwYlpe0DSFjVNUIkNNQxwKQ" }, - "cosmos", - ), + pubkey: { + type: "tendermint/PubKeySecp256k1", + value: "A08EGB7ro1ORuFhjOnZcSgwYlpe0DSFjVNUIkNNQxwKQ", + }, value: coin(1234, "ucosm"), }, }; @@ -226,10 +232,10 @@ describe("AminoTypes", () => { min_self_delegation: "123", delegator_address: "cosmos1pkptre7fdkl6gfrzlesjjvhxhlc3r4gmmk8rs6", validator_address: "cosmos10dyr9899g6t0pelew4nvf4j5c3jcgv0r73qga5", - pubkey: encodeBech32Pubkey( - { type: "tendermint/PubKeySecp256k1", value: "A08EGB7ro1ORuFhjOnZcSgwYlpe0DSFjVNUIkNNQxwKQ" }, - "cosmos", - ), + pubkey: { + type: "tendermint/PubKeySecp256k1", + value: "A08EGB7ro1ORuFhjOnZcSgwYlpe0DSFjVNUIkNNQxwKQ", + }, value: coin(1234, "ucosm"), }, }; @@ -252,7 +258,13 @@ describe("AminoTypes", () => { validatorAddress: "cosmos10dyr9899g6t0pelew4nvf4j5c3jcgv0r73qga5", pubkey: { typeUrl: "/cosmos.crypto.secp256k1.PubKey", - value: fromBase64("A08EGB7ro1ORuFhjOnZcSgwYlpe0DSFjVNUIkNNQxwKQ"), + value: Uint8Array.from( + CosmosCryptoSecp256k1Pubkey.encode( + CosmosCryptoSecp256k1Pubkey.fromPartial({ + key: fromBase64("A08EGB7ro1ORuFhjOnZcSgwYlpe0DSFjVNUIkNNQxwKQ"), + }), + ).finish(), + ), }, value: coin(1234, "ucosm"), }; diff --git a/packages/stargate/src/modules/staking/aminomessages.ts b/packages/stargate/src/modules/staking/aminomessages.ts index 9a4723e9eb..957cbba0dc 100644 --- a/packages/stargate/src/modules/staking/aminomessages.ts +++ b/packages/stargate/src/modules/staking/aminomessages.ts @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/naming-convention */ -import { AminoMsg, Coin, decodeBech32Pubkey, encodeBech32Pubkey } from "@cosmjs/amino"; -import { fromBase64, toBase64 } from "@cosmjs/encoding"; +import { AminoMsg, Coin, Pubkey } from "@cosmjs/amino"; import { Decimal } from "@cosmjs/math"; +import { anyToSinglePubkey, encodePubkey } from "@cosmjs/proto-signing"; import { assertDefinedAndNotNull } from "@cosmjs/utils"; import { MsgBeginRedelegate, @@ -51,8 +51,8 @@ export interface AminoMsgCreateValidator extends AminoMsg { readonly delegator_address: string; /** Bech32 encoded validator address */ readonly validator_address: string; - /** Bech32 encoded public key */ - readonly pubkey: string; + /** Public key */ + readonly pubkey: Pubkey; readonly value: Coin; }; } @@ -132,7 +132,7 @@ export function isAminoMsgUndelegate(msg: AminoMsg): msg is AminoMsgUndelegate { } export function createStakingAminoConverters( - prefix: string, + _prefix: string, ): Record { return { "/cosmos.staking.v1beta1.MsgBeginRedelegate": { @@ -194,13 +194,7 @@ export function createStakingAminoConverters( min_self_delegation: minSelfDelegation, delegator_address: delegatorAddress, validator_address: validatorAddress, - pubkey: encodeBech32Pubkey( - { - type: "tendermint/PubKeySecp256k1", - value: toBase64(pubkey.value), - }, - prefix, - ), + pubkey: anyToSinglePubkey(pubkey), value: value, }; }, @@ -213,10 +207,6 @@ export function createStakingAminoConverters( pubkey, value, }: AminoMsgCreateValidator["value"]): MsgCreateValidator => { - const decodedPubkey = decodeBech32Pubkey(pubkey); - if (decodedPubkey.type !== "tendermint/PubKeySecp256k1") { - throw new Error("Only Secp256k1 public keys are supported"); - } return { description: { moniker: description.moniker, @@ -233,10 +223,7 @@ export function createStakingAminoConverters( minSelfDelegation: min_self_delegation, delegatorAddress: delegator_address, validatorAddress: validator_address, - pubkey: { - typeUrl: "/cosmos.crypto.secp256k1.PubKey", - value: fromBase64(decodedPubkey.value), - }, + pubkey: encodePubkey(pubkey), value: value, }; }, diff --git a/packages/stargate/src/modules/staking/messages.spec.ts b/packages/stargate/src/modules/staking/messages.spec.ts index 6046ac00c7..d49c421b60 100644 --- a/packages/stargate/src/modules/staking/messages.spec.ts +++ b/packages/stargate/src/modules/staking/messages.spec.ts @@ -1,4 +1,4 @@ -import { coin } from "@cosmjs/amino"; +import { coin, Secp256k1HdWallet } from "@cosmjs/amino"; import { Random } from "@cosmjs/crypto"; import { fromBech32, toBase64, toBech32 } from "@cosmjs/encoding"; import { DirectSecp256k1HdWallet, encodePubkey } from "@cosmjs/proto-signing"; @@ -82,5 +82,55 @@ describe("staking messages", () => { client.disconnect(); }); + + it("works with Amino JSON sign mode", async () => { + pendingWithoutSimapp(); + + const valWallet = await Secp256k1HdWallet.generate(); + const [valAccount] = await valWallet.getAccounts(); + + await sendFeeAndStakingTokens(valAccount.address); + + const client = await SigningStargateClient.connectWithSigner( + simapp.tendermintUrl, + valWallet, + defaultSigningClientOptions, + ); + + const createMsg: MsgCreateValidatorEncodeObject = { + typeUrl: "/cosmos.staking.v1beta1.MsgCreateValidator", + value: { + description: { + moniker: "That's me", + identity: "AABB1234", + website: "http://example.com/me", + details: "What should I write?", + securityContact: "DM on Twitter", + }, + commission: { + maxChangeRate: "10000000000000000", // 0.01 + maxRate: "200000000000000000", // 0.2 + rate: "100000000000000000", // 0.1 + }, + minSelfDelegation: "1", + // Those two addresses need to be the same with different prefix 🤷‍♂️ + delegatorAddress: valAccount.address, + validatorAddress: changePrefix(valAccount.address, "cosmosvaloper"), + pubkey: encodePubkey({ + type: "tendermint/PubKeyEd25519", + value: toBase64(Random.getBytes(32)), + }), + value: { + amount: "1", + denom: simapp.denomStaking, + }, + }, + }; + const result = await client.signAndBroadcast(valAccount.address, [createMsg], "auto"); + + assertIsDeliverTxSuccess(result); + + client.disconnect(); + }); }); }); From cb2abf0592f188f65652cc7d296afd98726d2f07 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Thu, 13 Oct 2022 16:30:26 +0200 Subject: [PATCH 6/7] Test MsgEditValidator --- .../src/modules/staking/messages.spec.ts | 165 +++++++++++++++++- 1 file changed, 159 insertions(+), 6 deletions(-) diff --git a/packages/stargate/src/modules/staking/messages.spec.ts b/packages/stargate/src/modules/staking/messages.spec.ts index d49c421b60..a8694fcfad 100644 --- a/packages/stargate/src/modules/staking/messages.spec.ts +++ b/packages/stargate/src/modules/staking/messages.spec.ts @@ -3,10 +3,17 @@ import { Random } from "@cosmjs/crypto"; import { fromBech32, toBase64, toBech32 } from "@cosmjs/encoding"; import { DirectSecp256k1HdWallet, encodePubkey } from "@cosmjs/proto-signing"; +import { calculateFee } from "../../fee"; import { SigningStargateClient } from "../../signingstargateclient"; -import { assertIsDeliverTxSuccess } from "../../stargateclient"; -import { defaultSigningClientOptions, faucet, pendingWithoutSimapp, simapp } from "../../testutils.spec"; -import { MsgCreateValidatorEncodeObject } from "./messages"; +import { assertIsDeliverTxFailure, assertIsDeliverTxSuccess } from "../../stargateclient"; +import { + defaultGasPrice, + defaultSigningClientOptions, + faucet, + pendingWithoutSimapp, + simapp, +} from "../../testutils.spec"; +import { MsgCreateValidatorEncodeObject, MsgEditValidatorEncodeObject } from "./messages"; function changePrefix(address: string, newPrefix: string): string { return toBech32(newPrefix, fromBech32(address).data); @@ -24,7 +31,7 @@ async function sendFeeAndStakingTokens(address: string): Promise { const res = await client.sendTokens( firstAccount.address, address, - [coin(5000, simapp.denomFee), coin(28, simapp.denomStaking)], + [coin(11000, simapp.denomFee), coin(28, simapp.denomStaking)], "auto", ); assertIsDeliverTxSuccess(res); @@ -32,6 +39,9 @@ async function sendFeeAndStakingTokens(address: string): Promise { } describe("staking messages", () => { + const createFee = calculateFee(200_000, defaultGasPrice); + const editFee = calculateFee(200_000, defaultGasPrice); + describe("MsgCreateValidator", () => { it("works", async () => { pendingWithoutSimapp(); @@ -76,7 +86,7 @@ describe("staking messages", () => { }, }, }; - const result = await client.signAndBroadcast(valAccount.address, [createMsg], "auto"); + const result = await client.signAndBroadcast(valAccount.address, [createMsg], createFee); assertIsDeliverTxSuccess(result); @@ -126,10 +136,153 @@ describe("staking messages", () => { }, }, }; - const result = await client.signAndBroadcast(valAccount.address, [createMsg], "auto"); + const result = await client.signAndBroadcast(valAccount.address, [createMsg], createFee); + + assertIsDeliverTxSuccess(result); + + client.disconnect(); + }); + }); + + describe("MsgEditValidator", () => { + it("works", async () => { + pendingWithoutSimapp(); + + const valWallet = await DirectSecp256k1HdWallet.generate(); + const [valAccount] = await valWallet.getAccounts(); + + await sendFeeAndStakingTokens(valAccount.address); + + const client = await SigningStargateClient.connectWithSigner( + simapp.tendermintUrl, + valWallet, + defaultSigningClientOptions, + ); + + const createMsg: MsgCreateValidatorEncodeObject = { + typeUrl: "/cosmos.staking.v1beta1.MsgCreateValidator", + value: { + description: { + moniker: "That's me", + identity: "AABB1234", + website: "http://example.com/me", + details: "What should I write?", + securityContact: "DM on Twitter", + }, + commission: { + maxChangeRate: "10000000000000000", // 0.01 + maxRate: "200000000000000000", // 0.2 + rate: "100000000000000000", // 0.1 + }, + minSelfDelegation: "1", + // Those two addresses need to be the same with different prefix 🤷‍♂️ + delegatorAddress: valAccount.address, + validatorAddress: changePrefix(valAccount.address, "cosmosvaloper"), + pubkey: encodePubkey({ + type: "tendermint/PubKeyEd25519", + value: toBase64(Random.getBytes(32)), + }), + value: { + amount: "1", + denom: simapp.denomStaking, + }, + }, + }; + const result = await client.signAndBroadcast(valAccount.address, [createMsg], createFee); + assertIsDeliverTxSuccess(result); + + const editMsg: MsgEditValidatorEncodeObject = { + typeUrl: "/cosmos.staking.v1beta1.MsgEditValidator", + value: { + commissionRate: "100000000000000000", // we cannot change until 24h have passed + description: { + moniker: "new name", + identity: "ZZZZ", + website: "http://example.com/new-site", + details: "Still no idea", + securityContact: "DM on Discord", + }, + minSelfDelegation: "1", + validatorAddress: changePrefix(valAccount.address, "cosmosvaloper"), // unchanged + }, + }; + const editResult = await client.signAndBroadcast(valAccount.address, [editMsg], editFee); + + // Currently we have no way to unset commissionRate, so the DeliverTx is expected to fail + // with "commission cannot be changed more than once in 24h" :( + assertIsDeliverTxFailure(editResult); + + client.disconnect(); + }); + it("works with Amino JSON sign mode", async () => { + pendingWithoutSimapp(); + + const valWallet = await Secp256k1HdWallet.generate(); + const [valAccount] = await valWallet.getAccounts(); + + await sendFeeAndStakingTokens(valAccount.address); + + const client = await SigningStargateClient.connectWithSigner( + simapp.tendermintUrl, + valWallet, + defaultSigningClientOptions, + ); + + const createMsg: MsgCreateValidatorEncodeObject = { + typeUrl: "/cosmos.staking.v1beta1.MsgCreateValidator", + value: { + description: { + moniker: "That's me", + identity: "AABB1234", + website: "http://example.com/me", + details: "What should I write?", + securityContact: "DM on Twitter", + }, + commission: { + maxChangeRate: "10000000000000000", // 0.01 + maxRate: "200000000000000000", // 0.2 + rate: "100000000000000000", // 0.1 + }, + minSelfDelegation: "1", + // Those two addresses need to be the same with different prefix 🤷‍♂️ + delegatorAddress: valAccount.address, + validatorAddress: changePrefix(valAccount.address, "cosmosvaloper"), + pubkey: encodePubkey({ + type: "tendermint/PubKeyEd25519", + value: toBase64(Random.getBytes(32)), + }), + value: { + amount: "1", + denom: simapp.denomStaking, + }, + }, + }; + const result = await client.signAndBroadcast(valAccount.address, [createMsg], createFee); assertIsDeliverTxSuccess(result); + const editMsg: MsgEditValidatorEncodeObject = { + typeUrl: "/cosmos.staking.v1beta1.MsgEditValidator", + value: { + commissionRate: "100000000000000000", // we cannot change until 24h have passed + description: { + moniker: "new name", + identity: "ZZZZ", + website: "http://example.com/new-site", + details: "Still no idea", + securityContact: "DM on Discord", + }, + minSelfDelegation: "1", + validatorAddress: changePrefix(valAccount.address, "cosmosvaloper"), // unchanged + }, + }; + const editResult = await client.signAndBroadcast(valAccount.address, [editMsg], editFee); + + // Currently we have no way to unset commissionRate, so the DeliverTx is expected to fail + // with "commission cannot be changed more than once in 24h" :( + // assertIsDeliverTxSuccess(editResult); + assertIsDeliverTxFailure(editResult); + client.disconnect(); }); }); From 00ee040b8f43345beff69da5e09e57e9ea850de5 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Thu, 13 Oct 2022 17:10:40 +0200 Subject: [PATCH 7/7] Add CHANGELOG entry --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f90446211f..c7c2498aae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,9 +24,14 @@ and this project adheres to `CosmWasmClient.queryContractSmart`, `SigningCosmWasmClient.instantiate`, `SigningCosmWasmClient.migrate`, `SigningCosmWasmClient.execute`). This reverts the type change done in CosmJS 0.23.0. ([#1281], [#1284]) +- @cosmjs/cosmwasm-stargate: `AminoMsgCreateValidator` and + `createStakingAminoConverters` were fixed after testing both + `MsgCreateValidator` and `MsgEditValidator` in sign mode direct and Amino JSON + ([#1290]). [#1281]: https://github.com/cosmos/cosmjs/pull/1281 [#1284]: https://github.com/cosmos/cosmjs/pull/1284 +[#1290]: https://github.com/cosmos/cosmjs/pull/1290 ## [0.29.1] - 2022-10-09