1
1
package itest
2
2
3
3
import (
4
+ "bytes"
4
5
"context"
5
6
"fmt"
6
7
"math"
@@ -15,6 +16,7 @@ import (
15
16
"github.com/lightninglabs/taproot-assets/rfqmath"
16
17
"github.com/lightninglabs/taproot-assets/rfqmsg"
17
18
"github.com/lightninglabs/taproot-assets/taprpc/mintrpc"
19
+ oraclerpc "github.com/lightninglabs/taproot-assets/taprpc/priceoraclerpc"
18
20
"github.com/lightninglabs/taproot-assets/taprpc/rfqrpc"
19
21
"github.com/lightningnetwork/lnd/chainreg"
20
22
"github.com/lightningnetwork/lnd/lnrpc"
@@ -25,6 +27,7 @@ import (
25
27
"github.com/lightningnetwork/lnd/lntest/wait"
26
28
"github.com/lightningnetwork/lnd/lnwire"
27
29
"github.com/lightningnetwork/lnd/tlv"
30
+ "github.com/stretchr/testify/mock"
28
31
"github.com/stretchr/testify/require"
29
32
)
30
33
49
52
// As a final step (which is not part of this test), Bob's node will transfer
50
53
// the tap asset to Carol's node.
51
54
func testRfqAssetBuyHtlcIntercept (t * harnessTest ) {
55
+ // For this test we'll use an actual oracle RPC server harness.
56
+ oracleAddr := fmt .Sprintf ("localhost:%d" , port .NextAvailablePort ())
57
+ oracle := newOracleHarness (oracleAddr )
58
+ oracle .start (t .t )
59
+ t .t .Cleanup (oracle .stop )
60
+
61
+ // We need to craft the oracle server URL in the correct format.
62
+ oracleURL := fmt .Sprintf ("rfqrpc://%s" , oracleAddr )
63
+
52
64
// Initialize a new test scenario.
53
- ts := newRfqTestScenario (t )
65
+ ts := newRfqTestScenario (t , WithRfqOracleServer ( oracleURL ) )
54
66
55
67
// Mint an asset with Bob's tapd node.
56
68
rpcAssets := MintAssetsConfirmBatch (
@@ -108,8 +120,74 @@ func testRfqAssetBuyHtlcIntercept(t *harnessTest) {
108
120
// node.
109
121
PeerPubKey : ts .BobLnd .PubKey [:],
110
122
111
- TimeoutSeconds : uint32 (rfqTimeout .Seconds ()),
123
+ TimeoutSeconds : uint32 (rfqTimeout .Seconds ()),
124
+ PriceOracleMetadata : "buy-order-1" ,
112
125
}
126
+
127
+ // We now set up the expected calls that should come in to the mock
128
+ // oracle server during the process.
129
+ buySpecifier := & oraclerpc.AssetSpecifier {
130
+ Id : & oraclerpc.AssetSpecifier_AssetId {
131
+ AssetId : mintedAssetId ,
132
+ },
133
+ }
134
+ btcSpecifier := & oraclerpc.AssetSpecifier {
135
+ Id : & oraclerpc.AssetSpecifier_AssetId {
136
+ AssetId : bytes .Repeat ([]byte {0 }, 32 ),
137
+ },
138
+ }
139
+ mockResult := & oraclerpc.QueryAssetRatesResponse {
140
+ Result : & oraclerpc.QueryAssetRatesResponse_Ok {
141
+ Ok : & oraclerpc.QueryAssetRatesOkResponse {
142
+ AssetRates : & oraclerpc.AssetRates {
143
+ SubjectAssetRate : & oraclerpc.FixedPoint {
144
+ Coefficient : "1000000" ,
145
+ Scale : 3 ,
146
+ },
147
+ ExpiryTimestamp : uint64 (
148
+ time .Now ().Add (time .Minute ).
149
+ Unix (),
150
+ ),
151
+ },
152
+ },
153
+ },
154
+ }
155
+
156
+ // The first call is expected to be the rate hint call for the local
157
+ // oracle, using the hint intent.
158
+ oracle .On (
159
+ "QueryAssetRates" , oraclerpc .TransactionType_PURCHASE ,
160
+ buySpecifier , purchaseAssetAmt , btcSpecifier ,
161
+ mock .Anything , mock .Anything ,
162
+ oraclerpc .Intent_INTENT_RECV_PAYMENT_HINT ,
163
+ mock .Anything , "buy-order-1" ,
164
+ ).Return (mockResult , nil ).Once ()
165
+
166
+ // Then the counterparty will do a sale call with the intent to receive
167
+ // a payment.
168
+ oracle .On (
169
+ "QueryAssetRates" , oraclerpc .TransactionType_SALE ,
170
+ buySpecifier , purchaseAssetAmt , btcSpecifier ,
171
+ mock .Anything , mock .Anything ,
172
+ oraclerpc .Intent_INTENT_RECV_PAYMENT ,
173
+ mock .Anything , "buy-order-1" ,
174
+ ).Return (mockResult , nil ).Once ()
175
+
176
+ // And finally, we'll qualify (validate) the price again on our end.
177
+ oracle .On (
178
+ "QueryAssetRates" , oraclerpc .TransactionType_PURCHASE ,
179
+ buySpecifier , purchaseAssetAmt , btcSpecifier ,
180
+ mock .Anything , mock .Anything ,
181
+ oraclerpc .Intent_INTENT_RECV_PAYMENT_QUALIFY ,
182
+ mock .Anything , "buy-order-1" ,
183
+ ).Return (mockResult , nil ).Once ()
184
+
185
+ // At the end of the test, we also want to make sure each call came in
186
+ // as expected.
187
+ defer func () {
188
+ oracle .AssertExpectations (t .t )
189
+ }()
190
+
113
191
_ , err = ts .AliceTapd .AddAssetBuyOrder (ctxt , buyReq )
114
192
require .ErrorContains (
115
193
t .t , err , "error checking peer channel: error checking asset " +
@@ -236,8 +314,17 @@ func testRfqAssetBuyHtlcIntercept(t *harnessTest) {
236
314
// validation between three peers. The RFQ negotiation is initiated by an asset
237
315
// sell request.
238
316
func testRfqAssetSellHtlcIntercept (t * harnessTest ) {
317
+ // For this test we'll use an actual oracle RPC server harness.
318
+ oracleAddr := fmt .Sprintf ("localhost:%d" , port .NextAvailablePort ())
319
+ oracle := newOracleHarness (oracleAddr )
320
+ oracle .start (t .t )
321
+ t .t .Cleanup (oracle .stop )
322
+
323
+ // We need to craft the oracle server URL in the correct format.
324
+ oracleURL := fmt .Sprintf ("rfqrpc://%s" , oracleAddr )
325
+
239
326
// Initialize a new test scenario.
240
- ts := newRfqTestScenario (t )
327
+ ts := newRfqTestScenario (t , WithRfqOracleServer ( oracleURL ) )
241
328
242
329
// Mint an asset with Alice's tapd node.
243
330
rpcAssets := MintAssetsConfirmBatch (
@@ -297,8 +384,74 @@ func testRfqAssetSellHtlcIntercept(t *harnessTest) {
297
384
// Bob's node.
298
385
PeerPubKey : ts .BobLnd .PubKey [:],
299
386
300
- TimeoutSeconds : uint32 (rfqTimeout .Seconds ()),
387
+ TimeoutSeconds : uint32 (rfqTimeout .Seconds ()),
388
+ PriceOracleMetadata : "sell-order-1" ,
389
+ }
390
+
391
+ // We now set up the expected calls that should come in to the mock
392
+ // oracle server during the process.
393
+ buySpecifier := & oraclerpc.AssetSpecifier {
394
+ Id : & oraclerpc.AssetSpecifier_AssetId {
395
+ AssetId : mintedAssetIdBytes ,
396
+ },
301
397
}
398
+ btcSpecifier := & oraclerpc.AssetSpecifier {
399
+ Id : & oraclerpc.AssetSpecifier_AssetId {
400
+ AssetId : bytes .Repeat ([]byte {0 }, 32 ),
401
+ },
402
+ }
403
+ mockResult := & oraclerpc.QueryAssetRatesResponse {
404
+ Result : & oraclerpc.QueryAssetRatesResponse_Ok {
405
+ Ok : & oraclerpc.QueryAssetRatesOkResponse {
406
+ AssetRates : & oraclerpc.AssetRates {
407
+ SubjectAssetRate : & oraclerpc.FixedPoint {
408
+ Coefficient : "1000000" ,
409
+ Scale : 3 ,
410
+ },
411
+ ExpiryTimestamp : uint64 (
412
+ time .Now ().Add (time .Minute ).
413
+ Unix (),
414
+ ),
415
+ },
416
+ },
417
+ },
418
+ }
419
+
420
+ // The first call is expected to be the rate hint call for the local
421
+ // oracle, using the hint intent.
422
+ oracle .On (
423
+ "QueryAssetRates" , oraclerpc .TransactionType_SALE ,
424
+ buySpecifier , mock .Anything , btcSpecifier ,
425
+ askAmt , mock .Anything ,
426
+ oraclerpc .Intent_INTENT_PAY_INVOICE_HINT ,
427
+ mock .Anything , "sell-order-1" ,
428
+ ).Return (mockResult , nil ).Once ()
429
+
430
+ // Then the counterparty will do a sale call with the intent to receive
431
+ // a payment.
432
+ oracle .On (
433
+ "QueryAssetRates" , oraclerpc .TransactionType_PURCHASE ,
434
+ buySpecifier , mock .Anything , btcSpecifier ,
435
+ askAmt , mock .Anything ,
436
+ oraclerpc .Intent_INTENT_PAY_INVOICE ,
437
+ mock .Anything , "sell-order-1" ,
438
+ ).Return (mockResult , nil ).Once ()
439
+
440
+ // And finally, we'll qualify (validate) the price again on our end.
441
+ oracle .On (
442
+ "QueryAssetRates" , oraclerpc .TransactionType_SALE ,
443
+ buySpecifier , mock .Anything , btcSpecifier ,
444
+ askAmt , mock .Anything ,
445
+ oraclerpc .Intent_INTENT_PAY_INVOICE_QUALIFY ,
446
+ mock .Anything , "sell-order-1" ,
447
+ ).Return (mockResult , nil ).Once ()
448
+
449
+ // At the end of the test, we also want to make sure each call came in
450
+ // as expected.
451
+ defer func () {
452
+ oracle .AssertExpectations (t .t )
453
+ }()
454
+
302
455
_ , err = ts .AliceTapd .AddAssetSellOrder (ctxt , sellReq )
303
456
require .ErrorContains (
304
457
t .t , err , "error checking peer channel: error checking asset " +
@@ -690,18 +843,18 @@ func newRfqTestScenario(t *harnessTest, opts ...RfqOption) *rfqTestScenario {
690
843
aliceTapd := setupTapdHarness (
691
844
t .t , t , aliceLnd , t .universeServer , WithOracleServer (
692
845
rfqOpts .oracleServerAddr , rfqOpts .oracleServerAlice ,
693
- ),
846
+ ), WithSendPriceHint (),
694
847
)
695
848
696
849
bobTapd := setupTapdHarness (
697
850
t .t , t , bobLnd , t .universeServer , WithOracleServer (
698
851
rfqOpts .oracleServerAddr , rfqOpts .oracleServerBob ,
699
- ),
852
+ ), WithSendPriceHint (),
700
853
)
701
854
carolTapd := setupTapdHarness (
702
855
t .t , t , carolLnd , t .universeServer , WithOracleServer (
703
856
rfqOpts .oracleServerAddr , rfqOpts .oracleServerCarol ,
704
- ),
857
+ ), WithSendPriceHint (),
705
858
)
706
859
707
860
ts := rfqTestScenario {
0 commit comments