fix(express): use wallet multisigType instead of coin.supportsTss() for TRX consolidation routing#8811
Merged
Merged
Conversation
bhavidhingra
previously approved these changes
May 20, 2026
bhavidhingra
previously approved these changes
May 20, 2026
Marzooqa
previously approved these changes
May 20, 2026
…or TRX consolidation routing On-chain TRX wallets with an external signer configured were failing consolidation with "TxRequestId required to sign TSS transactions with External Signer." because handleV2ConsolidateAccount used coin.supportsTss() to decide signing params. For TRX, supportsTss() is always true at the coin level regardless of wallet type, causing TSS MPC generators to be injected for on-chain wallets that have no txRequestId in their build response. Align with handleV2SendMany (fixed in BG-65857) by switching to wallet._wallet.multisigType === 'tss', which reflects the actual wallet configuration rather than coin capability. TICKET: CHALO-473
bhavidhingra
approved these changes
May 20, 2026
Marzooqa
approved these changes
May 20, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
On-chain TRX wallets with an external signer configured were failing consolidation with "TxRequestId required to sign TSS transactions with External Signer." because handleV2ConsolidateAccount used
coin.supportsTss()to decide signing params. For TRX,supportsTss()is always true at the coin level regardless of wallet type, causing TSS MPC generators to be injected for on-chain wallets that have no txRequestId in their build response. Align with handleV2SendMany (fixed in BG-65857) by switching towallet._wallet.multisigType === 'tss', which reflects the actual wallet configuration rather than coin capability.TICKET: CHALO-473
Problem
Clients using BitGo Express with an external signer (
externalSignerUrl) are unable to consolidate on-chain TRX wallets. Every consolidation attempt returns:{"success":[],"failure":[{"message":"TxRequestId required to sign TSS transactions with External Signer.","name":"Error"}],"message":"All transactions failed"}Root Cause
In handleV2ConsolidateAccount, the choice between TSS and on-chain signing params is gated on coin.supportsTss() — a coin-level capability flag:
For TRX,
supportsTss()unconditionally returns true because TRX supports both on-chain multisig and TSS wallets at the coin level. This causes every TRXconsolidation request — including plain on-chain wallets — to go through createTSSSendParams, which injects ECDSA MPC share generator functions into the signing
params.
When the microservices build endpoint is called for an on-chain TRX wallet, it correctly returns { txHex, consolidateId } with no txRequestId (since it's not a
TSS wallet). Later, signTransaction detects the injected ECDSA generators and routes to
signTransactionTssExternalSignerECDSA, which immediately requires atxRequestId — throws, and the consolidation fails.
The analogous handleV2SendMany handler was already fixed (BG-65857) to use
wallet._wallet.multisigType === 'tss'— a wallet-instance level check that reflectsthe actual wallet configuration.
handleV2ConsolidateAccountwas never updated to match.Why This Did Not Surface Before
The bug has two hard prerequisites that must both be true simultaneously:
createTSSSendParamsandcreateSendParamsreturn plain req.body unchanged (the generatorfunctions are only injected when an external signer URL is present), so the wrong routing is completely masked and signing falls through to passphrase-based
signing successfully
Most TRX deployments historically used passphrase-based signing. The external signer pattern is an enterprise/custody setup where keys are never decrypted
inside Express. As more clients have migrated to external signer configurations while still operating on-chain TRX wallets — rather than migrating those wallets
to TSS — this code path started getting exercised in production and the latent bug became visible.
Additionally, TRX is unique among all consolidation-supporting coins in having
supportsTss() === trueat the coin level while defaulting new wallets tomultisigType: "onchain". Every other TSS-capable consolidation coin (SOL, NEAR, DOT, SUI, ETH, BSC, etc.) defaults new wallets to TSS, so their entire live
wallet population is TSS and
coin.supportsTss()happened to be a valid proxy for them. TRX is the only coin where the two diverge.Fix
Switch from the coin-level flag to the wallet-instance check, consistent with handleV2SendMany:
File changed:
modules/express/src/clientRoutes.tsThis ensures:
createSendParams→ customSigningFunction → external signer receives POST /api/v2/ttrx/sign with txHex ✅createTSSSendParams→ ECDSA MPC generators → txRequestId present in build response ✅Unit tests added:
createSendParamseven thoughcoin.supportsTss()is truecreateTSSSendParamsReferences