diff --git a/CHANGELOG.md b/CHANGELOG.md index 1bbafdc428..050a64933d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,12 @@ and this project adheres to - @cosmjs/cosmwasm-stargate: Add structured `Events`s field to `SigningCosmWasmClient`s transaction execution methods. +### Fixed + +- @cosmjs/stargate: Fix Amino JSON encoding of the unset case of + `commission_rate` and `min_self_delegation` in + `MsgEditValidator`/`AminoMsgEditValidator`. + ## [0.29.2] - 2022-10-13 ### Added diff --git a/packages/stargate/src/modules/staking/aminomessages.ts b/packages/stargate/src/modules/staking/aminomessages.ts index 957cbba0dc..5b46ec4ba6 100644 --- a/packages/stargate/src/modules/staking/aminomessages.ts +++ b/packages/stargate/src/modules/staking/aminomessages.ts @@ -68,8 +68,20 @@ export interface AminoMsgEditValidator extends AminoMsg { readonly description: Description; /** Bech32 encoded validator address */ readonly validator_address: string; - readonly commission_rate: string; - readonly min_self_delegation: string; + /** + * The new value for the comission rate. + * + * An empty string in the protobuf document means "do not change". + * In Amino JSON this empty string becomes undefined (omitempty) + */ + readonly commission_rate: string | undefined; + /** + * The new value for the comission rate. + * + * An empty string in the protobuf document means "do not change". + * In Amino JSON this empty string becomes undefined (omitempty) + */ + readonly min_self_delegation: string | undefined; }; } @@ -265,8 +277,10 @@ export function createStakingAminoConverters( security_contact: description.securityContact, details: description.details, }, - commission_rate: protoDecimalToJson(commissionRate), - min_self_delegation: minSelfDelegation, + // empty string in the protobuf document means "do not change" + commission_rate: commissionRate ? protoDecimalToJson(commissionRate) : undefined, + // empty string in the protobuf document means "do not change" + min_self_delegation: minSelfDelegation ? minSelfDelegation : undefined, validator_address: validatorAddress, }; }, @@ -283,8 +297,10 @@ export function createStakingAminoConverters( securityContact: description.security_contact, details: description.details, }, - commissionRate: jsonDecimalToProto(commission_rate), - minSelfDelegation: min_self_delegation, + // empty string in the protobuf document means "do not change" + commissionRate: commission_rate ? jsonDecimalToProto(commission_rate) : "", + // empty string in the protobuf document means "do not change" + minSelfDelegation: min_self_delegation ?? "", validatorAddress: validator_address, }), }, diff --git a/packages/stargate/src/modules/staking/messages.spec.ts b/packages/stargate/src/modules/staking/messages.spec.ts index a8694fcfad..5b8f5208da 100644 --- a/packages/stargate/src/modules/staking/messages.spec.ts +++ b/packages/stargate/src/modules/staking/messages.spec.ts @@ -5,7 +5,7 @@ import { DirectSecp256k1HdWallet, encodePubkey } from "@cosmjs/proto-signing"; import { calculateFee } from "../../fee"; import { SigningStargateClient } from "../../signingstargateclient"; -import { assertIsDeliverTxFailure, assertIsDeliverTxSuccess } from "../../stargateclient"; +import { assertIsDeliverTxSuccess } from "../../stargateclient"; import { defaultGasPrice, defaultSigningClientOptions, @@ -31,7 +31,7 @@ async function sendFeeAndStakingTokens(address: string): Promise { const res = await client.sendTokens( firstAccount.address, address, - [coin(11000, simapp.denomFee), coin(28, simapp.denomStaking)], + [coin(15000, simapp.denomFee), coin(28, simapp.denomStaking)], "auto", ); assertIsDeliverTxSuccess(res); @@ -183,7 +183,7 @@ describe("staking messages", () => { value: toBase64(Random.getBytes(32)), }), value: { - amount: "1", + amount: "3", denom: simapp.denomStaking, }, }, @@ -194,7 +194,6 @@ describe("staking messages", () => { const editMsg: MsgEditValidatorEncodeObject = { typeUrl: "/cosmos.staking.v1beta1.MsgEditValidator", value: { - commissionRate: "100000000000000000", // we cannot change until 24h have passed description: { moniker: "new name", identity: "ZZZZ", @@ -202,15 +201,34 @@ describe("staking messages", () => { details: "Still no idea", securityContact: "DM on Discord", }, - minSelfDelegation: "1", validatorAddress: changePrefix(valAccount.address, "cosmosvaloper"), // unchanged + // Use empty strings to encode the "do not change" case for those two + minSelfDelegation: "", + commissionRate: "", }, }; const editResult = await client.signAndBroadcast(valAccount.address, [editMsg], editFee); + assertIsDeliverTxSuccess(editResult); - // 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); + // Increase min self delegation + const editMsg2: MsgEditValidatorEncodeObject = { + typeUrl: "/cosmos.staking.v1beta1.MsgEditValidator", + value: { + description: { + moniker: "new name", + identity: "ZZZZ", + website: "http://example.com/new-site", + details: "Still no idea", + securityContact: "DM on Discord", + }, + validatorAddress: changePrefix(valAccount.address, "cosmosvaloper"), // unchanged + minSelfDelegation: "3", + // Use empty string to encode the "do not change" + commissionRate: "", + }, + }; + const editResult2 = await client.signAndBroadcast(valAccount.address, [editMsg2], editFee); + assertIsDeliverTxSuccess(editResult2); client.disconnect(); }); @@ -253,7 +271,7 @@ describe("staking messages", () => { value: toBase64(Random.getBytes(32)), }), value: { - amount: "1", + amount: "3", denom: simapp.denomStaking, }, }, @@ -264,7 +282,6 @@ describe("staking messages", () => { const editMsg: MsgEditValidatorEncodeObject = { typeUrl: "/cosmos.staking.v1beta1.MsgEditValidator", value: { - commissionRate: "100000000000000000", // we cannot change until 24h have passed description: { moniker: "new name", identity: "ZZZZ", @@ -272,16 +289,34 @@ describe("staking messages", () => { details: "Still no idea", securityContact: "DM on Discord", }, - minSelfDelegation: "1", validatorAddress: changePrefix(valAccount.address, "cosmosvaloper"), // unchanged + // Use empty strings to encode the "do not change" case for those two + minSelfDelegation: "", + commissionRate: "", }, }; const editResult = await client.signAndBroadcast(valAccount.address, [editMsg], editFee); + assertIsDeliverTxSuccess(editResult); - // 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); + // Increase min self delegation + const editMsg2: MsgEditValidatorEncodeObject = { + typeUrl: "/cosmos.staking.v1beta1.MsgEditValidator", + value: { + description: { + moniker: "new name", + identity: "ZZZZ", + website: "http://example.com/new-site", + details: "Still no idea", + securityContact: "DM on Discord", + }, + validatorAddress: changePrefix(valAccount.address, "cosmosvaloper"), // unchanged + minSelfDelegation: "3", + // Use empty string to encode the "do not change" + commissionRate: "", + }, + }; + const editResult2 = await client.signAndBroadcast(valAccount.address, [editMsg2], editFee); + assertIsDeliverTxSuccess(editResult2); client.disconnect(); });