feat(sdk-coin-flrp): enhance txn verification for atomic transactions#8821
Merged
Conversation
ArunBala-Bitgo
approved these changes
May 21, 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.
fix(sdk-core): fix FLRP MPCv2 verifyTransaction and hash bypass for Avalanche atomic transactions
Ticket: CECHO-1140
Problem
FLRP (Flare P-chain) MPCv2 cross-chain atomic transactions fail during TSS signing with:
failed to sign transaction Error: Invalid transaction: Transaction type not supported
Root cause — two bugs in
ecdsaMPCv2.ts signRequestBase:Bug 1 — verifyTransaction receives unparseable signableHex: For Avalanche atomic transactions,
signableHexis a 32-byte SHA-256 digest (SHA-256(txBody)), not the actual PVM transaction bytes.signRequestBasewas passingsignableHexastxHextoverifyTransaction, which tried to parse it as a PVM transaction and failed with "Transaction type not supported".Bug 2 — signRequestBase double-hashes the signing payload:
signRequestBaseapplies keccak256 to thesignableHexbuffer before passing it to the DKLS signer. For Avalanche atomic txs,signableHexisalready SHA-256(txBody) — the final signing hash. Applying keccak256 on top produces
keccak256(SHA-256(txBody)), which doesn't match the HSM/BitGo party that usesSHA-256(txBody)directly. The two DKLSparties disagree on the message hash, producing an invalid combined signature.
Fix
Bug 1: Detect Avalanche atomic transactions via
serializedTxHex.startsWith('0000')(Avalanche codec type ID prefix; EVM RLP starts with0xf8xxso no collision). When detected, passserializedTxHex(full parseable PVM bytes) to
verifyTransactioninstead ofsignableHex. This follows the existing ICP pattern already in the code.Bug 2: When
serializedTxHexstarts with'0000', skip keccak256 and use thesignableHexbuffer directly as the 32-byte DKLS message hash. This matches the existing fix ingetHashStringAndDerivationPath(external signer path) and the WP/HSM BitGo-party behaviour (MPCv2Signer.isPreHashed).Detection mechanism
Avalanche atomic tx: serializedTxHex starts with '0000' (codec type ID)
Standard EVM tx: serializedTxHex starts with 'f8' (RLP encoding)
The WP explicitly strips the
0xprefix before storingserializedTxHex(seeflrp.ts:1369andflr.ts:1145), so the check is against bare hex.Sandbox verification
Both fixes verified against real Coston2 testnet transactions:
c2pMpcToMpcTss.ts2Z5ELShnmmMgvTeupzLQzEKtAgbvZkDvq6KRYqbzVgcyBGVGpbp2cMpcToMpcTss.ts2tDQmQUtDMyVWe8Bo36yHXykV2RMvh8rft3to5QsgoNhATMDXzKey sandbox values used in test assertions:
0000(Avalanche codec prefix)recid:R:S:pubkeywith R/S each 32 bytes, recovery ∈ {0, 1}Changes
modules/sdk-core/src/bitgo/utils/tss/ecdsa/ecdsaMPCv2.tsserializedTxHextoverifyTransactionfor Avalanche atomic txs. Bug 7: skip keccak256 for pre-hashedsignableHex.modules/sdk-core/test/unit/bitgo/utils/tss/ecdsa/ecdsaMPCv2.tssignRequestBasehash bypass tests for both Avalanche (skip keccak)modules/sdk-coin-flrp/test/unit/flrp.tsverifyTransactiontests for all 3 cross-chain types (ExportInP, ImportInP, ImportInC); signablePayload SHA-256 length/codec-prefix assertions;Test results
sdk-coin-flrp: 353 passing
ecdsaMPCv2: 7 passing