diff --git a/src/families/cosmos/js-buildTransaction.ts b/src/families/cosmos/js-buildTransaction.ts index 4b86597563..66b932f1ad 100644 --- a/src/families/cosmos/js-buildTransaction.ts +++ b/src/families/cosmos/js-buildTransaction.ts @@ -1,7 +1,22 @@ import { Account } from "../../types"; import { Transaction } from "./types"; +import { + makeAuthInfoBytes, + Registry, + TxBodyEncodeObject, +} from "@cosmjs/proto-signing"; +import { + MsgDelegate, + MsgUndelegate, + MsgBeginRedelegate, +} from "cosmjs-types/cosmos/staking/v1beta1/tx"; +import { MsgWithdrawDelegatorReward } from "cosmjs-types/cosmos/distribution/v1beta1/tx"; +import { SignMode } from "cosmjs-types/cosmos/tx/signing/v1beta1/signing"; +import { TxRaw } from "cosmjs-types/cosmos/tx/v1beta1/tx"; +import { getAccount } from "./api/Cosmos"; +import BigNumber from "bignumber.js"; -const buildTransaction = async ( +export const buildTransaction = async ( account: Account, transaction: Transaction ): Promise => { @@ -163,4 +178,56 @@ const buildTransaction = async ( return msg; }; +export const postBuildTransaction = async ( + account: Account, + transaction: Transaction, + pubkey: any, + unsignedPayload: any, + signature: Uint8Array +): Promise => { + const txBodyFields: TxBodyEncodeObject = { + typeUrl: "/cosmos.tx.v1beta1.TxBody", + value: { + messages: unsignedPayload, + memo: transaction.memo || "", + }, + }; + + const registry = new Registry([ + ["/cosmos.staking.v1beta1.MsgDelegate", MsgDelegate], + ["/cosmos.staking.v1beta1.MsgUndelegate", MsgUndelegate], + ["/cosmos.staking.v1beta1.MsgBeginRedelegate", MsgBeginRedelegate], + [ + "/cosmos.distribution.v1beta1.MsgWithdrawDelegatorReward", + MsgWithdrawDelegatorReward, + ], + ]); + + const { sequence } = await getAccount(account.freshAddress); + + const txBodyBytes = registry.encode(txBodyFields); + + const authInfoBytes = makeAuthInfoBytes( + [{ pubkey, sequence }], + [ + { + amount: transaction.fees?.toString() || new BigNumber(2500).toString(), + denom: account.currency.units[1].code, + }, + ], + transaction.gas?.toNumber() || new BigNumber(250000).toNumber(), + SignMode.SIGN_MODE_LEGACY_AMINO_JSON + ); + + const txRaw = TxRaw.fromPartial({ + bodyBytes: txBodyBytes, + authInfoBytes, + signatures: [signature], + }); + + const tx_bytes = Array.from(Uint8Array.from(TxRaw.encode(txRaw).finish())); + + return tx_bytes; +}; + export default buildTransaction; diff --git a/src/families/cosmos/js-prepareTransaction.ts b/src/families/cosmos/js-prepareTransaction.ts index 8f75721b0a..60893c56bc 100644 --- a/src/families/cosmos/js-prepareTransaction.ts +++ b/src/families/cosmos/js-prepareTransaction.ts @@ -1,28 +1,16 @@ import { Account } from "../../types"; import { Transaction } from "./types"; import BigNumber from "bignumber.js"; -import { getAccount, simulate } from "./api/Cosmos"; -import { - encodePubkey, - makeAuthInfoBytes, - Registry, - TxBodyEncodeObject, -} from "@cosmjs/proto-signing"; -import { SignMode } from "cosmjs-types/cosmos/tx/signing/v1beta1/signing"; -import { TxRaw } from "cosmjs-types/cosmos/tx/v1beta1/tx"; -import { - MsgDelegate, - MsgUndelegate, - MsgBeginRedelegate, -} from "cosmjs-types/cosmos/staking/v1beta1/tx"; -import { MsgWithdrawDelegatorReward } from "cosmjs-types/cosmos/distribution/v1beta1/tx"; +import { simulate } from "./api/Cosmos"; +import { encodePubkey } from "@cosmjs/proto-signing"; import { getEnv } from "../../env"; -import buildTransaction from "./js-buildTransaction"; +import { buildTransaction, postBuildTransaction } from "./js-buildTransaction"; import { getMaxEstimatedBalance } from "./logic"; const prepareTransaction = async ( account: Account, - transaction: Transaction + transaction: Transaction, + calculateFees?: boolean ): Promise => { let memo = transaction.memo; let fees = transaction.fees; @@ -32,12 +20,19 @@ const prepareTransaction = async ( let gasQty = new BigNumber(250000); const gasPrice = new BigNumber(getEnv("COSMOS_GAS_PRICE")); - if (transaction.useAllAmount) { + if (transaction.useAllAmount && !calculateFees) { + const tempTransaction = await prepareTransaction( + account, + { + ...transaction, + amount: account.spendableBalance.minus(new BigNumber(2500)), + }, + true + ); + amount = getMaxEstimatedBalance( account, - account.balance - .dividedBy(new BigNumber(getEnv("COSMOS_GAS_AMPLIFIER"))) - .integerValue() + tempTransaction.fees || new BigNumber(0) ); } @@ -52,54 +47,19 @@ const prepareTransaction = async ( // be sure payload is complete if (unsignedPayload) { - const txBodyFields: TxBodyEncodeObject = { - typeUrl: "/cosmos.tx.v1beta1.TxBody", - value: { - messages: unsignedPayload, - memo: transaction.memo || memo || "", - }, - }; - - const registry = new Registry([ - ["/cosmos.staking.v1beta1.MsgDelegate", MsgDelegate], - ["/cosmos.staking.v1beta1.MsgUndelegate", MsgUndelegate], - ["/cosmos.staking.v1beta1.MsgBeginRedelegate", MsgBeginRedelegate], - [ - "/cosmos.distribution.v1beta1.MsgWithdrawDelegatorReward", - MsgWithdrawDelegatorReward, - ], - ]); - - const { sequence } = await getAccount(account.freshAddress); - const pubkey = encodePubkey({ type: "tendermint/PubKeySecp256k1", value: Buffer.from(account.seedIdentifier, "hex").toString("base64"), }); - const txBodyBytes = registry.encode(txBodyFields); - - const authInfoBytes = makeAuthInfoBytes( - [{ pubkey, sequence }], - [ - { - amount: - transaction.fees?.toString() || new BigNumber(2500).toString(), - denom: account.currency.units[1].code, - }, - ], - transaction.gas?.toNumber() || new BigNumber(250000).toNumber(), - SignMode.SIGN_MODE_LEGACY_AMINO_JSON + const tx_bytes = await postBuildTransaction( + account, + { ...transaction, memo, fees, gas, amount }, + pubkey, + unsignedPayload, + new Uint8Array(Buffer.from(account.seedIdentifier, "hex")) ); - const txRaw = TxRaw.fromPartial({ - bodyBytes: txBodyBytes, - authInfoBytes, - signatures: [new Uint8Array(Buffer.from(account.seedIdentifier, "hex"))], - }); - - const tx_bytes = Array.from(Uint8Array.from(TxRaw.encode(txRaw).finish())); - const gasUsed = await simulate(tx_bytes); if (gasUsed.gt(0)) { diff --git a/src/families/cosmos/js-signOperation.ts b/src/families/cosmos/js-signOperation.ts index 1e138af0ee..ffd71f8804 100644 --- a/src/families/cosmos/js-signOperation.ts +++ b/src/families/cosmos/js-signOperation.ts @@ -8,25 +8,12 @@ import type { Transaction } from "./types"; import { getAccount, getChainId } from "./api/Cosmos"; import { Observable } from "rxjs"; import { withDevice } from "../../hw/deviceAccess"; -import { - encodePubkey, - makeAuthInfoBytes, - Registry, - TxBodyEncodeObject, -} from "@cosmjs/proto-signing"; -import { SignMode } from "cosmjs-types/cosmos/tx/signing/v1beta1/signing"; -import { TxRaw } from "cosmjs-types/cosmos/tx/v1beta1/tx"; +import { encodePubkey } from "@cosmjs/proto-signing"; import { encodeOperationId } from "../../operation"; import { LedgerSigner } from "@cosmjs/ledger-amino"; import { AminoTypes } from "@cosmjs/stargate"; import { stringToPath } from "@cosmjs/crypto"; -import buildTransaction from "./js-buildTransaction"; -import { - MsgDelegate, - MsgUndelegate, - MsgBeginRedelegate, -} from "cosmjs-types/cosmos/staking/v1beta1/tx"; -import { MsgWithdrawDelegatorReward } from "cosmjs-types/cosmos/distribution/v1beta1/tx"; +import { buildTransaction, postBuildTransaction } from "./js-buildTransaction"; import BigNumber from "bignumber.js"; const aminoTypes = new AminoTypes({ prefix: "cosmos" }); @@ -51,16 +38,6 @@ const signOperation = ({ const chainId = await getChainId(); - const registry = new Registry([ - ["/cosmos.staking.v1beta1.MsgDelegate", MsgDelegate], - ["/cosmos.staking.v1beta1.MsgUndelegate", MsgUndelegate], - ["/cosmos.staking.v1beta1.MsgBeginRedelegate", MsgBeginRedelegate], - [ - "/cosmos.distribution.v1beta1.MsgWithdrawDelegatorReward", - MsgWithdrawDelegatorReward, - ], - ]); - const hdPaths: any = stringToPath("m/" + account.freshAddressPath); const ledgerSigner = new LedgerSigner(transport, { @@ -109,40 +86,15 @@ const signOperation = ({ memo: transaction.memo || "", }); - const txBodyFields: TxBodyEncodeObject = { - typeUrl: "/cosmos.tx.v1beta1.TxBody", - value: { - messages: msgs.map((msg) => aminoTypes.fromAmino(msg)), - memo: transaction.memo || "", - }, - }; - - const txBodyBytes = registry.encode(txBodyFields); - - const authInfoBytes = makeAuthInfoBytes( - [{ pubkey, sequence }], - [ - { - amount: - transaction.fees?.toString() || new BigNumber(2500).toString(), - denom: account.currency.units[1].code, - }, - ], - transaction.gas?.toNumber() || new BigNumber(250000).toNumber(), - SignMode.SIGN_MODE_LEGACY_AMINO_JSON + const tx_bytes = await postBuildTransaction( + account, + transaction, + pubkey, + unsignedPayload, + new Uint8Array(Buffer.from(signed.signature.signature, "base64")) ); - const txRaw = TxRaw.fromPartial({ - bodyBytes: txBodyBytes, - authInfoBytes, - signatures: [ - new Uint8Array(Buffer.from(signed.signature.signature, "base64")), - ], - }); - - const signature = Buffer.from(TxRaw.encode(txRaw).finish()).toString( - "hex" - ); + const signature = Buffer.from(tx_bytes).toString("hex"); if (cancelled) { return;