Skip to content

Commit

Permalink
#391: MsgUnjail support with unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
cdc-Hitesh committed Nov 22, 2022
1 parent 90b89d8 commit c0add99
Show file tree
Hide file tree
Showing 8 changed files with 250 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 { msgUnjail } 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: {
MsgUnjail: msgUnjail(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
140 changes: 140 additions & 0 deletions lib/src/transaction/msg/slashing/MsgUnjail.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
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 { Units } from '../../../coin/coin';
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 (Unbonding)', function () {
fuzzyDescribe('should throw Error when options is invalid', function (fuzzy) {
const anyValidOptions = {
validatorAddress: 'tcrocncl1j7pej8kplem4wt50p4hfvndhuw5jprxxxtenvr',
amount: new cro.Coin('1000', Units.BASE),
};
const testRunner = fuzzy(fuzzy.ObjArg(anyValidOptions));

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

it('Test MsgUnjail conversion', function () {
const MsgUnjail = new cro.v2.slashing.MsgUnjail({
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.MsgUnjail({
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.MsgUnjail(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.MsgUnjail({
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.MsgUnjail.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.MsgUnjail.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.MsgUnjail.fromCosmosMsgJSON(json);
expect(MsgUnjail.validatorAddress).to.eql('tcrocncl1j7pej8kplem4wt50p4hfvndhuw5jprxxxtenvr');
});
});
});
90 changes: 90 additions & 0 deletions lib/src/transaction/msg/slashing/MsgUnjail.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/* 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 interface Amount {
denom: string;
amount: string;
}

export const msgUnjail = 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;
};
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 c0add99

Please sign in to comment.