@@ -424,6 +424,112 @@ func testRfqAssetSellHtlcIntercept(t *harnessTest) {
424
424
require .NoError (t .t , err )
425
425
}
426
426
427
+ // testRfqNegotiationGroupKey checks that two nodes can negotiate and register
428
+ // quotes based on a specifier that only uses a group key.
429
+ func testRfqNegotiationGroupKey (t * harnessTest ) {
430
+ // Initialize a new test scenario.
431
+ ts := newRfqTestScenario (t )
432
+
433
+ // Mint an asset with Alice's tapd node.
434
+ rpcAssets := MintAssetsConfirmBatch (
435
+ t .t , t .lndHarness .Miner ().Client , ts .AliceTapd ,
436
+ []* mintrpc.MintAssetRequest {issuableAssets [0 ]},
437
+ )
438
+
439
+ mintedAssetGroupKey := rpcAssets [0 ].AssetGroup .TweakedGroupKey
440
+
441
+ ctxb := context .Background ()
442
+ ctxt , cancel := context .WithTimeout (ctxb , defaultWaitTimeout )
443
+ defer cancel ()
444
+
445
+ // Subscribe to Alice's RFQ events stream.
446
+ aliceEventNtfns , err := ts .AliceTapd .SubscribeRfqEventNtfns (
447
+ ctxb , & rfqrpc.SubscribeRfqEventNtfnsRequest {},
448
+ )
449
+ require .NoError (t .t , err )
450
+
451
+ // Alice sends a sell order to Bob for some amount of the newly minted
452
+ // asset.
453
+ askAmt := uint64 (42000 )
454
+ sellOrderExpiry := uint64 (time .Now ().Add (24 * time .Hour ).Unix ())
455
+
456
+ // We first try to add a sell order without specifying the asset skip
457
+ // flag. That should result in an error, since we only have a normal
458
+ // channel and not an asset channel.
459
+ sellReq := & rfqrpc.AddAssetSellOrderRequest {
460
+ AssetSpecifier : & rfqrpc.AssetSpecifier {
461
+ Id : & rfqrpc.AssetSpecifier_GroupKey {
462
+ GroupKey : mintedAssetGroupKey ,
463
+ },
464
+ },
465
+ PaymentMaxAmt : askAmt ,
466
+ Expiry : sellOrderExpiry ,
467
+
468
+ // Here we explicitly specify Bob as the destination
469
+ // peer for the sell order. This will prompt Alice's
470
+ // tapd node to send a request for quote message to
471
+ // Bob's node.
472
+ PeerPubKey : ts .BobLnd .PubKey [:],
473
+
474
+ TimeoutSeconds : uint32 (rfqTimeout .Seconds ()),
475
+ }
476
+ _ , err = ts .AliceTapd .AddAssetSellOrder (ctxt , sellReq )
477
+ require .ErrorContains (
478
+ t .t , err , "no asset channel balance found" ,
479
+ )
480
+
481
+ // Now we set the skip flag and we shouldn't get an error anymore.
482
+ sellReq .SkipAssetChannelCheck = true
483
+ _ , err = ts .AliceTapd .AddAssetSellOrder (ctxt , sellReq )
484
+ require .NoError (t .t , err , "unable to upsert asset sell order" )
485
+
486
+ // Wait until Alice receives an incoming sell quote accept message (sent
487
+ // from Bob) RFQ event notification.
488
+ BeforeTimeout (t .t , func () {
489
+ event , err := aliceEventNtfns .Recv ()
490
+ require .NoError (t .t , err )
491
+
492
+ _ , ok := event .Event .(* rfqrpc.RfqEvent_PeerAcceptedSellQuote )
493
+ require .True (t .t , ok , "unexpected event: %v" , event )
494
+ }, rfqTimeout )
495
+
496
+ // We now repeat the same flow, where Alice is making a BuyOrderRequest.
497
+ assetMaxAmt := uint64 (1000 )
498
+ buyOrderExpiry := sellOrderExpiry
499
+
500
+ buyReq := & rfqrpc.AddAssetBuyOrderRequest {
501
+ AssetSpecifier : & rfqrpc.AssetSpecifier {
502
+ Id : & rfqrpc.AssetSpecifier_GroupKey {
503
+ GroupKey : mintedAssetGroupKey ,
504
+ },
505
+ },
506
+ AssetMaxAmt : assetMaxAmt ,
507
+ Expiry : buyOrderExpiry ,
508
+ PeerPubKey : ts .BobLnd .PubKey [:],
509
+ TimeoutSeconds : uint32 (rfqTimeout .Seconds ()),
510
+ }
511
+
512
+ _ , err = ts .AliceTapd .AddAssetBuyOrder (ctxt , buyReq )
513
+ require .ErrorContains (
514
+ t .t , err , "no asset channel balance found" ,
515
+ )
516
+
517
+ // Now we set the skip flag and we shouldn't get an error anymore.
518
+ buyReq .SkipAssetChannelCheck = true
519
+ _ , err = ts .AliceTapd .AddAssetBuyOrder (ctxt , buyReq )
520
+ require .NoError (t .t , err )
521
+
522
+ // Wait until Alice receives an incoming buy quote accept message (sent
523
+ // from Bob) RFQ event notification.
524
+ BeforeTimeout (t .t , func () {
525
+ event , err := aliceEventNtfns .Recv ()
526
+ require .NoError (t .t , err )
527
+
528
+ _ , ok := event .Event .(* rfqrpc.RfqEvent_PeerAcceptedBuyQuote )
529
+ require .True (t .t , ok , "unexpected event: %v" , event )
530
+ }, rfqTimeout )
531
+ }
532
+
427
533
// rfqTestScenario is a struct which holds test scenario helper infra.
428
534
type rfqTestScenario struct {
429
535
testHarness * harnessTest
0 commit comments