keysend_test.go raw
1 package transactions
2
3 import (
4 "context"
5 "encoding/hex"
6 "encoding/json"
7 "errors"
8 "strconv"
9 "testing"
10
11 "github.com/stretchr/testify/assert"
12 "github.com/stretchr/testify/require"
13
14 "github.com/getAlby/hub/constants"
15 "github.com/getAlby/hub/db"
16 "github.com/getAlby/hub/db/queries"
17 "github.com/getAlby/hub/lnclient"
18 "github.com/getAlby/hub/tests"
19 )
20
21 func TestSendKeysend(t *testing.T) {
22 svc, err := tests.CreateTestService(t)
23 require.NoError(t, err)
24 defer svc.Remove()
25
26 mockEventConsumer := tests.NewMockEventConsumer()
27 svc.EventPublisher.RegisterSubscriber(mockEventConsumer)
28
29 transactionsService := NewTransactionsService(svc.DB, svc.EventPublisher)
30 transaction, err := transactionsService.SendKeysend(uint64(1000), "fake destination", nil, "", svc.LNClient, nil, nil)
31 assert.NoError(t, err)
32
33 var metadata lnclient.Metadata
34 err = json.Unmarshal(transaction.Metadata, &metadata)
35 assert.NoError(t, err)
36
37 assert.Equal(t, "fake destination", metadata["destination"])
38 assert.Nil(t, metadata["tlv_records"])
39 assert.Equal(t, uint64(1000), transaction.AmountMsat)
40 assert.Equal(t, constants.TRANSACTION_TYPE_OUTGOING, transaction.Type)
41 assert.Equal(t, constants.TRANSACTION_STATE_SETTLED, transaction.State)
42 assert.Zero(t, transaction.FeeReserveMsat)
43 assert.NotNil(t, transaction.Preimage)
44 assert.Equal(t, 64, len(*transaction.Preimage))
45
46 consumedEvents := mockEventConsumer.WaitForConsumedEvents(1)
47 assert.Equal(t, 1, len(consumedEvents))
48 assert.Equal(t, "nwc_payment_sent", consumedEvents[0].Event)
49 settledTransaction := consumedEvents[0].Properties.(*db.Transaction)
50 assert.Equal(t, transaction, settledTransaction)
51 }
52 func TestSendKeysend_FailedRemovesFeeReserve(t *testing.T) {
53 svc, err := tests.CreateTestService(t)
54 require.NoError(t, err)
55 defer svc.Remove()
56
57 svc.LNClient.(*tests.MockLn).PayKeysendErrors = append(svc.LNClient.(*tests.MockLn).PayKeysendErrors, errors.New("Some error"))
58 svc.LNClient.(*tests.MockLn).PayKeysendResponses = append(svc.LNClient.(*tests.MockLn).PayKeysendResponses, nil)
59
60 mockEventConsumer := tests.NewMockEventConsumer()
61 svc.EventPublisher.RegisterSubscriber(mockEventConsumer)
62
63 transactionsService := NewTransactionsService(svc.DB, svc.EventPublisher)
64 transaction, err := transactionsService.SendKeysend(uint64(1000), "fake destination", nil, "", svc.LNClient, nil, nil)
65
66 assert.Error(t, err)
67 assert.Nil(t, transaction)
68
69 failedTransaction := db.Transaction{}
70 require.NoError(t, svc.DB.Where("type = ? AND state = ?", constants.TRANSACTION_TYPE_OUTGOING, constants.TRANSACTION_STATE_FAILED).First(&failedTransaction).Error)
71
72 assert.Equal(t, uint64(1000), failedTransaction.AmountMsat)
73 assert.Zero(t, failedTransaction.FeeReserveMsat)
74 assert.Equal(t, "Some error", failedTransaction.FailureReason)
75
76 consumedEvents := mockEventConsumer.WaitForConsumedEvents(1)
77 assert.Equal(t, 1, len(consumedEvents))
78 assert.Equal(t, "nwc_payment_failed", consumedEvents[0].Event)
79 }
80
81 func TestSendKeysend_CustomPreimage(t *testing.T) {
82 svc, err := tests.CreateTestService(t)
83 require.NoError(t, err)
84 defer svc.Remove()
85
86 customPreimage := "018465013e2337234a7e5530a21c4a8cf70d84231f4a8ff0b1e2cce3cb2bd03b"
87 transactionsService := NewTransactionsService(svc.DB, svc.EventPublisher)
88 transaction, err := transactionsService.SendKeysend(uint64(1000), "fake destination", nil, customPreimage, svc.LNClient, nil, nil)
89 assert.NoError(t, err)
90
91 var metadata lnclient.Metadata
92 err = json.Unmarshal(transaction.Metadata, &metadata)
93 assert.NoError(t, err)
94
95 assert.Equal(t, "fake destination", metadata["destination"])
96 assert.Nil(t, metadata["tlv_records"])
97 assert.Equal(t, uint64(1000), transaction.AmountMsat)
98 assert.Equal(t, constants.TRANSACTION_TYPE_OUTGOING, transaction.Type)
99 assert.Equal(t, constants.TRANSACTION_STATE_SETTLED, transaction.State)
100 assert.Zero(t, transaction.FeeReserveMsat)
101 assert.NotNil(t, transaction.Preimage)
102 assert.Equal(t, customPreimage, *transaction.Preimage)
103 }
104
105 func TestSendKeysend_App_NoPermission(t *testing.T) {
106 svc, err := tests.CreateTestService(t)
107 require.NoError(t, err)
108 defer svc.Remove()
109
110 app, _, err := tests.CreateApp(svc)
111 assert.NoError(t, err)
112
113 dbRequestEvent := &db.RequestEvent{}
114 err = svc.DB.Create(&dbRequestEvent).Error
115 assert.NoError(t, err)
116
117 transactionsService := NewTransactionsService(svc.DB, svc.EventPublisher)
118 transaction, err := transactionsService.SendKeysend(uint64(1000), "fake destination", nil, "", svc.LNClient, &app.ID, &dbRequestEvent.ID)
119
120 assert.Error(t, err)
121 assert.Equal(t, "app does not have pay_invoice scope", err.Error())
122 assert.Nil(t, transaction)
123 }
124
125 func TestSendKeysend_App_WithPermission(t *testing.T) {
126 svc, err := tests.CreateTestService(t)
127 require.NoError(t, err)
128 defer svc.Remove()
129
130 app, _, err := tests.CreateApp(svc)
131 assert.NoError(t, err)
132
133 dbRequestEvent := &db.RequestEvent{}
134 err = svc.DB.Create(&dbRequestEvent).Error
135 assert.NoError(t, err)
136
137 appPermission := &db.AppPermission{
138 AppId: app.ID,
139 App: *app,
140 Scope: constants.PAY_INVOICE_SCOPE,
141 }
142 err = svc.DB.Create(appPermission).Error
143 assert.NoError(t, err)
144
145 transactionsService := NewTransactionsService(svc.DB, svc.EventPublisher)
146 transaction, err := transactionsService.SendKeysend(uint64(1000), "fake destination", nil, "", svc.LNClient, &app.ID, &dbRequestEvent.ID)
147 assert.NoError(t, err)
148
149 var metadata lnclient.Metadata
150 err = json.Unmarshal(transaction.Metadata, &metadata)
151 assert.NoError(t, err)
152
153 assert.Equal(t, "fake destination", metadata["destination"])
154 assert.Nil(t, metadata["tlv_records"])
155 assert.Equal(t, uint64(1000), transaction.AmountMsat)
156 assert.Equal(t, constants.TRANSACTION_TYPE_OUTGOING, transaction.Type)
157 assert.Equal(t, constants.TRANSACTION_STATE_SETTLED, transaction.State)
158 assert.Equal(t, app.ID, *transaction.AppId)
159 assert.Equal(t, dbRequestEvent.ID, *transaction.RequestEventId)
160 assert.Zero(t, transaction.FeeReserveMsat)
161 assert.NotNil(t, transaction.Preimage)
162 assert.Equal(t, 64, len(*transaction.Preimage))
163 }
164
165 func TestSendKeysend_App_BudgetExceeded(t *testing.T) {
166 svc, err := tests.CreateTestService(t)
167 require.NoError(t, err)
168 defer svc.Remove()
169
170 app, _, err := tests.CreateApp(svc)
171 assert.NoError(t, err)
172
173 dbRequestEvent := &db.RequestEvent{}
174 err = svc.DB.Create(&dbRequestEvent).Error
175 assert.NoError(t, err)
176
177 appPermission := &db.AppPermission{
178 AppId: app.ID,
179 App: *app,
180 Scope: constants.PAY_INVOICE_SCOPE,
181 MaxAmountSat: 10, // not enough for the fee reserve
182 }
183 err = svc.DB.Create(appPermission).Error
184 assert.NoError(t, err)
185
186 mockEventConsumer := tests.NewMockEventConsumer()
187 svc.EventPublisher.RegisterSubscriber(mockEventConsumer)
188
189 transactionsService := NewTransactionsService(svc.DB, svc.EventPublisher)
190 transaction, err := transactionsService.SendKeysend(uint64(1000), "fake destination", nil, "", svc.LNClient, &app.ID, &dbRequestEvent.ID)
191
192 assert.ErrorIs(t, err, NewQuotaExceededError())
193 assert.Nil(t, transaction)
194
195 consumedEvents := mockEventConsumer.WaitForConsumedEvents(1)
196 assert.Equal(t, 1, len(consumedEvents))
197 assert.Equal(t, "nwc_permission_denied", consumedEvents[0].Event)
198 assert.Equal(t, app.Name, consumedEvents[0].Properties.(map[string]interface{})["app_name"])
199 assert.Equal(t, constants.ERROR_QUOTA_EXCEEDED, consumedEvents[0].Properties.(map[string]interface{})["code"])
200 assert.Equal(t, NewQuotaExceededError().Error(), consumedEvents[0].Properties.(map[string]interface{})["message"])
201 }
202 func TestSendKeysend_App_BudgetNotExceeded(t *testing.T) {
203 svc, err := tests.CreateTestService(t)
204 require.NoError(t, err)
205 defer svc.Remove()
206
207 app, _, err := tests.CreateApp(svc)
208 assert.NoError(t, err)
209
210 dbRequestEvent := &db.RequestEvent{}
211 err = svc.DB.Create(&dbRequestEvent).Error
212 assert.NoError(t, err)
213
214 appPermission := &db.AppPermission{
215 AppId: app.ID,
216 App: *app,
217 Scope: constants.PAY_INVOICE_SCOPE,
218 MaxAmountSat: 11, // fee reserve (10) + keysend amount (1)
219 }
220 err = svc.DB.Create(appPermission).Error
221 assert.NoError(t, err)
222
223 transactionsService := NewTransactionsService(svc.DB, svc.EventPublisher)
224 transaction, err := transactionsService.SendKeysend(uint64(1000), "fake destination", nil, "", svc.LNClient, &app.ID, &dbRequestEvent.ID)
225 assert.NoError(t, err)
226
227 var metadata lnclient.Metadata
228 err = json.Unmarshal(transaction.Metadata, &metadata)
229 assert.NoError(t, err)
230
231 assert.Equal(t, "fake destination", metadata["destination"])
232 assert.Nil(t, metadata["tlv_records"])
233 assert.Equal(t, uint64(1000), transaction.AmountMsat)
234 assert.Equal(t, constants.TRANSACTION_TYPE_OUTGOING, transaction.Type)
235 assert.Equal(t, constants.TRANSACTION_STATE_SETTLED, transaction.State)
236 assert.Equal(t, app.ID, *transaction.AppId)
237 assert.Equal(t, dbRequestEvent.ID, *transaction.RequestEventId)
238 assert.Zero(t, transaction.FeeReserveMsat)
239 assert.NotNil(t, transaction.Preimage)
240 assert.Equal(t, 64, len(*transaction.Preimage))
241 }
242
243 func TestSendKeysend_App_BalanceExceeded(t *testing.T) {
244 svc, err := tests.CreateTestService(t)
245 require.NoError(t, err)
246 defer svc.Remove()
247
248 app, _, err := tests.CreateApp(svc)
249 assert.NoError(t, err)
250
251 dbRequestEvent := &db.RequestEvent{}
252 err = svc.DB.Create(&dbRequestEvent).Error
253 assert.NoError(t, err)
254 app.Isolated = true
255 svc.DB.Save(&app)
256
257 appPermission := &db.AppPermission{
258 AppId: app.ID,
259 App: *app,
260 Scope: constants.PAY_INVOICE_SCOPE,
261 }
262 err = svc.DB.Create(appPermission).Error
263 assert.NoError(t, err)
264
265 svc.DB.Create(&db.Transaction{
266 AppId: &app.ID,
267 State: constants.TRANSACTION_STATE_SETTLED,
268 Type: constants.TRANSACTION_TYPE_INCOMING,
269 AmountMsat: 10000, // invoice is 1000 msat, but we also calculate fee reserves max of(10 sats or 1%)
270 })
271
272 transactionsService := NewTransactionsService(svc.DB, svc.EventPublisher)
273 transaction, err := transactionsService.SendKeysend(uint64(1000), "fake destination", nil, "", svc.LNClient, &app.ID, &dbRequestEvent.ID)
274
275 assert.ErrorIs(t, err, NewInsufficientBalanceError())
276 assert.Nil(t, transaction)
277 }
278
279 func TestSendKeysend_App_BalanceSufficient(t *testing.T) {
280 svc, err := tests.CreateTestService(t)
281 require.NoError(t, err)
282 defer svc.Remove()
283
284 app, _, err := tests.CreateApp(svc)
285 assert.NoError(t, err)
286
287 dbRequestEvent := &db.RequestEvent{}
288 err = svc.DB.Create(&dbRequestEvent).Error
289 assert.NoError(t, err)
290 app.Isolated = true
291 svc.DB.Save(&app)
292
293 appPermission := &db.AppPermission{
294 AppId: app.ID,
295 App: *app,
296 Scope: constants.PAY_INVOICE_SCOPE,
297 }
298 err = svc.DB.Create(appPermission).Error
299 assert.NoError(t, err)
300
301 svc.DB.Create(&db.Transaction{
302 AppId: &app.ID,
303 State: constants.TRANSACTION_STATE_SETTLED,
304 Type: constants.TRANSACTION_TYPE_INCOMING,
305 AmountMsat: 11000, // invoice is 1000 msat, but we also calculate fee reserves max of(10 sats or 1%)
306 })
307
308 transactionsService := NewTransactionsService(svc.DB, svc.EventPublisher)
309 transaction, err := transactionsService.SendKeysend(uint64(1000), "fake destination", nil, "", svc.LNClient, &app.ID, &dbRequestEvent.ID)
310 assert.NoError(t, err)
311
312 var metadata lnclient.Metadata
313 err = json.Unmarshal(transaction.Metadata, &metadata)
314 assert.NoError(t, err)
315
316 assert.Equal(t, "fake destination", metadata["destination"])
317 assert.Nil(t, metadata["tlv_records"])
318 assert.Equal(t, uint64(1000), transaction.AmountMsat)
319 assert.Equal(t, constants.TRANSACTION_TYPE_OUTGOING, transaction.Type)
320 assert.Equal(t, constants.TRANSACTION_STATE_SETTLED, transaction.State)
321 assert.Equal(t, app.ID, *transaction.AppId)
322 assert.Equal(t, dbRequestEvent.ID, *transaction.RequestEventId)
323 assert.NotNil(t, transaction.Preimage)
324 assert.Equal(t, 64, len(*transaction.Preimage))
325 assert.Zero(t, transaction.FeeReserveMsat)
326 }
327
328 func TestSendKeysend_TLVs(t *testing.T) {
329 svc, err := tests.CreateTestService(t)
330 require.NoError(t, err)
331 defer svc.Remove()
332
333 transactionsService := NewTransactionsService(svc.DB, svc.EventPublisher)
334 transaction, err := transactionsService.SendKeysend(uint64(1000), "fake destination", []lnclient.TLVRecord{
335 {
336 Type: 7629169,
337 Value: "7b22616374696f6e223a22626f6f7374222c2276616c75655f6d736174223a313030302c2276616c75655f6d7361745f746f74616c223a313030302c226170705f6e616d65223a22e29aa1205765624c4e2044656d6f222c226170705f76657273696f6e223a22312e30222c22666565644944223a2268747470733a2f2f66656564732e706f6463617374696e6465782e6f72672f706332302e786d6c222c22706f6463617374223a22506f6463617374696e6720322e30222c22657069736f6465223a22457069736f6465203130343a2041204e65772044756d70222c227473223a32312c226e616d65223a22e29aa1205765624c4e2044656d6f222c2273656e6465725f6e616d65223a225361746f736869204e616b616d6f746f222c226d657373616765223a22476f20706f6463617374696e6721227d",
338 },
339 }, "", svc.LNClient, nil, nil)
340 assert.NoError(t, err)
341
342 var metadata lnclient.Metadata
343 err = json.Unmarshal(transaction.Metadata, &metadata)
344 assert.NoError(t, err)
345
346 assert.Equal(t, "fake destination", metadata["destination"])
347 assert.NotNil(t, metadata["tlv_records"])
348
349 var boostagram Boostagram
350 err = json.Unmarshal(transaction.Boostagram, &boostagram)
351 assert.NoError(t, err)
352
353 assert.Equal(t, "⚡ WebLN Demo", boostagram.AppName)
354 assert.Equal(t, "⚡ WebLN Demo", boostagram.Name)
355 assert.Equal(t, "Podcasting 2.0", boostagram.Podcast)
356 assert.Equal(t, "Episode 104: A New Dump", boostagram.Episode.String())
357 assert.Equal(t, "https://feeds.podcastindex.org/pc20.xml", boostagram.FeedId.String())
358 assert.Equal(t, int64(21), boostagram.Timestamp)
359 assert.Equal(t, "Go podcasting!", boostagram.Message)
360 assert.Equal(t, "Satoshi Nakamoto", boostagram.SenderName)
361 assert.Equal(t, "boost", boostagram.Action)
362 assert.Equal(t, int64(1000), boostagram.ValueMsatTotal)
363
364 assert.Equal(t, "Go podcasting!", transaction.Description)
365
366 assert.Equal(t, uint64(1000), transaction.AmountMsat)
367 assert.Equal(t, constants.TRANSACTION_TYPE_OUTGOING, transaction.Type)
368 assert.Equal(t, constants.TRANSACTION_STATE_SETTLED, transaction.State)
369 assert.NotNil(t, transaction.Preimage)
370 assert.Equal(t, 64, len(*transaction.Preimage))
371 assert.Zero(t, transaction.FeeReserveMsat)
372 }
373
374 func TestSendKeysend_IsolatedAppToNoApp(t *testing.T) {
375 svc, err := tests.CreateTestService(t)
376 require.NoError(t, err)
377 defer svc.Remove()
378
379 // setup for self payment
380 svc.LNClient.(*tests.MockLn).Pubkey = "03cbd788f5b22bd56e2714bff756372d2293504c064e03250ed16a4dd80ad70e2c"
381
382 app, _, err := tests.CreateApp(svc)
383 assert.NoError(t, err)
384 app.Isolated = true
385 err = svc.DB.Save(&app).Error
386 assert.NoError(t, err)
387
388 appPermission := &db.AppPermission{
389 AppId: app.ID,
390 App: *app,
391 Scope: constants.PAY_INVOICE_SCOPE,
392 }
393 err = svc.DB.Create(appPermission).Error
394 assert.NoError(t, err)
395
396 // give the isolated app 133 sats
397 svc.DB.Create(&db.Transaction{
398 AppId: &app.ID,
399 State: constants.TRANSACTION_STATE_SETTLED,
400 Type: constants.TRANSACTION_TYPE_INCOMING,
401 AmountMsat: 133000, // payment is 123000 msat, but we also calculate fee reserves max of(10 sats or 1%)
402 })
403
404 dbRequestEvent := &db.RequestEvent{}
405 err = svc.DB.Create(&dbRequestEvent).Error
406 assert.NoError(t, err)
407
408 mockPreimage := "c8aeb44ae8eb269c8dbfb7ec5c263f0bfa3d755bc0ca641b8ee118673afda657"
409
410 transactionsService := NewTransactionsService(svc.DB, svc.EventPublisher)
411 transaction, err := transactionsService.SendKeysend(123000, "03cbd788f5b22bd56e2714bff756372d2293504c064e03250ed16a4dd80ad70e2c", []lnclient.TLVRecord{}, mockPreimage, svc.LNClient, &app.ID, &dbRequestEvent.ID)
412
413 assert.NoError(t, err)
414 assert.NotNil(t, transaction)
415 assert.Equal(t, uint64(123000), transaction.AmountMsat)
416 assert.Equal(t, constants.TRANSACTION_STATE_SETTLED, transaction.State)
417 assert.Equal(t, mockPreimage, *transaction.Preimage)
418 assert.Equal(t, app.ID, *transaction.AppId)
419 assert.Equal(t, dbRequestEvent.ID, *transaction.RequestEventId)
420 assert.True(t, transaction.SelfPayment)
421
422 transactionType := constants.TRANSACTION_TYPE_INCOMING
423 incomingTransaction, err := transactionsService.LookupTransaction(context.TODO(), transaction.PaymentHash, &transactionType, svc.LNClient, nil)
424 assert.NoError(t, err)
425 assert.Equal(t, uint64(123000), incomingTransaction.AmountMsat)
426 assert.Equal(t, constants.TRANSACTION_STATE_SETTLED, incomingTransaction.State)
427 assert.Equal(t, mockPreimage, *incomingTransaction.Preimage)
428 assert.True(t, incomingTransaction.SelfPayment)
429
430 transactions := []db.Transaction{}
431 result := svc.DB.Find(&transactions)
432 assert.Equal(t, int64(3), result.RowsAffected)
433 // expect balance to be decreased
434 balanceMsat, err := queries.GetIsolatedBalanceMsat(svc.DB, app.ID)
435 assert.NoError(t, err)
436 assert.Equal(t, int64(10000), balanceMsat)
437 }
438
439 func TestSendKeysend_IsolatedAppToIsolatedApp(t *testing.T) {
440 svc, err := tests.CreateTestService(t)
441 require.NoError(t, err)
442 defer svc.Remove()
443
444 // setup for self payment
445 svc.LNClient.(*tests.MockLn).Pubkey = "03cbd788f5b22bd56e2714bff756372d2293504c064e03250ed16a4dd80ad70e2c"
446
447 app, _, err := tests.CreateApp(svc)
448 assert.NoError(t, err)
449 app.Isolated = true
450 err = svc.DB.Save(&app).Error
451 assert.NoError(t, err)
452
453 app2, _, err := tests.CreateApp(svc)
454 assert.NoError(t, err)
455 app2.Isolated = true
456 err = svc.DB.Save(&app2).Error
457 assert.NoError(t, err)
458
459 appPermission := &db.AppPermission{
460 AppId: app.ID,
461 App: *app,
462 Scope: constants.PAY_INVOICE_SCOPE,
463 }
464 err = svc.DB.Create(appPermission).Error
465 assert.NoError(t, err)
466
467 // give the isolated app 133 sats
468 svc.DB.Create(&db.Transaction{
469 AppId: &app.ID,
470 State: constants.TRANSACTION_STATE_SETTLED,
471 Type: constants.TRANSACTION_TYPE_INCOMING,
472 AmountMsat: 133000, // payment is 123000 msat, but we also calculate fee reserves max of(10 sats or 1%)
473 })
474
475 dbRequestEvent := &db.RequestEvent{}
476 err = svc.DB.Create(&dbRequestEvent).Error
477 assert.NoError(t, err)
478
479 mockPreimage := "c8aeb44ae8eb269c8dbfb7ec5c263f0bfa3d755bc0ca641b8ee118673afda657"
480
481 // Keysend from app 1 to app 2
482 tlvRecords := []lnclient.TLVRecord{
483 {
484 Type: 696969,
485 Value: hex.EncodeToString([]byte(strconv.FormatUint(uint64(app2.ID), 10))),
486 },
487 {
488 Type: 7629169,
489 Value: "7b22616374696f6e223a22626f6f7374222c2276616c75655f6d736174223a313030302c2276616c75655f6d7361745f746f74616c223a313030302c226170705f6e616d65223a22e29aa1205765624c4e2044656d6f222c226170705f76657273696f6e223a22312e30222c22666565644944223a2268747470733a2f2f66656564732e706f6463617374696e6465782e6f72672f706332302e786d6c222c22706f6463617374223a22506f6463617374696e6720322e30222c22657069736f6465223a22457069736f6465203130343a2041204e65772044756d70222c227473223a32312c226e616d65223a22e29aa1205765624c4e2044656d6f222c2273656e6465725f6e616d65223a225361746f736869204e616b616d6f746f222c226d657373616765223a22476f20706f6463617374696e6721227d",
490 },
491 }
492
493 mockEventConsumer := tests.NewMockEventConsumer()
494 svc.EventPublisher.RegisterSubscriber(mockEventConsumer)
495
496 transactionsService := NewTransactionsService(svc.DB, svc.EventPublisher)
497 transaction, err := transactionsService.SendKeysend(123000, "03cbd788f5b22bd56e2714bff756372d2293504c064e03250ed16a4dd80ad70e2c", tlvRecords, mockPreimage, svc.LNClient, &app.ID, &dbRequestEvent.ID)
498
499 assert.NoError(t, err)
500 assert.NotNil(t, transaction)
501 assert.Equal(t, uint64(123000), transaction.AmountMsat)
502 assert.Equal(t, constants.TRANSACTION_STATE_SETTLED, transaction.State)
503 assert.Equal(t, mockPreimage, *transaction.Preimage)
504 assert.Equal(t, app.ID, *transaction.AppId)
505 assert.Equal(t, dbRequestEvent.ID, *transaction.RequestEventId)
506 assert.True(t, transaction.SelfPayment)
507
508 transactionType := constants.TRANSACTION_TYPE_INCOMING
509 incomingTransaction, err := transactionsService.LookupTransaction(context.TODO(), transaction.PaymentHash, &transactionType, svc.LNClient, &app2.ID)
510 assert.NoError(t, err)
511 assert.Equal(t, uint64(123000), incomingTransaction.AmountMsat)
512 assert.Equal(t, constants.TRANSACTION_STATE_SETTLED, incomingTransaction.State)
513 assert.Equal(t, mockPreimage, *incomingTransaction.Preimage)
514 assert.Equal(t, app2.ID, *incomingTransaction.AppId)
515 assert.True(t, incomingTransaction.SelfPayment)
516
517 // receiving app should have the same data as what was sent
518 assert.Equal(t, transaction.Description, incomingTransaction.Description)
519 assert.Equal(t, transaction.Metadata, incomingTransaction.Metadata)
520 assert.Equal(t, transaction.Boostagram, incomingTransaction.Boostagram)
521
522 transactions := []db.Transaction{}
523 result := svc.DB.Find(&transactions)
524 assert.Equal(t, int64(3), result.RowsAffected)
525 // expect balance to be decreased
526 balanceMsat, err := queries.GetIsolatedBalanceMsat(svc.DB, app.ID)
527 assert.NoError(t, err)
528 assert.Equal(t, int64(10000), balanceMsat)
529
530 // expect app2 to receive the payment
531 balanceMsat, err = queries.GetIsolatedBalanceMsat(svc.DB, app2.ID)
532 assert.NoError(t, err)
533 assert.Equal(t, int64(123000), balanceMsat)
534
535 // check notifications
536 consumedEvents := mockEventConsumer.WaitForConsumedEvents(2)
537 assert.Equal(t, 2, len(consumedEvents))
538
539 // we can't guarantee which notification was processed first because events are published async
540 // so swap them if they are back to front
541 if consumedEvents[1].Event == "nwc_payment_received" {
542 consumedEvents[0], consumedEvents[1] = consumedEvents[1], consumedEvents[0]
543 }
544
545 assert.Equal(t, "nwc_payment_sent", consumedEvents[1].Event)
546 settledTransaction := consumedEvents[1].Properties.(*db.Transaction)
547 assert.Equal(t, transaction.ID, settledTransaction.ID)
548
549 assert.Equal(t, "nwc_payment_received", consumedEvents[0].Event)
550 receivedTransaction := consumedEvents[0].Properties.(*db.Transaction)
551 assert.Equal(t, incomingTransaction.ID, receivedTransaction.ID)
552 }
553