From 475e285d4195e29009ce52c5de8951ff613421c3 Mon Sep 17 00:00:00 2001 From: cdc-Hitesh Date: Tue, 22 Jun 2021 12:07:47 +0530 Subject: [PATCH 1/3] #284: Support MsgUpdateClient --- lib/src/core/cro.ts | 2 + lib/src/cosmos/v1beta1/types/typeurls.ts | 1 + .../transaction/common/constants/typeurl.ts | 1 + .../msg/ibc/core/MsgUpdateClient.spec.ts | 120 ++++++++++++++++++ .../msg/ibc/core/MsgUpdateClient.ts | 75 +++++++++++ lib/src/transaction/msg/ow.types.ts | 6 + 6 files changed, 205 insertions(+) create mode 100644 lib/src/transaction/msg/ibc/core/MsgUpdateClient.spec.ts create mode 100644 lib/src/transaction/msg/ibc/core/MsgUpdateClient.ts diff --git a/lib/src/core/cro.ts b/lib/src/core/cro.ts index 27f8c255..2909b5c5 100644 --- a/lib/src/core/cro.ts +++ b/lib/src/core/cro.ts @@ -31,6 +31,7 @@ import { msgTransferNFT } from '../transaction/msg/nft/MsgTransferNFT'; import { msgBurnNFT } from '../transaction/msg/nft/MsgBurnNFT'; import { msgTransferIBC } from '../transaction/msg/ibc/applications/MsgTransfer'; import { msgCreateClientIBC } from '../transaction/msg/ibc/core/MsgCreateClient'; +import { msgUpdateClientIBC } from '../transaction/msg/ibc/core/MsgUpdateClient'; export const CroSDK = function (configs: InitConfigurations) { ow(configs, 'configs', owCroSDKInitParams); @@ -79,6 +80,7 @@ export const CroSDK = function (configs: InitConfigurations) { ibc: { MsgTransfer: msgTransferIBC(configs), MsgCreateClient: msgCreateClientIBC(configs), + MsgUpdateClient: msgUpdateClientIBC(configs), }, Options: configs, }; diff --git a/lib/src/cosmos/v1beta1/types/typeurls.ts b/lib/src/cosmos/v1beta1/types/typeurls.ts index 1a4d1e18..1d62b041 100644 --- a/lib/src/cosmos/v1beta1/types/typeurls.ts +++ b/lib/src/cosmos/v1beta1/types/typeurls.ts @@ -33,6 +33,7 @@ export const typeUrlMappings: { '/chainmain.nft.v1.MsgBurnNFT': chainmain.nft.v1.MsgBurnNFT, '/ibc.applications.transfer.v1.MsgTransfer': ibc.applications.transfer.v1.MsgTransfer, '/ibc.core.client.v1.MsgCreateClient': ibc.core.client.v1.MsgCreateClient, + '/ibc.core.client.v1.MsgUpdateClient': ibc.core.client.v1.MsgUpdateClient, }; export interface GeneratedType { diff --git a/lib/src/transaction/common/constants/typeurl.ts b/lib/src/transaction/common/constants/typeurl.ts index 9c0b4757..78e43c38 100644 --- a/lib/src/transaction/common/constants/typeurl.ts +++ b/lib/src/transaction/common/constants/typeurl.ts @@ -35,5 +35,6 @@ export const COSMOS_MSG_TYPEURL = { ibc: { MsgTransfer: '/ibc.applications.transfer.v1.MsgTransfer', MsgCreateClient: '/ibc.core.client.v1.MsgCreateClient', + MsgUpdateClient: '/ibc.core.client.v1.MsgUpdateClient', }, }; diff --git a/lib/src/transaction/msg/ibc/core/MsgUpdateClient.spec.ts b/lib/src/transaction/msg/ibc/core/MsgUpdateClient.spec.ts new file mode 100644 index 00000000..5d4c646c --- /dev/null +++ b/lib/src/transaction/msg/ibc/core/MsgUpdateClient.spec.ts @@ -0,0 +1,120 @@ +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 { COSMOS_MSG_TYPEURL } from '../../../common/constants/typeurl'; +import { google } from '../../../../cosmos/v1beta1/codec'; + +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 MsgUpdateClient', function () { + fuzzyDescribe('should throw Error when options is invalid', function (fuzzy) { + const anyValidOptions = { + signer: 'tcro15sfupd26sp6qf37ll5q6xuf330k7df9tnvrqht', + }; + + const testRunner = fuzzy(fuzzy.ObjArg(anyValidOptions)); + + testRunner(function (options) { + if (options.valid) { + return; + } + expect(() => new cro.ibc.MsgUpdateClient(options.value)).to.throw( + 'Expected `options` to be of type `object`', + ); + }); + }); + + it('Test MsgUpdateClient conversion', function () { + const MsgUpdateClient = new cro.ibc.MsgUpdateClient({ + signer: 'tcro15sfupd26sp6qf37ll5q6xuf330k7df9tnvrqht', + clientId: 'clientId', + header: null, + }); + + const rawMsg: Msg = { + typeUrl: COSMOS_MSG_TYPEURL.ibc.MsgUpdateClient, + value: { + signer: 'tcro15sfupd26sp6qf37ll5q6xuf330k7df9tnvrqht', + clientId: 'clientId', + header: null, + }, + }; + + expect(MsgUpdateClient.toRawMsg()).to.eqls(rawMsg); + }); + + it('Test appendTxBody MsgUpdateClient Tx signing', function () { + const anyKeyPair = Secp256k1KeyPair.fromPrivKey( + Bytes.fromHexString('66633d18513bec30dd11a209f1ceb1787aa9e2069d5d47e590174dc9665102b3'), + ); + + const MsgUpdateClient = new cro.ibc.MsgUpdateClient({ + signer: 'tcro15sfupd26sp6qf37ll5q6xuf330k7df9tnvrqht', + header: google.protobuf.Any.create({ + type_url: '/some.valid.type.url', + value: new Uint8Array([1, 2, 35, 5]), + }), + clientId: 'clientId', + }); + + const anySigner = { + publicKey: anyKeyPair.getPubKey(), + accountNumber: new Big(0), + accountSequence: new Big(2), + }; + + const rawTx = new cro.RawTransaction(); + + const signableTx = rawTx.appendMessage(MsgUpdateClient).addSigner(anySigner).toSignable(); + + const signedTx = signableTx.setSignature(0, anyKeyPair.sign(signableTx.toSignDocumentHash(0))).toSigned(); + + const signedTxHex = signedTx.encode().toHexString(); + expect(signedTxHex).to.be.eql( + '0a7e0a7c0a232f6962632e636f72652e636c69656e742e76312e4d7367557064617465436c69656e7412550a08636c69656e744964121c0a142f736f6d652e76616c69642e747970652e75726c1204010223051a2b7463726f313573667570643236737036716633376c6c3571367875663333306b37646639746e767271687412580a500a460a1f2f636f736d6f732e63727970746f2e736563703235366b312e5075624b657912230a2103fd0d560b6c4aa1ca16721d039a192867c3457e19dad553edb98e7ba88b159c2712040a0208011802120410c09a0c1a40a3e29655c317f80832e34c978220cbd8d9f38a80353228b6d3b2db4a3d7eafe5717f449fa2ab5afacb0531ca63afb55b9088571248cf07876896595459487cd2', + ); + }); + + it('Should validate MsgUpdateClient provided addresses with network config', function () { + const params1 = { + signer: 'cosmos1vw4ucaeagtduv5ep4sa95e3aqzqpsk5meda08c', + clientId: 'clientId', + }; + + expect(() => new cro.ibc.MsgUpdateClient(params1)).to.throw( + 'Provided `signer` does not match network selected', + ); + }); + + it('Should throw on getting toRawAminoMsg()', function () { + const MsgUpdateClient = new cro.ibc.MsgUpdateClient({ + signer: 'tcro15sfupd26sp6qf37ll5q6xuf330k7df9tnvrqht', + clientId: 'clientId', + }); + + expect(() => MsgUpdateClient.toRawAminoMsg()).to.throw('IBC Module not supported under amino encoding scheme'); + }); +}); diff --git a/lib/src/transaction/msg/ibc/core/MsgUpdateClient.ts b/lib/src/transaction/msg/ibc/core/MsgUpdateClient.ts new file mode 100644 index 00000000..6663f180 --- /dev/null +++ b/lib/src/transaction/msg/ibc/core/MsgUpdateClient.ts @@ -0,0 +1,75 @@ +import ow from 'ow'; +import { google } from '../../../../cosmos/v1beta1/codec/generated/codecimpl'; +import { InitConfigurations } from '../../../../core/cro'; +import { CosmosMsg } from '../../cosmosMsg'; +import { Msg } from '../../../../cosmos/v1beta1/types/msg'; +import { COSMOS_MSG_TYPEURL } from '../../../common/constants/typeurl'; +import { validateAddress, AddressType } from '../../../../utils/address'; +import { owMsgUpdateClientOptions } from '../../ow.types'; +import * as legacyAmino from '../../../../cosmos/amino'; + +export const msgUpdateClientIBC = function (config: InitConfigurations) { + return class MsgUpdateClient implements CosmosMsg { + /** MsgUpdateClient clientId. */ + public clientId: string; + + /** MsgUpdateClient header. */ + public header?: google.protobuf.IAny | null; + + /** MsgUpdateClient signer. */ + public signer: string; + + /** + * Constructor to create a new IBC.MsgUpdateClient + * @param {MsgUpdateClientOptions} options + * @returns {MsgUpdateClient} + * @throws {Error} when options is invalid + */ + constructor(options: MsgUpdateClientOptions) { + ow(options, 'options', owMsgUpdateClientOptions); + this.clientId = options.clientId; + this.header = options.header; + this.signer = options.signer; + this.validateAddresses(); + } + + /** + * Returns the raw Msg representation of Ibc.MsgUpdateClient + * @returns {Msg} + */ + toRawMsg(): Msg { + return { + typeUrl: COSMOS_MSG_TYPEURL.ibc.MsgUpdateClient, + value: { + clientId: this.clientId, + header: this.header, + signer: this.signer, + }, + }; + } + + // eslint-disable-next-line class-methods-use-this + toRawAminoMsg(): legacyAmino.Msg { + throw new Error('IBC Module not supported under amino encoding scheme'); + } + + validateAddresses() { + // TODO: Can `signer` be from non-CRO network + if ( + !validateAddress({ + address: this.signer, + network: config.network, + type: AddressType.USER, + }) + ) { + throw new TypeError('Provided `signer` does not match network selected'); + } + } + }; +}; + +export type MsgUpdateClientOptions = { + clientId: string; + header?: google.protobuf.IAny | null; + signer: string; +}; diff --git a/lib/src/transaction/msg/ow.types.ts b/lib/src/transaction/msg/ow.types.ts index 6061867d..00ebed4d 100644 --- a/lib/src/transaction/msg/ow.types.ts +++ b/lib/src/transaction/msg/ow.types.ts @@ -211,3 +211,9 @@ export const owMsgCreateClientOptions = owStrictObject().exactShape({ clientState: owGoogleProtoAnyOptional(), consensusState: owGoogleProtoAnyOptional(), }); + +export const owMsgUpdateClientOptions = owStrictObject().exactShape({ + signer: ow.string, + clientId: ow.string, + header: ow.optional.any(owGoogleProtoAnyOptional(), ow.optional.null), +}); From b36cb14d882d1c3be18ea5f0cbd92e70408c7eda Mon Sep 17 00:00:00 2001 From: cdc-Hitesh Date: Thu, 8 Jul 2021 16:26:40 +0530 Subject: [PATCH 2/3] #284: Support MsgUpdateClient --- .../transaction/common/constants/typeurl.ts | 2 + .../msg/ibc/core/MsgUpdateClient.spec.ts | 57 +++++++-- .../msg/ibc/core/MsgUpdateClient.ts | 119 ++++++++++++++++++ 3 files changed, 171 insertions(+), 7 deletions(-) diff --git a/lib/src/transaction/common/constants/typeurl.ts b/lib/src/transaction/common/constants/typeurl.ts index b65b2983..7beb67b7 100644 --- a/lib/src/transaction/common/constants/typeurl.ts +++ b/lib/src/transaction/common/constants/typeurl.ts @@ -94,6 +94,8 @@ export const typeUrlToMsgClassMapping = (cro: any, typeUrl: string) => { return cro.ibc.MsgTransfer; case COSMOS_MSG_TYPEURL.ibc.MsgCreateClient: return cro.ibc.MsgCreateClient; + case COSMOS_MSG_TYPEURL.ibc.MsgUpdateClient: + return cro.ibc.MsgUpdateClient; // nft case COSMOS_MSG_TYPEURL.nft.MsgIssueDenom: diff --git a/lib/src/transaction/msg/ibc/core/MsgUpdateClient.spec.ts b/lib/src/transaction/msg/ibc/core/MsgUpdateClient.spec.ts index 5d4c646c..5b71087f 100644 --- a/lib/src/transaction/msg/ibc/core/MsgUpdateClient.spec.ts +++ b/lib/src/transaction/msg/ibc/core/MsgUpdateClient.spec.ts @@ -6,9 +6,8 @@ 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 { CroSDK, CroNetwork } from '../../../../core/cro'; import { COSMOS_MSG_TYPEURL } from '../../../common/constants/typeurl'; -import { google } from '../../../../cosmos/v1beta1/codec'; const cro = CroSDK({ network: { @@ -73,10 +72,7 @@ describe('Testing MsgUpdateClient', function () { const MsgUpdateClient = new cro.ibc.MsgUpdateClient({ signer: 'tcro15sfupd26sp6qf37ll5q6xuf330k7df9tnvrqht', - header: google.protobuf.Any.create({ - type_url: '/some.valid.type.url', - value: new Uint8Array([1, 2, 35, 5]), - }), + header: undefined, clientId: 'clientId', }); @@ -94,7 +90,7 @@ describe('Testing MsgUpdateClient', function () { const signedTxHex = signedTx.encode().toHexString(); expect(signedTxHex).to.be.eql( - '0a7e0a7c0a232f6962632e636f72652e636c69656e742e76312e4d7367557064617465436c69656e7412550a08636c69656e744964121c0a142f736f6d652e76616c69642e747970652e75726c1204010223051a2b7463726f313573667570643236737036716633376c6c3571367875663333306b37646639746e767271687412580a500a460a1f2f636f736d6f732e63727970746f2e736563703235366b312e5075624b657912230a2103fd0d560b6c4aa1ca16721d039a192867c3457e19dad553edb98e7ba88b159c2712040a0208011802120410c09a0c1a40a3e29655c317f80832e34c978220cbd8d9f38a80353228b6d3b2db4a3d7eafe5717f449fa2ab5afacb0531ca63afb55b9088571248cf07876896595459487cd2', + '0a600a5e0a232f6962632e636f72652e636c69656e742e76312e4d7367557064617465436c69656e7412370a08636c69656e7449641a2b7463726f313573667570643236737036716633376c6c3571367875663333306b37646639746e767271687412580a500a460a1f2f636f736d6f732e63727970746f2e736563703235366b312e5075624b657912230a2103fd0d560b6c4aa1ca16721d039a192867c3457e19dad553edb98e7ba88b159c2712040a0208011802120410c09a0c1a40c8529d07e0c51b9d14a2fc77475c6ffbefd4fed6305392f5979f489164e6102546f3e5c537fcbee75587e36eb0206326639c6807d0e2afd1d1c3c3c16e7ec5ec', ); }); @@ -117,4 +113,51 @@ describe('Testing MsgUpdateClient', function () { expect(() => MsgUpdateClient.toRawAminoMsg()).to.throw('IBC Module not supported under amino encoding scheme'); }); + describe('fromCosmosJSON', function () { + it('should throw Error if the JSON is not a IBC MsgUpdateClient', function () { + const json = + '{ "@type": "/cosmos.bank.v1beta1.MsgCreateValidator", "amount": [{ "denom": "basetcro", "amount": "3478499933290496" }], "from_address": "tcro1x07kkkepfj2hl8etlcuqhej7jj6myqrp48y4hg", "to_address": "tcro184lta2lsyu47vwyp2e8zmtca3k5yq85p6c4vp3" }'; + expect(() => cro.ibc.MsgUpdateClient.fromCosmosMsgJSON(json, CroNetwork.Testnet)).to.throw( + 'Expected /ibc.core.client.v1.MsgUpdateClient but got /cosmos.bank.v1beta1.MsgCreateValidator', + ); + }); + it('should throw on invalid `signer`', function () { + const json = ` + { + "@type": "/ibc.core.client.v1.MsgUpdateClient", + "signer": "cosmos1u8prj0rj3ur7kr23dhjgyteuq55ntahfuzlf6g", + "client_id": "07-tendermint-33" + } + `; + + expect(() => cro.ibc.MsgUpdateClient.fromCosmosMsgJSON(json, CroNetwork.Testnet)).to.throw( + 'Provided `signer` does not match network selected', + ); + }); + it('should throw on invalid `clientId`', function () { + const json = ` + { + "@type": "/ibc.core.client.v1.MsgUpdateClient", + "signer": "cosmos1u8prj0rj3ur7kr23dhjgyteuq55ntahfuzlf6g" + } + `; + + expect(() => cro.ibc.MsgUpdateClient.fromCosmosMsgJSON(json, CroNetwork.Testnet)).to.throw( + 'Expected property `clientId` to be of type `string` but received type `undefined` in object `options`', + ); + }); + it('should return the IBC MsgUpdateClient corresponding to the JSON', function () { + const json = `{ + "@type": "/ibc.core.client.v1.MsgUpdateClient", + "signer": "tcro1agr5hwr6gxljf4kpg6fm7l7ehjxtyazg86nef8", + "client_id": "07-tendermint-33" + } + `; + + const MsgUpdateClient = cro.ibc.MsgUpdateClient.fromCosmosMsgJSON(json, CroNetwork.Testnet); + expect(MsgUpdateClient.signer).to.eql('tcro1agr5hwr6gxljf4kpg6fm7l7ehjxtyazg86nef8'); + expect(MsgUpdateClient.clientId).to.eql('07-tendermint-33'); + expect(MsgUpdateClient.header).to.be.null; + }); + }); }); diff --git a/lib/src/transaction/msg/ibc/core/MsgUpdateClient.ts b/lib/src/transaction/msg/ibc/core/MsgUpdateClient.ts index 6663f180..fa2765c2 100644 --- a/lib/src/transaction/msg/ibc/core/MsgUpdateClient.ts +++ b/lib/src/transaction/msg/ibc/core/MsgUpdateClient.ts @@ -1,3 +1,4 @@ +/* eslint-disable camelcase */ import ow from 'ow'; import { google } from '../../../../cosmos/v1beta1/codec/generated/codecimpl'; import { InitConfigurations } from '../../../../core/cro'; @@ -7,6 +8,7 @@ import { COSMOS_MSG_TYPEURL } from '../../../common/constants/typeurl'; import { validateAddress, AddressType } from '../../../../utils/address'; import { owMsgUpdateClientOptions } from '../../ow.types'; import * as legacyAmino from '../../../../cosmos/amino'; +import { Network } from '../../../../network/network'; export const msgUpdateClientIBC = function (config: InitConfigurations) { return class MsgUpdateClient implements CosmosMsg { @@ -53,6 +55,30 @@ export const msgUpdateClientIBC = function (config: InitConfigurations) { throw new Error('IBC Module not supported under amino encoding scheme'); } + /** + * Returns an instance of IBC.MsgUpdateClient + * @param {string} msgJsonStr + * @param {Network} network + * @returns {MsgUpdateClient} + */ + public static fromCosmosMsgJSON(msgJsonStr: string, _network: Network): MsgUpdateClient { + const parsedMsg = JSON.parse(msgJsonStr) as MsgUpdateClientJsonRaw; + if (parsedMsg['@type'] !== COSMOS_MSG_TYPEURL.ibc.MsgUpdateClient) { + throw new Error(`Expected ${COSMOS_MSG_TYPEURL.ibc.MsgUpdateClient} but got ${parsedMsg['@type']}`); + } + + // TODO: The `header` value needs to be handled, currently keeping it as `null` + if (typeof parsedMsg.header === 'object' && Object.keys(parsedMsg.header).length > 0) { + throw new Error('IBC MsgUpdateClient does not support `header` decoding.'); + } + + return new MsgUpdateClient({ + clientId: parsedMsg.client_id, + header: null, + signer: parsedMsg.signer, + }); + } + validateAddresses() { // TODO: Can `signer` be from non-CRO network if ( @@ -73,3 +99,96 @@ export type MsgUpdateClientOptions = { header?: google.protobuf.IAny | null; signer: string; }; + +export interface MsgUpdateClientJsonRaw { + '@type': string; + client_id: string; + header: any | MsgUpdateClientJsonRawHeader; + signer: string; +} + +export interface MsgUpdateClientJsonRawHeader { + '@type': string; + signed_header: SignedHeader; + validator_set: TrustedValidators; + trusted_height: TrustedHeight; + trusted_validators: TrustedValidators; +} + +export interface SignedHeader { + header: SignedHeaderHeader; + commit: Commit; +} + +export interface Commit { + height: string; + round: number; + block_id: Blockid; + signatures: Signature[]; +} + +export interface Blockid { + hash: string; + part_set_header: PartSetHeader; +} + +export interface PartSetHeader { + total: number; + hash: string; +} + +export interface Signature { + block_id_flag: BlockidFlag; + validator_address: null | string; + timestamp: Date; + signature: null | string; +} + +export enum BlockidFlag { + BlockIDFlagAbsent = 'BLOCK_ID_FLAG_ABSENT', + BlockIDFlagCommit = 'BLOCK_ID_FLAG_COMMIT', +} + +export interface SignedHeaderHeader { + version: Version; + chain_id: string; + height: string; + time: Date; + last_block_id: Blockid; + last_commit_hash: string; + data_hash: string; + validators_hash: string; + next_validators_hash: string; + consensus_hash: string; + app_hash: string; + last_results_hash: string; + evidence_hash: string; + proposer_address: string; +} + +export interface Version { + block: string; + app: string; +} + +export interface TrustedHeight { + revision_number: string; + revision_height: string; +} + +export interface TrustedValidators { + validators: Proposer[]; + proposer: Proposer; + total_voting_power: string; +} + +export interface Proposer { + address: string; + pub_key: PubKey; + voting_power: string; + proposer_priority: string; +} + +export interface PubKey { + ed25519: string; +} From 0065f3c73329af7f23792680e6fe2fc33666122c Mon Sep 17 00:00:00 2001 From: cdc-Hitesh Date: Thu, 8 Jul 2021 16:31:19 +0530 Subject: [PATCH 3/3] MsgCreateClient fixed. --- .../msg/ibc/core/MsgCreateClient.spec.ts | 13 +-- .../msg/ibc/core/MsgCreateClient.ts | 89 ++++++++++++++++--- .../msg/ibc/core/MsgUpdateClient.ts | 2 +- 3 files changed, 81 insertions(+), 23 deletions(-) diff --git a/lib/src/transaction/msg/ibc/core/MsgCreateClient.spec.ts b/lib/src/transaction/msg/ibc/core/MsgCreateClient.spec.ts index 7f0f9ef9..eed496fb 100644 --- a/lib/src/transaction/msg/ibc/core/MsgCreateClient.spec.ts +++ b/lib/src/transaction/msg/ibc/core/MsgCreateClient.spec.ts @@ -8,7 +8,6 @@ import { Secp256k1KeyPair } from '../../../../keypair/secp256k1'; import { Bytes } from '../../../../utils/bytes/bytes'; import { CroSDK, CroNetwork } from '../../../../core/cro'; import { COSMOS_MSG_TYPEURL } from '../../../common/constants/typeurl'; -import { google } from '../../../../cosmos/v1beta1/codec'; const cro = CroSDK({ network: { @@ -71,14 +70,8 @@ describe('Testing MsgCreateClient', function () { const MsgCreateClient = new cro.ibc.MsgCreateClient({ signer: 'tcro15sfupd26sp6qf37ll5q6xuf330k7df9tnvrqht', - clientState: google.protobuf.Any.create({ - type_url: '/some.valid.type.url', - value: new Uint8Array([1, 2, 35, 5]), - }), - consensusState: google.protobuf.Any.create({ - type_url: '/some.valid.type.url', - value: new Uint8Array([1, 2, 35, 5]), - }), + clientState: undefined, + consensusState: undefined, }); const anySigner = { @@ -95,7 +88,7 @@ describe('Testing MsgCreateClient', function () { const signedTxHex = signedTx.encode().toHexString(); expect(signedTxHex).to.be.eql( - '0a5a0a580a232f6962632e636f72652e636c69656e742e76312e4d7367437265617465436c69656e7412310a0012001a2b7463726f313573667570643236737036716633376c6c3571367875663333306b37646639746e767271687412580a500a460a1f2f636f736d6f732e63727970746f2e736563703235366b312e5075624b657912230a2103fd0d560b6c4aa1ca16721d039a192867c3457e19dad553edb98e7ba88b159c2712040a0208011802120410c09a0c1a40b2b3a0e852a19b4656ce172adbaa95f69d7ab85a9283b9f0f1692b6a1ed094ec63210407a3912a44bec37f3c7ed467a2b77bc90b364db30a913103ca23ba7197', + '0a560a540a232f6962632e636f72652e636c69656e742e76312e4d7367437265617465436c69656e74122d1a2b7463726f313573667570643236737036716633376c6c3571367875663333306b37646639746e767271687412580a500a460a1f2f636f736d6f732e63727970746f2e736563703235366b312e5075624b657912230a2103fd0d560b6c4aa1ca16721d039a192867c3457e19dad553edb98e7ba88b159c2712040a0208011802120410c09a0c1a4015d479781ae26136f291374111f39c137d363c6fd466d3694d17db9cac18e9852dd87f9ffb1c56a80e96c11051d51f1eb3d06b0929f715c6e0c99b78fd89f7eb', ); }); diff --git a/lib/src/transaction/msg/ibc/core/MsgCreateClient.ts b/lib/src/transaction/msg/ibc/core/MsgCreateClient.ts index 06cf7945..1e3fef8d 100644 --- a/lib/src/transaction/msg/ibc/core/MsgCreateClient.ts +++ b/lib/src/transaction/msg/ibc/core/MsgCreateClient.ts @@ -1,3 +1,4 @@ +/* eslint-disable camelcase */ import ow from 'ow'; import { google } from '../../../../cosmos/v1beta1/codec/generated/codecimpl'; import { InitConfigurations } from '../../../../core/cro'; @@ -61,20 +62,24 @@ export const msgCreateClientIBC = function (config: InitConfigurations) { * @returns {MsgCreateClient} */ public static fromCosmosMsgJSON(msgJsonStr: string, _network: Network): MsgCreateClient { - const parsedMsg = JSON.parse(msgJsonStr) as IBCMsgCreateClientRaw; + const parsedMsg = JSON.parse(msgJsonStr) as MsgCreateClientJsonRaw; if (parsedMsg['@type'] !== COSMOS_MSG_TYPEURL.ibc.MsgCreateClient) { throw new Error(`Expected ${COSMOS_MSG_TYPEURL.ibc.MsgCreateClient} but got ${parsedMsg['@type']}`); } + // TODO: The `client_state` value needs to be handled, currently keeping it as `null` + if (typeof parsedMsg.client_state === 'object' && Object.keys(parsedMsg.client_state).length > 0) { + throw new Error('IBC MsgUpdateClient does not support `client_state` decoding.'); + } + + // TODO: The `consensus_state` value needs to be handled, currently keeping it as `null` + if (typeof parsedMsg.consensus_state === 'object' && Object.keys(parsedMsg.consensus_state).length > 0) { + throw new Error('IBC MsgUpdateClient does not support `consensus_state` decoding.'); + } + return new MsgCreateClient({ - clientState: google.protobuf.Any.create({ - type_url: parsedMsg.clientState?.['@type'], - value: parsedMsg.clientState?.value, - }), - consensusState: google.protobuf.Any.create({ - type_url: parsedMsg.consensusState?.['@type'], - value: parsedMsg.consensusState?.value, - }), + clientState: null, + consensusState: null, signer: parsedMsg.signer, }); } @@ -100,9 +105,69 @@ export type MsgCreateClientOptions = { signer: string; }; -interface IBCMsgCreateClientRaw { +export interface MsgCreateClientJsonRaw { '@type': string; + client_state?: ClientState; + consensus_state?: ConsensusState; signer: string; - clientState?: { '@type': string; value: any }; - consensusState?: { '@type': string; value: any }; +} + +export interface ClientState { + '@type': string; + chain_id: string; + trust_level: TrustLevel; + trusting_period: string; + unbonding_period: string; + max_clock_drift: string; + frozen_height: Height; + latest_height: Height; + proof_specs: ProofSpec[]; + upgrade_path: string[]; + allow_update_after_expiry: boolean; + allow_update_after_misbehaviour: boolean; +} + +export interface Height { + revision_number: string; + revision_height: string; +} + +export interface ProofSpec { + leaf_spec: LeafSpec; + inner_spec: InnerSpec; + max_depth: number; + min_depth: number; +} + +export interface InnerSpec { + child_order: number[]; + child_size: number; + min_prefix_length: number; + max_prefix_length: number; + empty_child: null; + hash: string; +} + +export interface LeafSpec { + hash: string; + prehash_key: string; + prehash_value: string; + length: string; + prefix: string; +} + +export interface TrustLevel { + numerator: string; + denominator: string; +} + +export interface ConsensusState { + '@type': string; + timestamp: Date; + root: Root; + next_validators_hash: string; +} + +export interface Root { + hash: string; } diff --git a/lib/src/transaction/msg/ibc/core/MsgUpdateClient.ts b/lib/src/transaction/msg/ibc/core/MsgUpdateClient.ts index fa2765c2..75b5689e 100644 --- a/lib/src/transaction/msg/ibc/core/MsgUpdateClient.ts +++ b/lib/src/transaction/msg/ibc/core/MsgUpdateClient.ts @@ -103,7 +103,7 @@ export type MsgUpdateClientOptions = { export interface MsgUpdateClientJsonRaw { '@type': string; client_id: string; - header: any | MsgUpdateClientJsonRawHeader; + header?: any | MsgUpdateClientJsonRawHeader; signer: string; }