Skip to content

Commit

Permalink
Merge pull request #392 from cdc-Hitesh/feature/#391/support-MsgUnjail
Browse files Browse the repository at this point in the history
#391: MsgUnjail support with unit tests
  • Loading branch information
calvinaco authored Nov 22, 2022
2 parents 90b89d8 + a67a7c1 commit e231c53
Show file tree
Hide file tree
Showing 9 changed files with 256 additions and 3 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

All notable changes to this project will be documented in this file.

## v1.0.9
- Added support for `MsgUnjail`

## v1.0.8
- Fix wrong commission tx decoding for `MsgCreateValidator` and `MsgEditValidator`

Expand Down
4 changes: 4 additions & 0 deletions lib/src/core/cro.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ import { MsgConnectionOpenConfirmIBC } from '../transaction/msg/ibc/core/connect
import { MsgConnectionOpenTryIBC } from '../transaction/msg/ibc/core/connection/MsgConnectionOpenTry';
import { msgCreateVestingAccount } from '../transaction/msg/account/MsgCreateVestingAccount';
import { delayedVestingAccount } from '../transaction/msg/account/DelayedVestingAccount';
import { msgUnjailV2 } from '../transaction/msg/slashing/MsgUnjail';

export const CroSDK = function (configs: InitConfigurations) {
ow(configs, 'configs', owCroSDKInitParams);
Expand Down Expand Up @@ -126,6 +127,9 @@ export const CroSDK = function (configs: InitConfigurations) {
CommunityPoolSpendProposalV2: communityPoolSpendProposalV2(configs),
},
},
slashing: {
MsgUnjailV2: msgUnjailV2(configs),
},
RawTransactionV2: rawTransactionV2(configs),
CoinV2: coinv2(configs),
},
Expand Down
6 changes: 6 additions & 0 deletions lib/src/transaction/common/constants/typeurl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ export const COSMOS_MSG_TYPEURL = {
PubKey: {
ed25519: '/cosmos.crypto.ed25519.PubKey',
},
slashing: {
MsgUnjail: '/cosmos.slashing.v1beta1.MsgUnjail',
},
upgrade: {
CancelSoftwareUpgradeProposal: '/cosmos.upgrade.v1beta1.CancelSoftwareUpgradeProposal',
SoftwareUpgradeProposal: '/cosmos.upgrade.v1beta1.SoftwareUpgradeProposal',
Expand Down Expand Up @@ -134,6 +137,9 @@ export const typeUrlToMsgClassMapping = (cro: any, typeUrl: string) => {
case COSMOS_MSG_TYPEURL.nft.MsgBurnNFT:
return cro.nft.MsgBurnNFT;

// slashing
case COSMOS_MSG_TYPEURL.slashing.MsgUnjail:
return cro.v2.slashing.MsgUnjail;
default:
throw new Error(`${typeUrl} not supported.`);
}
Expand Down
4 changes: 4 additions & 0 deletions lib/src/transaction/msg/ow.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,10 @@ export const owMsgUndelegateOptions = owStrictObject().exactShape({
amount: owCoin(),
});

export const owMsgUnjailOptions = owStrictObject().exactShape({
validatorAddress: ow.string,
});

export const owMsgWithdrawValidatorCommissionOptions = owStrictObject().exactShape({
validatorAddress: ow.string,
});
Expand Down
138 changes: 138 additions & 0 deletions lib/src/transaction/msg/slashing/MsgUnjail.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
import 'mocha';
import { expect } from 'chai';
import Big from 'big.js';

import { fuzzyDescribe } from '../../../test/mocha-fuzzy/suite';
import { Msg } from '../../../cosmos/v1beta1/types/msg';
import { Secp256k1KeyPair } from '../../../keypair/secp256k1';
import { Bytes } from '../../../utils/bytes/bytes';
import { CroSDK } from '../../../core/cro';
import * as legacyAmino from '../../../cosmos/amino';

const cro = CroSDK({
network: {
defaultNodeUrl: '',
chainId: 'testnet-croeseid-1',
addressPrefix: 'tcro',
validatorAddressPrefix: 'tcrocncl',
validatorPubKeyPrefix: 'tcrocnclconspub',
coin: {
baseDenom: 'basetcro',
croDenom: 'tcro',
},
bip44Path: {
coinType: 1,
account: 0,
},
rpcUrl: '',
},
});

describe('Testing MsgUnjail', function () {
fuzzyDescribe('should throw Error when options is invalid', function (fuzzy) {
const anyValidOptions = {
validatorAddress: 'tcrocncl1j7pej8kplem4wt50p4hfvndhuw5jprxxxtenvr',
};
const testRunner = fuzzy(fuzzy.ObjArg(anyValidOptions));

testRunner(function (options) {
if (options.valid) {
return;
}
expect(() => new cro.v2.slashing.MsgUnjailV2(options.value)).to.throw(
'Expected `options` to be of type `object`',
);
});
});

it('Test MsgUnjail conversion', function () {
const MsgUnjail = new cro.v2.slashing.MsgUnjailV2({
validatorAddress: 'tcrocncl1j7pej8kplem4wt50p4hfvndhuw5jprxxxtenvr',
});

const rawMsg: Msg = {
typeUrl: '/cosmos.slashing.v1beta1.MsgUnjail',
value: {
validatorAddr: 'tcrocncl1j7pej8kplem4wt50p4hfvndhuw5jprxxxtenvr',
},
};

expect(MsgUnjail.toRawMsg()).to.eqls(rawMsg);
});

it('Test appendTxBody MsgUnjail Tx signing', function () {
const anyKeyPair = Secp256k1KeyPair.fromPrivKey(
Bytes.fromHexString('66633d18513bec30dd11a209f1ceb1787aa9e2069d5d47e590174dc9665102b3'),
);

const MsgUnjail = new cro.v2.slashing.MsgUnjailV2({
validatorAddress: 'tcrocncl1j7pej8kplem4wt50p4hfvndhuw5jprxxxtenvr',
});

const anySigner = {
publicKey: anyKeyPair.getPubKey(),
accountNumber: new Big(0),
accountSequence: new Big(2),
};

const rawTx = new cro.RawTransaction();

const signableTx = rawTx.appendMessage(MsgUnjail).addSigner(anySigner).toSignable();

const signedTx = signableTx.setSignature(0, anyKeyPair.sign(signableTx.toSignDocumentHash(0))).toSigned();

const signedTxHex = signedTx.encode().toHexString();
expect(signedTxHex).to.be.eql(
'0a590a570a222f636f736d6f732e736c617368696e672e763162657461312e4d7367556e6a61696c12310a2f7463726f636e636c316a3770656a386b706c656d347774353070346866766e64687577356a707278787874656e767212580a500a460a1f2f636f736d6f732e63727970746f2e736563703235366b312e5075624b657912230a2103fd0d560b6c4aa1ca16721d039a192867c3457e19dad553edb98e7ba88b159c2712040a0208011802120410c09a0c1a40186e87b0b41928e69a1211c1fb5ebcb4c11fa6350f5cc830fa5f38f36f37f66e00d062707672b5d4ebf98cd5e3c7c4b40562707321bb9e8f2d3d605d8beb7b13',
);
});

it('Should validate MsgUnjail provided addresses with network config', function () {
const params2 = {
validatorAddress: 'tcro165tzcrh2yl83g8qeqxueg2g5gzgu57y3fe3kc3',
};

expect(() => new cro.v2.slashing.MsgUnjailV2(params2)).to.throw(
'Provided `validatorAddress` doesnt match network selected',
);
});

describe('Testing MsgUnjail Json', function () {
it('Test MsgUnjail conversion for amino json', function () {
const MsgUnjail = new cro.v2.slashing.MsgUnjailV2({
validatorAddress: 'tcrocncl1j7pej8kplem4wt50p4hfvndhuw5jprxxxtenvr',
});

const rawMsg: legacyAmino.Msg = {
type: 'cosmos-sdk/MsgUnjail',
value: {
validator_addr: 'tcrocncl1j7pej8kplem4wt50p4hfvndhuw5jprxxxtenvr',
},
};

expect(MsgUnjail.toRawAminoMsg()).to.eqls(rawMsg);
});
});
describe('fromCosmosJSON', function () {
it('should throw Error if the JSON is not a MsgUnjail', function () {
const json =
'{ "@type": "/cosmos.bank.v1beta1.MsgCreateValidator", "amount": [{ "denom": "basetcro", "amount": "3478499933290496" }], "from_address": "tcro1x07kkkepfj2hl8etlcuqhej7jj6myqrp48y4hg", "to_address": "tcro184lta2lsyu47vwyp2e8zmtca3k5yq85p6c4vp3" }';
expect(() => cro.v2.slashing.MsgUnjailV2.fromCosmosMsgJSON(json)).to.throw(
'Expected /cosmos.slashing.v1beta1.MsgUnjail but got /cosmos.bank.v1beta1.MsgCreateValidator',
);
});
it('should throw Error when the `validator_address` field is missing', function () {
const json = '{"@type":"/cosmos.slashing.v1beta1.MsgUnjail"}';
expect(() => cro.v2.slashing.MsgUnjailV2.fromCosmosMsgJSON(json)).to.throw(
'Expected property `validatorAddress` to be of type `string` but received type `undefined` in object `options`',
);
});

it('should return the MsgUnjail corresponding to the JSON', function () {
const json =
'{"@type":"/cosmos.slashing.v1beta1.MsgUnjail","validator_addr":"tcrocncl1j7pej8kplem4wt50p4hfvndhuw5jprxxxtenvr"}';
const MsgUnjail = cro.v2.slashing.MsgUnjailV2.fromCosmosMsgJSON(json);
expect(MsgUnjail.validatorAddress).to.eql('tcrocncl1j7pej8kplem4wt50p4hfvndhuw5jprxxxtenvr');
});
});
});
85 changes: 85 additions & 0 deletions lib/src/transaction/msg/slashing/MsgUnjail.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/* eslint-disable camelcase */
import ow from 'ow';
import { Msg } from '../../../cosmos/v1beta1/types/msg';
import { CosmosMsg } from '../cosmosMsg';
import { owMsgUnjailOptions } from '../ow.types';
import { InitConfigurations } from '../../../core/cro';
import { validateAddress, AddressType } from '../../../utils/address';
import { COSMOS_MSG_TYPEURL } from '../../common/constants/typeurl';
import * as legacyAmino from '../../../cosmos/amino';

export interface MsgUnjailRaw {
'@type': string;
validator_addr: string;
}

export const msgUnjailV2 = function (config: InitConfigurations) {
return class MsgUnjail implements CosmosMsg {
/** MsgUnjail validatorAddress. */
public validatorAddress: string;

/**
* Constructor to create a new MsgSend
* @param {IMsgUnjail} options
* @returns {MsgUnjail}
* @throws {Error} when options is invalid
*/
constructor(options: IMsgUnjail) {
ow(options, 'options', owMsgUnjailOptions);
this.validatorAddress = options.validatorAddress;
this.validateAddresses();
}

// eslint-disable-next-line class-methods-use-this
toRawAminoMsg(): legacyAmino.Msg {
return {
type: 'cosmos-sdk/MsgUnjail',
value: {
validator_addr: this.validatorAddress,
},
} as legacyAmino.MsgUnjail;
}

/**
* Returns the raw Msg representation of MsgUnjail
* @returns {Msg}
*/
toRawMsg(): Msg {
return {
typeUrl: COSMOS_MSG_TYPEURL.slashing.MsgUnjail,
value: {
validatorAddr: this.validatorAddress,
},
};
}

/**
* Returns an instance of MsgUnjail
* @param {string} msgJsonStr
* @param {Network} network
* @returns {MsgUnjail}
*/
public static fromCosmosMsgJSON(msgJsonStr: string): MsgUnjail {
const parsedMsg = JSON.parse(msgJsonStr) as MsgUnjailRaw;
if (parsedMsg['@type'] !== COSMOS_MSG_TYPEURL.slashing.MsgUnjail) {
throw new Error(`Expected ${COSMOS_MSG_TYPEURL.slashing.MsgUnjail} but got ${parsedMsg['@type']}`);
}

return new MsgUnjail({
validatorAddress: parsedMsg.validator_addr,
});
}

validateAddresses(): void {
const { network } = config;

if (!validateAddress({ network, address: this.validatorAddress, type: AddressType.VALIDATOR })) {
throw new TypeError('Provided `validatorAddress` doesnt match network selected');
}
}
};
};

export type IMsgUnjail = {
validatorAddress: string;
};
13 changes: 13 additions & 0 deletions lib/src/utils/txDecoder.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,19 @@ describe('TxDecoder', function () {
});
})

context('`MsgUnjail`', function () {
it('should decode `MsgUnjail` correctly', function () {
const txDecoder = new TxDecoder();
expect(
txDecoder
.fromHex(
'0a590a570a222f636f736d6f732e736c617368696e672e763162657461312e4d7367556e6a61696c12310a2f7463726f636e636c316a3770656a386b706c656d347774353070346866766e64687577356a707278787874656e767212580a500a460a1f2f636f736d6f732e63727970746f2e736563703235366b312e5075624b657912230a2103fd0d560b6c4aa1ca16721d039a192867c3457e19dad553edb98e7ba88b159c2712040a0208011802120410c09a0c1a40186e87b0b41928e69a1211c1fb5ebcb4c11fa6350f5cc830fa5f38f36f37f66e00d062707672b5d4ebf98cd5e3c7c4b40562707321bb9e8f2d3d605d8beb7b13',
)
.toCosmosJSON(),
).to.deep.equal(JSON.stringify({ "body": { "messages": [{ "@type": "/cosmos.slashing.v1beta1.MsgUnjail", "validator_addr": "tcrocncl1j7pej8kplem4wt50p4hfvndhuw5jprxxxtenvr" }], "memo": "", "timeout_height": "0", "extension_options": [], "non_critical_extension_options": [] }, "auth_info": { "signer_infos": [{ "public_key": { "@type": "/cosmos.crypto.secp256k1.PubKey", "key": "A/0NVgtsSqHKFnIdA5oZKGfDRX4Z2tVT7bmOe6iLFZwn" }, "mode_info": { "single": { "mode": "SIGN_MODE_DIRECT" } }, "sequence": "2" }], "fee": { "amount": [], "gas_limit": "200000", "payer": "", "granter": "" } }, "signatures": ["GG6HsLQZKOaaEhHB+168tMEfpjUPXMgw+l8482839m4A0GJwdnK11Ov5jNXjx8S0BWJwcyG7no8tPWBdi+t7Ew=="] }));
});
})

it('should decode the transaction correctly FOR CUSTOM MESSAGE PARAMS', function () {
const txDecoder = new TxDecoder();
expect(
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@crypto-org-chain/chain-jslib",
"version": "1.0.8",
"version": "1.0.9",
"description": "Crypto.org Chain JavaScript library",
"author": "Crypto.org <[email protected]>",
"license": "Apache-2.0",
Expand Down

0 comments on commit e231c53

Please sign in to comment.