diff --git a/.changeset/tame-schools-float.md b/.changeset/tame-schools-float.md new file mode 100644 index 000000000000..8609ff74b15b --- /dev/null +++ b/.changeset/tame-schools-float.md @@ -0,0 +1,5 @@ +--- +"@ledgerhq/live-common": minor +--- + +Fix big number transactions on cosmos family diff --git a/libs/ledger-live-common/src/families/cosmos/js-buildTransaction.test.ts b/libs/ledger-live-common/src/families/cosmos/js-buildTransaction.test.ts index 427b347ed098..89882f3d7961 100644 --- a/libs/ledger-live-common/src/families/cosmos/js-buildTransaction.test.ts +++ b/libs/ledger-live-common/src/families/cosmos/js-buildTransaction.test.ts @@ -12,6 +12,8 @@ import { MsgWithdrawDelegatorReward } from "cosmjs-types/cosmos/distribution/v1b import { TxBody, TxRaw } from "cosmjs-types/cosmos/tx/v1beta1/tx"; import { Fee } from "@keplr-wallet/proto-types/cosmos/tx/v1beta1/tx"; +const veryBigNumber = new BigNumber(3333300000000000000000); + describe("txToMessages", () => { const transaction: Transaction = {} as Transaction; const account: CosmosAccount = { @@ -34,10 +36,18 @@ describe("txToMessages", () => { expect(aminoMsg.type).toContain("MsgSend"); expect(aminoMsg.value.to_address).toEqual(transaction.recipient); expect(aminoMsg.value.from_address).toEqual(account.freshAddress); - expect(aminoMsg.value.amount[0].amount).toEqual(transaction.amount.toString()); + expect(aminoMsg.value.amount[0].amount).toEqual(transaction.amount.toFixed()); expect(aminoMsg.value.amount[0].denom).toEqual(account.currency.units[1].code); }); + it("should not include exponential part on big numbers", () => { + transaction.recipient = "address"; + transaction.amount = veryBigNumber; + const { aminoMsgs } = txToMessages(account, transaction); + const [aminoMsg] = aminoMsgs; + expect(aminoMsg.value.amount[0].amount.includes("e")).toEqual(false); + }); + it("should return no message if recipient isn't defined", () => { transaction.amount = new BigNumber(10); transaction.recipient = ""; @@ -75,10 +85,19 @@ describe("txToMessages", () => { expect(protoMsg.typeUrl).toContain("MsgSend"); expect(value.toAddress).toEqual(transaction.recipient); expect(value.fromAddress).toEqual(account.freshAddress); - expect(value.amount[0].amount).toEqual(transaction.amount.toString()); + expect(value.amount[0].amount).toEqual(transaction.amount.toFixed()); expect(value.amount[0].denom).toEqual(account.currency.units[1].code); }); + it("should not include exponential part on big numbers", () => { + transaction.recipient = "address"; + transaction.amount = veryBigNumber; + const { protoMsgs } = txToMessages(account, transaction); + const [protoMsg] = protoMsgs; + const value = cosmos.bank.v1beta1.MsgSend.decode(protoMsg.value); + expect(value.amount[0].amount?.includes("e")).toEqual(false); + }); + it("should return no message if recipient isn't defined", () => { transaction.amount = new BigNumber(10); transaction.recipient = ""; @@ -120,10 +139,24 @@ describe("txToMessages", () => { expect(message.type).toContain("MsgDelegate"); expect(message.value.validator_address).toEqual(transaction.validators[0].address); expect(message.value.delegator_address).toEqual(account.freshAddress); - expect(message.value.amount?.amount).toEqual(transaction.amount.toString()); + expect(message.value.amount?.amount).toEqual(transaction.amount.toFixed()); expect(message.value.amount?.denom).toEqual(account.currency.units[1].code); }); + it("should not include exponential part on big numbers", () => { + transaction.recipient = "address"; + transaction.amount = veryBigNumber; + transaction.validators = [ + { + address: "realAddressTrustMe", + amount: veryBigNumber, + } as CosmosDelegationInfo, + ]; + const { aminoMsgs } = txToMessages(account, transaction); + const [message] = aminoMsgs; + expect(message.value.amount?.amount.includes("e")).toEqual(false); + }); + it("should return no message if tx has a 0 amount", () => { transaction.amount = new BigNumber(0); transaction.validators = [{ address: "realAddressTrustMe" } as CosmosDelegationInfo]; @@ -167,10 +200,24 @@ describe("txToMessages", () => { const value = MsgDelegate.decode(message.value); expect(value.validatorAddress).toEqual(transaction.validators[0].address); expect(value.delegatorAddress).toEqual(account.freshAddress); - expect(value.amount?.amount).toEqual(transaction.amount.toString()); + expect(value.amount?.amount).toEqual(transaction.amount.toFixed()); expect(value.amount?.denom).toEqual(account.currency.units[1].code); }); + it("should not include exponential part on big numbers", () => { + transaction.amount = veryBigNumber; + transaction.validators = [ + { + address: "realAddressTrustMe", + amount: veryBigNumber, + } as CosmosDelegationInfo, + ]; + const { protoMsgs } = txToMessages(account, transaction); + const [message] = protoMsgs; + const value = MsgDelegate.decode(message.value); + expect(value.amount?.amount.includes("e")).toEqual(false); + }); + it("should return no message if tx has a 0 amount", () => { transaction.amount = new BigNumber(0); transaction.validators = [{ address: "realAddressTrustMe" } as CosmosDelegationInfo]; @@ -219,10 +266,23 @@ describe("txToMessages", () => { expect(message.type).toContain("MsgUndelegate"); expect(message.value.validator_address).toEqual(transaction.validators[0].address); expect(message.value.delegator_address).toEqual(account.freshAddress); - expect(message.value.amount?.amount).toEqual(transaction.validators[0].amount.toString()); + expect(message.value.amount?.amount).toEqual(transaction.validators[0].amount.toFixed()); expect(message.value.amount?.denom).toEqual(account.currency.units[1].code); }); + it("should not include exponential part on big numbers", () => { + transaction.amount = veryBigNumber; + transaction.validators = [ + { + address: "realAddressTrustMe", + amount: veryBigNumber, + } as CosmosDelegationInfo, + ]; + const { aminoMsgs } = txToMessages(account, transaction); + const [message] = aminoMsgs; + expect(message.value.amount?.amount.includes("e")).toEqual(false); + }); + it("should return no message if validators aren't defined", () => { transaction.validators = []; const { aminoMsgs } = txToMessages(account, transaction); @@ -279,10 +339,24 @@ describe("txToMessages", () => { const value = MsgUndelegate.decode(message.value); expect(value.validatorAddress).toEqual(transaction.validators[0].address); expect(value.delegatorAddress).toEqual(account.freshAddress); - expect(value.amount?.amount).toEqual(transaction.validators[0].amount.toString()); + expect(value.amount?.amount).toEqual(transaction.validators[0].amount.toFixed()); expect(value.amount?.denom).toEqual(account.currency.units[1].code); }); + it("should not include exponential part on big numbers", () => { + transaction.amount = veryBigNumber; + transaction.validators = [ + { + address: "realAddressTrustMe", + amount: veryBigNumber, + } as CosmosDelegationInfo, + ]; + const { protoMsgs } = txToMessages(account, transaction); + const [message] = protoMsgs; + const value = MsgUndelegate.decode(message.value); + expect(value.amount?.amount.includes("e")).toEqual(false); + }); + it("should return no message if validators aren't defined", () => { transaction.validators = []; const { protoMsgs } = txToMessages(account, transaction); @@ -345,10 +419,23 @@ describe("txToMessages", () => { expect(message.value.validator_src_address).toEqual(transaction.sourceValidator); expect(message.value.validator_dst_address).toEqual(transaction.validators[0].address); expect(message.value.delegator_address).toEqual(account.freshAddress); - expect(message.value.amount.amount).toEqual(transaction.validators[0].amount.toString()); + expect(message.value.amount.amount).toEqual(transaction.validators[0].amount.toFixed()); expect(message.value.amount.denom).toEqual(account.currency.units[1].code); }); + it("should not include exponential part on big numbers", () => { + transaction.sourceValidator = "source"; + transaction.validators = [ + { + address: "realAddressTrustMe", + amount: veryBigNumber, + } as CosmosDelegationInfo, + ]; + const { aminoMsgs } = txToMessages(account, transaction); + const [message] = aminoMsgs; + expect(message.value.amount.amount.includes("e")).toEqual(false); + }); + it("should return no message if sourceValidator isn't defined", () => { transaction.sourceValidator = ""; transaction.validators = [ @@ -410,10 +497,25 @@ describe("txToMessages", () => { expect(value.validatorSrcAddress).toEqual(transaction.sourceValidator); expect(value.validatorDstAddress).toEqual(transaction.validators[0].address); expect(value.delegatorAddress).toEqual(account.freshAddress); - expect(value.amount?.amount).toEqual(transaction.validators[0].amount.toString()); + expect(value.amount?.amount).toEqual(transaction.validators[0].amount.toFixed()); expect(value.amount?.denom).toEqual(account.currency.units[1].code); }); + it("should not include exponential part on big numbers", () => { + transaction.sourceValidator = "source"; + transaction.validators = [ + { + address: "realAddressTrustMe", + amount: veryBigNumber, + } as CosmosDelegationInfo, + ]; + const { protoMsgs } = txToMessages(account, transaction); + const [message] = protoMsgs; + expect(message).toBeTruthy(); + const value = MsgBeginRedelegate.decode(message.value); + expect(value.amount?.amount.includes("e")).toEqual(false); + }); + it("should return no message if sourceValidator isn't defined", () => { transaction.sourceValidator = ""; transaction.validators = [ @@ -558,10 +660,22 @@ describe("txToMessages", () => { expect(delegateMessage.value.validator_address).toEqual(transaction.validators[0].address); expect(delegateMessage.value.delegator_address).toEqual(account.freshAddress); expect(delegateMessage.value.amount.amount).toEqual( - transaction.validators[0].amount.toString(), + transaction.validators[0].amount.toFixed(), ); expect(delegateMessage.value.amount.denom).toEqual(account.currency.units[1].code); }); + + it("should not include exponential part on big numbers", () => { + transaction.validators = [ + { + address: "iAmAValidatorAddress", + amount: veryBigNumber, + } as CosmosDelegationInfo, + ]; + const { aminoMsgs } = txToMessages(account, transaction); + const [, delegateMessage] = aminoMsgs; + expect(delegateMessage.value.amount.amount.includes("e")).toEqual(false); + }); }); describe("Proto", () => { @@ -585,10 +699,23 @@ describe("txToMessages", () => { expect(delegateMessageValue.validatorAddress).toEqual(transaction.validators[0].address); expect(delegateMessageValue.delegatorAddress).toEqual(account.freshAddress); expect(delegateMessageValue.amount?.amount).toEqual( - transaction.validators[0].amount.toString(), + transaction.validators[0].amount.toFixed(), ); expect(delegateMessageValue.amount?.denom).toEqual(account.currency.units[1].code); }); + + it("should return a MsgWithdrawDelegatorReward message and a MsgDelegate if transaction is complete", () => { + transaction.validators = [ + { + address: "iAmAValidatorAddress", + amount: veryBigNumber, + } as CosmosDelegationInfo, + ]; + const { protoMsgs } = txToMessages(account, transaction); + const [, delegateMessage] = protoMsgs; + const delegateMessageValue = MsgDelegate.decode(delegateMessage.value); + expect(delegateMessageValue.amount?.amount.includes("e")).toEqual(false); + }); }); }); diff --git a/libs/ledger-live-common/src/families/cosmos/js-buildTransaction.ts b/libs/ledger-live-common/src/families/cosmos/js-buildTransaction.ts index 54258ba1e2a8..ff9e8702ae96 100644 --- a/libs/ledger-live-common/src/families/cosmos/js-buildTransaction.ts +++ b/libs/ledger-live-common/src/families/cosmos/js-buildTransaction.ts @@ -48,7 +48,7 @@ export const txToMessages = ( amount: [ { denom: account.currency.units[1].code, - amount: transaction.amount.toString(), + amount: transaction.amount.toFixed(), }, ], }, @@ -64,7 +64,7 @@ export const txToMessages = ( amount: [ { denom: account.currency.units[1].code, - amount: transaction.amount.toString(), + amount: transaction.amount.toFixed(), }, ], }).finish(), @@ -82,7 +82,7 @@ export const txToMessages = ( validator_address: validator.address, amount: { denom: account.currency.units[1].code, - amount: transaction.amount.toString(), + amount: transaction.amount.toFixed(), }, }, }; @@ -96,7 +96,7 @@ export const txToMessages = ( validatorAddress: validator.address, amount: { denom: account.currency.units[1].code, - amount: transaction.amount.toString(), + amount: transaction.amount.toFixed(), }, }).finish(), }); @@ -121,7 +121,7 @@ export const txToMessages = ( validator_dst_address: validator.address, amount: { denom: account.currency.units[1].code, - amount: validator.amount.toString(), + amount: validator.amount.toFixed(), }, }, }; @@ -136,7 +136,7 @@ export const txToMessages = ( validatorDstAddress: validator.address, amount: { denom: account.currency.units[1].code, - amount: validator.amount.toString(), + amount: validator.amount.toFixed(), }, }).finish(), }); @@ -154,7 +154,7 @@ export const txToMessages = ( validator_address: validator.address, amount: { denom: account.currency.units[1].code, - amount: validator.amount.toString(), + amount: validator.amount.toFixed(), }, }, }; @@ -168,7 +168,7 @@ export const txToMessages = ( validatorAddress: validator.address, amount: { denom: account.currency.units[1].code, - amount: validator.amount.toString(), + amount: validator.amount.toFixed(), }, }).finish(), }); @@ -224,7 +224,7 @@ export const txToMessages = ( validator_address: validator.address, amount: { denom: account.currency.units[1].code, - amount: validator.amount.toString(), + amount: validator.amount.toFixed(), }, }, }; @@ -245,7 +245,7 @@ export const txToMessages = ( validatorAddress: validator.address, amount: { denom: account.currency.units[1].code, - amount: validator.amount.toString(), + amount: validator.amount.toFixed(), }, }).finish(), }); diff --git a/libs/ledger-live-common/src/families/cosmos/js-prepareTransaction.ts b/libs/ledger-live-common/src/families/cosmos/js-prepareTransaction.ts index f58d20da43ea..8ce29ccd9553 100644 --- a/libs/ledger-live-common/src/families/cosmos/js-prepareTransaction.ts +++ b/libs/ledger-live-common/src/families/cosmos/js-prepareTransaction.ts @@ -29,7 +29,7 @@ export const calculateFees: CacheRes< return await getEstimatedFees(account as CosmosAccount, transaction); }, ({ account, transaction }) => - `${account.id}_${account.currency.id}_${transaction.amount.toString()}_${ + `${account.id}_${account.currency.id}_${transaction.amount.toFixed()}_${ transaction.recipient }_${String(transaction.useAllAmount)}_${transaction.mode}_${ transaction.validators diff --git a/libs/ledger-live-common/src/families/cosmos/js-signOperation.ts b/libs/ledger-live-common/src/families/cosmos/js-signOperation.ts index 8593879d37ea..ff4684e3fc30 100644 --- a/libs/ledger-live-common/src/families/cosmos/js-signOperation.ts +++ b/libs/ledger-live-common/src/families/cosmos/js-signOperation.ts @@ -34,10 +34,10 @@ const signOperation: SignOperationFnSignature = ({ account, deviceI amount: [ { denom: account.currency.units[1].code, - amount: transaction.fees.toString(), + amount: transaction.fees.toFixed(), }, ], - gas: transaction.gas.toString(), + gas: transaction.gas.toFixed(), }; // Note: // Cosmos Nano App sign data in Amino way only, not Protobuf.