diff --git a/package.json b/package.json index fbf5954c0..258e512f7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@terra-money/terra.js", - "version": "3.0.4", + "version": "3.0.5", "description": "The JavaScript SDK for Terra", "license": "MIT", "author": "Terraform Labs, PTE.", diff --git a/src/core/ibc-transfer/msgs/MsgTransfer.spec.ts b/src/core/ibc-transfer/msgs/MsgTransfer.spec.ts index 4820e4481..7fae0ed0f 100644 --- a/src/core/ibc-transfer/msgs/MsgTransfer.spec.ts +++ b/src/core/ibc-transfer/msgs/MsgTransfer.spec.ts @@ -1,5 +1,7 @@ import { MsgTransfer } from './MsgTransfer'; import { Coin } from '../../Coin'; +import { Height } from '../../ibc/msgs/client/Height'; +import { Numeric } from '../..'; describe('MsgTransfer', () => { it('deserializes correctly', () => { @@ -14,7 +16,7 @@ describe('MsgTransfer', () => { revision_number: '0', revision_height: '0', }, - timeout_timestamp: '1631618921', + timeout_timestamp: '1642663176848000000', }); expect(send).toMatchObject({ @@ -27,7 +29,66 @@ describe('MsgTransfer', () => { revision_number: 0, revision_height: 0, }, - timeout_timestamp: 1631618921, + timeout_timestamp: Numeric.parse('1642663176848000000'), + }); + }); + + it('deserializes amino without timeout_height', () => { + const send = MsgTransfer.fromData({ + '@type': '/ibc.applications.transfer.v1.MsgTransfer', + source_port: 'sourceport-01', + source_channel: 'sourcehannel-01', + token: { denom: 'uluna', amount: '1024' }, + sender: 'terra1x46rqay4d3cssq8gxxvqz8xt6nwlz4td20k38v', + receiver: 'recvr17lmam6zguazs5q5u6z5mmx76uj63gldnse2pdp', + timeout_height: new Height(0, 0).toData(), + timeout_timestamp: '1642663176848000000', + }); + const aminoSend = send.toAmino(); + + expect(aminoSend).toMatchObject({ + type: 'cosmos-sdk/MsgTransfer', + value: { + source_port: 'sourceport-01', + source_channel: 'sourcehannel-01', + token: new Coin('uluna', '1024').toAmino(), + sender: 'terra1x46rqay4d3cssq8gxxvqz8xt6nwlz4td20k38v', + receiver: 'recvr17lmam6zguazs5q5u6z5mmx76uj63gldnse2pdp', + timeout_height: {}, + timeout_timestamp: '1642663176848000000', + }, + }); + + expect(send.toData()).toMatchObject({}); + }); + + it('deserializes amino without timeout_timestamp', () => { + const send = MsgTransfer.fromData({ + '@type': '/ibc.applications.transfer.v1.MsgTransfer', + source_port: 'sourceport-01', + source_channel: 'sourcehannel-01', + token: { denom: 'uluna', amount: '1024' }, + sender: 'terra1x46rqay4d3cssq8gxxvqz8xt6nwlz4td20k38v', + receiver: 'recvr17lmam6zguazs5q5u6z5mmx76uj63gldnse2pdp', + timeout_height: { + revision_number: '5', + revision_height: '57240001', + }, + timeout_timestamp: '0', + }); + const aminoSend = send.toAmino(); + + expect(aminoSend).toMatchObject({ + type: 'cosmos-sdk/MsgTransfer', + value: { + source_port: 'sourceport-01', + source_channel: 'sourcehannel-01', + token: new Coin('uluna', '1024').toAmino(), + sender: 'terra1x46rqay4d3cssq8gxxvqz8xt6nwlz4td20k38v', + receiver: 'recvr17lmam6zguazs5q5u6z5mmx76uj63gldnse2pdp', + timeout_height: new Height(5, 57240001).toAmino(), + timeout_timestamp: undefined, + }, }); expect(send.toData()).toMatchObject({}); diff --git a/src/core/ibc-transfer/msgs/MsgTransfer.ts b/src/core/ibc-transfer/msgs/MsgTransfer.ts index 11e3e8f6f..a74f783fd 100644 --- a/src/core/ibc-transfer/msgs/MsgTransfer.ts +++ b/src/core/ibc-transfer/msgs/MsgTransfer.ts @@ -5,6 +5,7 @@ import * as Long from 'long'; import { Any } from '@terra-money/terra.proto/google/protobuf/any'; import { MsgTransfer as MsgTransfer_pb } from '@terra-money/terra.proto/ibc/applications/transfer/v1/tx'; import { Height } from '../../ibc/msgs/client/Height'; +import { Numeric } from '../../..'; /** * A basic message for transfer [[Coin]] via IBC. */ @@ -19,7 +20,7 @@ export class MsgTransfer extends JSONSerializable< public sender: AccAddress; public receiver: string; // destination chain can be non-cosmos-based public timeout_height?: Height; // 0 to disable - public timeout_timestamp: number; // 0 to disable + public timeout_timestamp?: Numeric.Output; // 0 to disable /** * @param source_port the port on which the packet will be sent * @param source_channel the channel by which the packet will be sent @@ -36,16 +37,23 @@ export class MsgTransfer extends JSONSerializable< sender: AccAddress, receiver: string, timeout_height: Height | undefined, - timeout_timestamp: number + timeout_timestamp: Numeric.Input | undefined ) { super(); + + if (!timeout_height && !timeout_timestamp) { + throw 'both of timeout_height and timeout_timestamp are undefined'; + } + this.source_port = source_port; this.source_channel = source_channel; this.token = token; this.sender = sender; this.receiver = receiver; this.timeout_height = timeout_height; - this.timeout_timestamp = timeout_timestamp; + this.timeout_timestamp = timeout_timestamp + ? Numeric.parse(timeout_timestamp) + : undefined; } public static fromAmino(data: MsgTransfer.Amino): MsgTransfer { @@ -60,6 +68,11 @@ export class MsgTransfer extends JSONSerializable< timeout_timestamp, }, } = data; + + if (!timeout_height && !timeout_timestamp) { + throw 'both of timeout_height and timeout_timestamp are undefined'; + } + return new MsgTransfer( source_port, source_channel, @@ -67,7 +80,7 @@ export class MsgTransfer extends JSONSerializable< sender, receiver, timeout_height ? Height.fromAmino(timeout_height) : undefined, - Number.parseInt(timeout_timestamp) + timeout_timestamp ? Numeric.parse(timeout_timestamp) : undefined ); } @@ -89,8 +102,8 @@ export class MsgTransfer extends JSONSerializable< token: token ? token.toAmino() : undefined, sender, receiver, - timeout_height: timeout_height ? timeout_height.toAmino() : undefined, - timeout_timestamp: timeout_timestamp.toFixed(), + timeout_height: timeout_height?.toAmino() || {}, + timeout_timestamp: timeout_timestamp?.toFixed() || undefined, }, }; } @@ -105,6 +118,11 @@ export class MsgTransfer extends JSONSerializable< timeout_timestamp, timeout_height, } = data; + + if (!timeout_height && !timeout_timestamp) { + throw 'both of timeout_height and timeout_timestamp are undefined'; + } + return new MsgTransfer( source_port, source_channel, @@ -112,7 +130,7 @@ export class MsgTransfer extends JSONSerializable< sender, receiver, timeout_height ? Height.fromData(timeout_height) : undefined, - Number.parseInt(timeout_timestamp) + timeout_timestamp ? Number.parseInt(timeout_timestamp) : undefined ); } @@ -133,12 +151,18 @@ export class MsgTransfer extends JSONSerializable< token: token ? token.toData() : undefined, sender, receiver, - timeout_height: timeout_height ? timeout_height.toData() : undefined, - timeout_timestamp: timeout_timestamp.toFixed(), + timeout_height: timeout_height + ? timeout_height.toData() + : new Height(0, 0).toData(), + timeout_timestamp: timeout_timestamp?.toFixed() || '0', }; } public static fromProto(proto: MsgTransfer.Proto): MsgTransfer { + if (!proto.timeoutHeight && proto.timeoutTimestamp.toNumber() == 0) { + throw 'both of timeout_height and timeout_timestamp are empty'; + } + return new MsgTransfer( proto.sourcePort, proto.sourceChannel, @@ -167,7 +191,7 @@ export class MsgTransfer extends JSONSerializable< sender, receiver, timeoutHeight: timeout_height ? timeout_height.toProto() : undefined, - timeoutTimestamp: Long.fromNumber(timeout_timestamp), + timeoutTimestamp: Long.fromString(timeout_timestamp?.toFixed() || '0'), }); } @@ -192,8 +216,8 @@ export namespace MsgTransfer { token?: Coin.Amino; sender: AccAddress; receiver: string; - timeout_height?: Height.Amino; - timeout_timestamp: string; + timeout_height: Height.Amino; + timeout_timestamp?: string; }; } export interface Data { @@ -203,7 +227,7 @@ export namespace MsgTransfer { token?: Coin.Data; sender: AccAddress; receiver: string; - timeout_height?: Height.Data; + timeout_height: Height.Data; timeout_timestamp: string; } export type Proto = MsgTransfer_pb; diff --git a/src/core/ibc/msgs/client/Height.ts b/src/core/ibc/msgs/client/Height.ts index e2258521c..58e109c09 100644 --- a/src/core/ibc/msgs/client/Height.ts +++ b/src/core/ibc/msgs/client/Height.ts @@ -29,14 +29,19 @@ export class Height extends JSONSerializable< public static fromAmino(data: Height.Amino): Height { const { revision_number, revision_height } = data; - return new Height(parseInt(revision_number), parseInt(revision_height)); + return new Height( + parseInt(revision_number || '0'), + parseInt(revision_height || '0') + ); } public toAmino(): Height.Amino { const { revision_number, revision_height } = this; const res: Height.Amino = { - revision_number: revision_number.toFixed(), - revision_height: revision_height.toFixed(), + revision_number: + revision_number > 0 ? revision_number.toFixed() : undefined, + revision_height: + revision_height > 0 ? revision_height.toFixed() : undefined, }; return res; } @@ -76,8 +81,8 @@ export class Height extends JSONSerializable< export namespace Height { export interface Amino { - revision_number: string; - revision_height: string; + revision_number?: string; + revision_height?: string; } export interface Data {