11import assert from "node:assert" ;
22import * as utxolib from "@bitgo/utxo-lib" ;
3- import { fixedScriptWallet , BIP32 } from "../../js/index.js" ;
4- import { BitGoPsbt , RootWalletKeys } from "../../js/fixedScriptWallet/index.js" ;
3+ import { fixedScriptWallet , BIP32 , ECPair } from "../../js/index.js" ;
4+ import { BitGoPsbt , RootWalletKeys , ParsedTransaction } from "../../js/fixedScriptWallet/index.js" ;
55import {
66 loadPsbtFixture ,
77 loadWalletKeysFromFixture ,
88 getPsbtBuffer ,
99 type Fixture ,
10+ loadReplayProtectionKeyFromFixture ,
1011} from "./fixtureUtil.js" ;
1112
1213type SignatureStage = "unsigned" | "halfsigned" | "fullsigned" ;
@@ -61,7 +62,9 @@ function getExpectedSignatures(
6162 */
6263function verifyInputSignatures (
6364 bitgoPsbt : BitGoPsbt ,
65+ parsed : ParsedTransaction ,
6466 rootWalletKeys : RootWalletKeys ,
67+ replayProtectionKey : ECPair ,
6568 inputIndex : number ,
6669 expectedSignatures : ExpectedSignatures ,
6770) : void {
@@ -82,6 +85,20 @@ function verifyInputSignatures(
8285 return ;
8386 }
8487
88+ if ( parsed . inputs [ inputIndex ] . scriptType === "p2shP2pk" ) {
89+ const hasReplaySig = bitgoPsbt . verifySignature ( inputIndex , replayProtectionKey ) ;
90+ assert . ok (
91+ "hasReplayProtectionSignature" in expectedSignatures ,
92+ "Expected hasReplayProtectionSignature to be present" ,
93+ ) ;
94+ assert . strictEqual (
95+ hasReplaySig ,
96+ expectedSignatures . hasReplayProtectionSignature ,
97+ `Input ${ inputIndex } replay protection signature mismatch` ,
98+ ) ;
99+ return ;
100+ }
101+
85102 // Handle standard multisig inputs
86103 const hasUserSig = bitgoPsbt . verifySignature ( inputIndex , rootWalletKeys . userKey ( ) ) ;
87104 const hasBackupSig = bitgoPsbt . verifySignature ( inputIndex , rootWalletKeys . backupKey ( ) ) ;
@@ -121,18 +138,25 @@ describe("verifySignature", function () {
121138
122139 describe ( `network: ${ networkName } ` , function ( ) {
123140 let rootWalletKeys : RootWalletKeys ;
141+ let replayProtectionKey : ECPair ;
124142 let unsignedFixture : Fixture ;
125143 let halfsignedFixture : Fixture ;
126144 let fullsignedFixture : Fixture ;
127145 let unsignedBitgoPsbt : BitGoPsbt ;
128146 let halfsignedBitgoPsbt : BitGoPsbt ;
129147 let fullsignedBitgoPsbt : BitGoPsbt ;
148+ let replayProtectionScript : Uint8Array ;
130149
131150 before ( function ( ) {
132- rootWalletKeys = loadWalletKeysFromFixture ( networkName ) ;
133151 unsignedFixture = loadPsbtFixture ( networkName , "unsigned" ) ;
134152 halfsignedFixture = loadPsbtFixture ( networkName , "halfsigned" ) ;
135153 fullsignedFixture = loadPsbtFixture ( networkName , "fullsigned" ) ;
154+ rootWalletKeys = loadWalletKeysFromFixture ( fullsignedFixture ) ;
155+ replayProtectionKey = loadReplayProtectionKeyFromFixture ( fullsignedFixture ) ;
156+ replayProtectionScript = Buffer . from (
157+ "a91420b37094d82a513451ff0ccd9db23aba05bc5ef387" ,
158+ "hex" ,
159+ ) ;
136160 unsignedBitgoPsbt = fixedScriptWallet . BitGoPsbt . fromBytes (
137161 getPsbtBuffer ( unsignedFixture ) ,
138162 networkName ,
@@ -149,11 +173,16 @@ describe("verifySignature", function () {
149173
150174 describe ( "unsigned PSBT" , function ( ) {
151175 it ( "should return false for unsigned inputs" , function ( ) {
176+ const parsed = unsignedBitgoPsbt . parseTransactionWithWalletKeys ( rootWalletKeys , {
177+ outputScripts : [ replayProtectionScript ] ,
178+ } ) ;
152179 // Verify all xpubs return false for all inputs
153180 unsignedFixture . psbtInputs . forEach ( ( input , index ) => {
154181 verifyInputSignatures (
155182 unsignedBitgoPsbt ,
183+ parsed ,
156184 rootWalletKeys ,
185+ replayProtectionKey ,
157186 index ,
158187 getExpectedSignatures ( input . type , "unsigned" ) ,
159188 ) ;
@@ -163,10 +192,15 @@ describe("verifySignature", function () {
163192
164193 describe ( "half-signed PSBT" , function ( ) {
165194 it ( "should return true for signed xpubs and false for unsigned" , function ( ) {
195+ const parsed = halfsignedBitgoPsbt . parseTransactionWithWalletKeys ( rootWalletKeys , {
196+ outputScripts : [ replayProtectionScript ] ,
197+ } ) ;
166198 halfsignedFixture . psbtInputs . forEach ( ( input , index ) => {
167199 verifyInputSignatures (
168200 halfsignedBitgoPsbt ,
201+ parsed ,
169202 rootWalletKeys ,
203+ replayProtectionKey ,
170204 index ,
171205 getExpectedSignatures ( input . type , "halfsigned" ) ,
172206 ) ;
@@ -177,10 +211,15 @@ describe("verifySignature", function () {
177211 describe ( "fully signed PSBT" , function ( ) {
178212 it ( "should have 2 signatures (2-of-3 multisig)" , function ( ) {
179213 // In fullsigned fixtures, verify 2 signatures exist per multisig input
214+ const parsed = fullsignedBitgoPsbt . parseTransactionWithWalletKeys ( rootWalletKeys , {
215+ outputScripts : [ replayProtectionScript ] ,
216+ } ) ;
180217 fullsignedFixture . psbtInputs . forEach ( ( input , index ) => {
181218 verifyInputSignatures (
182219 fullsignedBitgoPsbt ,
220+ parsed ,
183221 rootWalletKeys ,
222+ replayProtectionKey ,
184223 index ,
185224 getExpectedSignatures ( input . type , "fullsigned" ) ,
186225 ) ;
0 commit comments