@@ -168,7 +168,7 @@ public void SenderPersistence()
168168 var uri = receiver . PjUri ( ) ;
169169
170170 var senderPersister = new InMemorySenderPersister ( ) ;
171- var psbt = "cHNidP8BAHMCAAAAAY8nutGgJdyYGXWiBEb45Hoe9lWGbkxh/6bNiOJdCDuDAAAAAAD+////AtyVuAUAAAAAF6kUHehJ8GnSdBUOOv6ujXLrWmsJRDCHgIQeAAAAAAAXqRR3QJbbz0hnQ8IvQ0fptGn+votneofTAAAAAAEBIKgb1wUAAAAAF6kU3k4ekGHKWRNbA1rV5tR5kEVDVNCHAQcXFgAUx4pFclNVgo1WWAdN1SYNX8tphTABCGsCRzBEAiB8Q+A6dep+Rz92vhy26lT0AjZn4PRLi8Bf9qoB/CMk0wIgP/Rj2PWZ3gEjUkTlhDRNAQ0gXwTO7t9n+V14pZ6oljUBIQMVmsAaoNWHVMS02LfTSe0e388LNitPa1UQZyOihY+FFgABABYAFEb2Giu6c4KO5YW0pfw3lGp9jMUUAAA=" ;
171+ var psbt = PayjoinMethods . OriginalPsbt ( ) ;
172172
173173 var withReplyKey = new SenderBuilder ( psbt , uri )
174174 . BuildRecommended ( 1000 )
@@ -210,7 +210,7 @@ public async Task SenderPersistenceAsync()
210210 var uri = receiver . PjUri ( ) ;
211211
212212 var senderPersister = new InMemorySenderPersisterAsync ( ) ;
213- var psbt = "cHNidP8BAHMCAAAAAY8nutGgJdyYGXWiBEb45Hoe9lWGbkxh/6bNiOJdCDuDAAAAAAD+////AtyVuAUAAAAAF6kUHehJ8GnSdBUOOv6ujXLrWmsJRDCHgIQeAAAAAAAXqRR3QJbbz0hnQ8IvQ0fptGn+votneofTAAAAAAEBIKgb1wUAAAAAF6kU3k4ekGHKWRNbA1rV5tR5kEVDVNCHAQcXFgAUx4pFclNVgo1WWAdN1SYNX8tphTABCGsCRzBEAiB8Q+A6dep+Rz92vhy26lT0AjZn4PRLi8Bf9qoB/CMk0wIgP/Rj2PWZ3gEjUkTlhDRNAQ0gXwTO7t9n+V14pZ6oljUBIQMVmsAaoNWHVMS02LfTSe0e388LNitPa1UQZyOihY+FFgABABYAFEb2Giu6c4KO5YW0pfw3lGp9jMUUAAA=" ;
213+ var psbt = PayjoinMethods . OriginalPsbt ( ) ;
214214
215215 var withReplyKey = await new SenderBuilder ( psbt , uri )
216216 . BuildRecommended ( 1000 )
@@ -237,6 +237,16 @@ public class ValidationTests
237237 0x00 , 0x01 , 0x00 , 0x03 ,
238238 } ;
239239
240+ private static PjUri CreateV2PjUri ( )
241+ {
242+ var ohttpKeys = OhttpKeys . Decode ( OhttpKeysData ) ;
243+ var persister = new InMemoryReceiverPersister ( ) ;
244+ using var builder = new ReceiverBuilder ( "2MuyMrZHkbHbfjudmKUy45dU4P17pjG2szK" , "https://example.com" , ohttpKeys ) ;
245+ using var transition = builder . Build ( ) ;
246+ using var receiver = transition . Save ( persister ) ;
247+ return receiver . PjUri ( ) ;
248+ }
249+
240250 [ Fact ]
241251 public void ReceiverBuilderRejectsBadAddress ( )
242252 {
@@ -263,4 +273,93 @@ public void InputPairRejectsInvalidOutpoint()
263273 new InputPair ( txin , psbtIn , null ) ;
264274 } ) ;
265275 }
276+
277+ [ Fact ]
278+ public void SenderBuilderRejectsBadPsbt ( )
279+ {
280+ using var parsed = Uri . Parse ( "bitcoin:tb1q6d3a2w975yny0asuvd9a67ner4nks58ff0q8g4?pj=https://example.com/pj" ) ;
281+ using var uri = parsed . CheckPjSupported ( ) ;
282+
283+ var ex = Assert . Throws < SenderInputException . Psbt > ( ( ) =>
284+ {
285+ new SenderBuilder ( "not-a-psbt" , uri ) ;
286+ } ) ;
287+
288+ Assert . IsType < PsbtParseException . InvalidPsbt > ( ex . v1 ) ;
289+ }
290+
291+ [ Fact ]
292+ public void ReceiverBuilderRejectsAmountOverflow ( )
293+ {
294+ var ohttpKeys = OhttpKeys . Decode ( OhttpKeysData ) ;
295+ using var builder = new ReceiverBuilder (
296+ "tb1q6d3a2w975yny0asuvd9a67ner4nks58ff0q8g4" ,
297+ "https://example.com" ,
298+ ohttpKeys ) ;
299+
300+ Assert . Throws < FfiValidationException . AmountOutOfRange > ( ( ) =>
301+ {
302+ builder . WithAmount ( 21_000_000UL * 100_000_000UL + 1 ) ;
303+ } ) ;
304+ }
305+
306+ [ Fact ]
307+ public void ReceiverBuilderRejectsExpirationOverflow ( )
308+ {
309+ var ohttpKeys = OhttpKeys . Decode ( OhttpKeysData ) ;
310+ using var builder = new ReceiverBuilder (
311+ "tb1q6d3a2w975yny0asuvd9a67ner4nks58ff0q8g4" ,
312+ "https://example.com" ,
313+ ohttpKeys ) ;
314+
315+ Assert . Throws < FfiValidationException . ExpirationOutOfRange > ( ( ) =>
316+ {
317+ builder . WithExpiration ( ( ulong ) uint . MaxValue + 1 ) ;
318+ } ) ;
319+ }
320+
321+ [ Fact ]
322+ public void SenderBuilderWithAdditionalFeeRejectsFeeContributionOverflow ( )
323+ {
324+ using var uri = CreateV2PjUri ( ) ;
325+ var psbt = PayjoinMethods . OriginalPsbt ( ) ;
326+ using var builder = new SenderBuilder ( psbt , uri ) ;
327+
328+ var ex = Assert . Throws < SenderInputException . FfiValidation > ( ( ) =>
329+ {
330+ builder . BuildWithAdditionalFee ( 21_000_000UL * 100_000_000UL + 1 , null , 1000 , false ) ;
331+ } ) ;
332+
333+ Assert . IsType < FfiValidationException . AmountOutOfRange > ( ex . v1 ) ;
334+ }
335+
336+ [ Fact ]
337+ public void SenderBuilderWithAdditionalFeeRejectsFeeRateOverflow ( )
338+ {
339+ using var uri = CreateV2PjUri ( ) ;
340+ var psbt = PayjoinMethods . OriginalPsbt ( ) ;
341+ using var builder = new SenderBuilder ( psbt , uri ) ;
342+
343+ var ex = Assert . Throws < SenderInputException . FfiValidation > ( ( ) =>
344+ {
345+ builder . BuildWithAdditionalFee ( 1 , null , ulong . MaxValue , false ) ;
346+ } ) ;
347+
348+ Assert . IsType < FfiValidationException . FeeRateOutOfRange > ( ex . v1 ) ;
349+ }
350+
351+ [ Fact ]
352+ public void SenderBuilderNonIncentivizingRejectsFeeRateOverflow ( )
353+ {
354+ using var uri = CreateV2PjUri ( ) ;
355+ var psbt = PayjoinMethods . OriginalPsbt ( ) ;
356+ using var builder = new SenderBuilder ( psbt , uri ) ;
357+
358+ var ex = Assert . Throws < SenderInputException . FfiValidation > ( ( ) =>
359+ {
360+ builder . BuildNonIncentivizing ( ulong . MaxValue ) ;
361+ } ) ;
362+
363+ Assert . IsType < FfiValidationException . FeeRateOutOfRange > ( ex . v1 ) ;
364+ }
266365}
0 commit comments