Skip to content

Commit

Permalink
Merge pull request #282 from cdc-Hitesh/#281/support-amountList
Browse files Browse the repository at this point in the history
Problem: Support amount list on Messages
  • Loading branch information
calvinaco authored Jul 5, 2021
2 parents dd7be09 + e21a3ce commit 792a001
Show file tree
Hide file tree
Showing 17 changed files with 1,119 additions and 19 deletions.
1 change: 0 additions & 1 deletion lib/e2e/transaction.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
// @ts-nocheck
/* eslint-disable */
import 'mocha';
import Big from 'big.js';
Expand Down
14 changes: 14 additions & 0 deletions lib/src/core/cro.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ import { msgEditNFT } from '../transaction/msg/nft/MsgEditNFT';
import { msgTransferNFT } from '../transaction/msg/nft/MsgTransferNFT';
import { msgBurnNFT } from '../transaction/msg/nft/MsgBurnNFT';
import { msgSendV2 } from '../transaction/msg/v2/bank/v2.msgsend';
import { msgFundCommunityPoolV2 } from '../transaction/msg/v2/distribution/v2.MsgFundCommunityPool';
import { msgDepositV2 } from '../transaction/msg/v2/gov/v2.MsgDeposit';
import { communityPoolSpendProposalV2 } from '../transaction/msg/v2/gov/proposal/v2.CommunityPoolSpendProposal';
import { msgSubmitProposalV2 } from '../transaction/msg/v2/gov/v2.MsgSubmitProposal';

export const CroSDK = function (configs: InitConfigurations) {
ow(configs, 'configs', owCroSDKInitParams);
Expand Down Expand Up @@ -78,6 +82,16 @@ export const CroSDK = function (configs: InitConfigurations) {
bank: {
MsgSendV2: msgSendV2(configs),
},
distribution: {
MsgFundCommunityPoolV2: msgFundCommunityPoolV2(configs),
},
gov: {
MsgDepositV2: msgDepositV2(configs),
MsgSubmitProposalV2: msgSubmitProposalV2(configs),
proposal: {
CommunityPoolSpendProposalV2: communityPoolSpendProposalV2(configs),
},
},
},
Options: configs,
};
Expand Down
2 changes: 0 additions & 2 deletions lib/src/transaction/msg/bank/msgsend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ export const msgSend = function (config: InitConfigurations) {
return new MsgSend({
fromAddress: parsedMsg.from_address,
toAddress: parsedMsg.to_address,
// TODO: Handle the complete list
amount: cro.Coin.fromCustomAmountDenom(parsedMsg.amount[0].amount, parsedMsg.amount[0].denom),
});
}
Expand Down Expand Up @@ -124,6 +123,5 @@ export const msgSend = function (config: InitConfigurations) {
export type MsgSendOptions = {
fromAddress: string;
toAddress: string;
// Todo: It should be ICoin[]
amount: ICoin;
};
Original file line number Diff line number Diff line change
Expand Up @@ -136,4 +136,4 @@ describe('Testing MsgFundCommunityPool', function () {
expect(msgFundCommPool.amount.toCosmosCoin().denom).to.eql('basetcro');
});
});
});
});
2 changes: 0 additions & 2 deletions lib/src/transaction/msg/distribution/MsgFundCommunityPool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,6 @@ export const msgFundCommunityPool = function (config: InitConfigurations) {

return new MsgFundCommunityPool({
depositor: parsedMsg.depositor,
// TOdo: Handle the complete list
amount: cro.Coin.fromCustomAmountDenom(parsedMsg.amount[0].amount, parsedMsg.amount[0].denom),
});
}
Expand All @@ -97,7 +96,6 @@ export const msgFundCommunityPool = function (config: InitConfigurations) {

export type MsgFundCommunityPoolOptions = {
depositor: string;
// Todo: Make it a list instead
amount: ICoin;
};
interface MsgFundCommunityPoolRaw {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import { IMsgProposalContent } from '../IMsgProposalContent';
import { owSoftwareUpgradeProposalOptions } from '../ow.types';
import { COSMOS_MSG_TYPEURL } from '../../../common/constants/typeurl';
import { Network } from '../../../../network/network';
// import { Network } from '../../../../network/network';

export const softwareUpgradeProposal = function () {
return class SoftwareUpgradeProposal implements IMsgProposalContent {
Expand Down
34 changes: 27 additions & 7 deletions lib/src/transaction/msg/ow.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,13 @@ const voteOptionValidator = (val: number) => ({
message: (label: string) => `Expected ${label} to be one of the Vote options, got \`${val}\``,
});

const proposalContentValidatorFn = (val: object) => ({
validator: isMsgProposalContent(val),
message: (label: string) => `Expected ${label} to be an instance of \`IMsgProposalContent\`, got \`${val}\``,
});

const owContent = () => owStrictObject().validate(proposalContentValidatorFn);

export const owVoteOption = () => ow.number.validate(voteOptionValidator);

export const owMsgSendOptions = owStrictObject().exactShape({
Expand All @@ -22,15 +29,28 @@ export const v2 = {
toAddress: ow.string,
amount: ow.array.ofType(owCoin()),
}),
owMsgFundCommunityPoolOptions: owStrictObject().exactShape({
depositor: ow.string,
amount: ow.array.ofType(owCoin()),
}),
owMsgDepositOptions: owStrictObject().exactShape({
depositor: ow.string,
proposalId: owBig(),
amount: ow.array.ofType(owCoin()),
}),
owCommunityPoolSpendProposalOptions: owStrictObject().exactShape({
title: ow.string,
description: ow.string,
recipient: ow.string,
amount: ow.array.ofType(owCoin()),
}),
owMsgSubmitProposalOptions: owStrictObject().exactShape({
proposer: ow.string,
initialDeposit: ow.array.ofType(owCoin()),
content: owContent(),
}),
};

const proposalContentValidatorFn = (val: object) => ({
validator: isMsgProposalContent(val),
message: (label: string) => `Expected ${label} to be an instance of \`IMsgProposalContent\`, got \`${val}\``,
});

const owContent = () => owStrictObject().validate(proposalContentValidatorFn);

export const owMsgSubmitProposalOptions = owStrictObject().exactShape({
proposer: ow.string,
initialDeposit: owCoin(),
Expand Down
1 change: 0 additions & 1 deletion lib/src/transaction/msg/staking/MsgBeginRedelegate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,6 @@ export const msgBeginRedelegate = function (config: InitConfigurations) {
delegatorAddress: parsedMsg.delegator_address,
validatorDstAddress: parsedMsg.validator_dst_address,
validatorSrcAddress: parsedMsg.validator_src_address,
// TODO: Handle the complete list
amount: cro.Coin.fromCustomAmountDenom(parsedMsg.amount.amount, parsedMsg.amount.denom),
});
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
/* eslint-disable */
import { expect } from 'chai';
import Big from 'big.js';
import { fuzzyDescribe } from '../../../../test/mocha-fuzzy/suite';
import { CroSDK, CroNetwork } from '../../../../core/cro';
import { Secp256k1KeyPair } from '../../../../keypair/secp256k1';
import { Bytes } from '../../../../utils/bytes/bytes';
import * as legacyAmino from '../../../../cosmos/amino';
import { Units } from '../../../../coin/coin';

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: '',
},
});
let amount = new cro.Coin('1000', Units.BASE)

describe('Testing MsgFundCommunityPool', function () {
fuzzyDescribe('should throw Error when options is invalid', function (fuzzy) {
const anyValidOptions = {
depositor: 'tcro165tzcrh2yl83g8qeqxueg2g5gzgu57y3fe3kc3',
amount: [amount],
};
const testRunner = fuzzy(fuzzy.ObjArg(anyValidOptions));

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

it('Test appending MsgFundCommunityPool and signing it', function () {
const anyKeyPair = Secp256k1KeyPair.fromPrivKey(
Bytes.fromHexString('66633d18513bec30dd11a209f1ceb1787aa9e2069d5d47e590174dc9665102b3'),
);

const MsgFundCommunityPool = new cro.v2.distribution.MsgFundCommunityPoolV2({
depositor: 'tcro165tzcrh2yl83g8qeqxueg2g5gzgu57y3fe3kc3',
amount: [amount],
});

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

const rawTx = new cro.RawTransaction();

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

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

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

describe('Testing MsgFundCommunityPool json', function () {
it('Test MsgFundCommunityPool conversion for amino json', function () {
const MsgWithdrawDelegatatorReward = new cro.v2.distribution.MsgFundCommunityPoolV2({
depositor: 'tcro165tzcrh2yl83g8qeqxueg2g5gzgu57y3fe3kc3',
amount: [amount],
});

const rawMsg: legacyAmino.Msg = {
type: 'cosmos-sdk/MsgFundCommunityPool',
value: {
depositor: 'tcro165tzcrh2yl83g8qeqxueg2g5gzgu57y3fe3kc3',
amount: amount.toCosmosCoins(),
},
};

expect(MsgWithdrawDelegatatorReward.toRawAminoMsg()).to.eqls(rawMsg);
});
});

describe('Testing throw scenarios', function () {
it('Should throw on invalid depositor', function () {
expect(() => {
new cro.v2.distribution.MsgFundCommunityPoolV2({
depositor: 'cro1xh3dqgljnydpwelzqf265edryrqrq7wzacx2nr',
amount: [amount],
});
}).to.throw('Provided `depositor` address doesnt match network selected');
});
});
describe('fromCosmosJSON', function () {
it('should throw Error if the JSON is not a MsgFundCommunityPool', function () {
const json =
'{ "@type": "/cosmos.bank.v1beta1.MsgCreateValidator", "amount": [{ "denom": "basetcro", "amount": "3478499933290496" }], "from_address": "tcro1x07kkkepfj2hl8etlcuqhej7jj6myqrp48y4hg", "to_address": "tcro184lta2lsyu47vwyp2e8zmtca3k5yq85p6c4vp3" }';
expect(() => cro.v2.distribution.MsgFundCommunityPoolV2.fromCosmosMsgJSON(json, CroNetwork.Testnet)).to.throw(
'Expected /cosmos.distribution.v1beta1.MsgFundCommunityPool but got /cosmos.bank.v1beta1.MsgCreateValidator',
);
});

it('should throw Error when the `depositor` field is missing', function () {
const json =
'{"@type":"/cosmos.distribution.v1beta1.MsgFundCommunityPool","amount":[{ "denom": "basetcro", "amount": "3478499933290496" }]}';
expect(() => cro.v2.distribution.MsgFundCommunityPoolV2.fromCosmosMsgJSON(json, CroNetwork.Testnet)).to.throw(
'Expected property `depositor` to be of type `string` but received type `undefined` in object `communityPoolOptions`',
);
});
it('should throw Error when the amount field is missing', function () {
const json =
'{"@type":"/cosmos.distribution.v1beta1.MsgFundCommunityPool","depositor":"tcro165tzcrh2yl83g8qeqxueg2g5gzgu57y3fe3kc3"}';
expect(() => cro.v2.distribution.MsgFundCommunityPoolV2.fromCosmosMsgJSON(json, CroNetwork.Testnet)).to.throw(
'Invalid amount in the Msg.',
);
});
it('should return the `MsgFundCommunityPool` corresponding to the JSON', function () {
const json =
'{"@type":"/cosmos.distribution.v1beta1.MsgFundCommunityPool","amount":[{ "denom": "basetcro", "amount": "3478499933290496" }],"depositor":"tcro165tzcrh2yl83g8qeqxueg2g5gzgu57y3fe3kc3"}';

const msgFundCommPool = cro.v2.distribution.MsgFundCommunityPoolV2.fromCosmosMsgJSON(json, CroNetwork.Testnet);
expect(msgFundCommPool.depositor).to.eql('tcro165tzcrh2yl83g8qeqxueg2g5gzgu57y3fe3kc3');
expect(msgFundCommPool.amount[0].toCosmosCoin().amount).to.eql('3478499933290496');
expect(msgFundCommPool.amount[0].toCosmosCoin().denom).to.eql('basetcro');
});
});
});
110 changes: 110 additions & 0 deletions lib/src/transaction/msg/v2/distribution/v2.MsgFundCommunityPool.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import ow from 'ow';
import { CosmosMsg } from '../../cosmosMsg';
import { Msg } from '../../../../cosmos/v1beta1/types/msg';
import { InitConfigurations, CroSDK } from '../../../../core/cro';
import { AddressType, validateAddress } from '../../../../utils/address';
import { v2 } from '../../ow.types';
import { COSMOS_MSG_TYPEURL } from '../../../common/constants/typeurl';
import * as legacyAmino from '../../../../cosmos/amino';
import { ICoin } from '../../../../coin/coin';
import { Network } from '../../../../network/network';

export const msgFundCommunityPoolV2 = function (config: InitConfigurations) {
return class MsgFundCommunityPoolV2 implements CosmosMsg {
// Normal user addresses with (t)cro prefix
public readonly depositor: string;

public amount: ICoin[];

/**
* Constructor to create a new MsgFundCommunityPool
* @param {MsgFundCommunityPoolOptions} options
* @returns {MsgFundCommunityPoolV2}
* @throws {Error} when options is invalid
*/
constructor(options: MsgFundCommunityPoolOptions) {
ow(options, 'communityPoolOptions', v2.owMsgFundCommunityPoolOptions);

this.depositor = options.depositor;
this.amount = options.amount;

this.validateAddresses();
}

// eslint-disable-next-line class-methods-use-this
toRawAminoMsg(): legacyAmino.Msg {
return {
type: 'cosmos-sdk/MsgFundCommunityPool',
value: {
depositor: this.depositor,
amount: this.amount.map((coin) => coin.toCosmosCoin()),
},
} as legacyAmino.MsgFundCommunityPool;
}

/**
* Returns the raw Msg representation of MsgFundCommunityPool
* @returns {Msg}
*/
toRawMsg(): Msg {
return {
typeUrl: COSMOS_MSG_TYPEURL.distribution.MsgFundCommunityPool,
value: {
depositor: this.depositor,
amount: this.amount.map((coin) => coin.toCosmosCoin()),
},
};
}

/**
* Returns an instance of MsgFundCommunityPool
* @param {string} msgJsonStr
* @param {Network} network
* @returns {MsgFundCommunityPool}
*/
public static fromCosmosMsgJSON(msgJsonStr: string, network: Network): MsgFundCommunityPoolV2 {
const parsedMsg = JSON.parse(msgJsonStr) as MsgFundCommunityPoolRaw;
const cro = CroSDK({ network });
if (parsedMsg['@type'] !== COSMOS_MSG_TYPEURL.distribution.MsgFundCommunityPool) {
throw new Error(
`Expected ${COSMOS_MSG_TYPEURL.distribution.MsgFundCommunityPool} but got ${parsedMsg['@type']}`,
);
}
if (!parsedMsg.amount || parsedMsg.amount.length < 1) {
throw new Error('Invalid amount in the Msg.');
}

return new MsgFundCommunityPoolV2({
depositor: parsedMsg.depositor,
amount: parsedMsg.amount.map((coin) => cro.Coin.fromCustomAmountDenom(coin.amount, coin.denom)),
});
}

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

export type MsgFundCommunityPoolOptions = {
depositor: string;
amount: ICoin[];
};
interface MsgFundCommunityPoolRaw {
'@type': string;
amount: Amount[];
depositor: string;
}

interface Amount {
denom: string;
amount: string;
}
Loading

0 comments on commit 792a001

Please sign in to comment.