Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Problem: Support amount list on Messages #282

Merged
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');
});
});
});
});
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