settle_hold_invoice_controller_test.go raw

   1  package controllers
   2  
   3  import (
   4  	"context"
   5  	"encoding/json"
   6  	"testing"
   7  
   8  	"github.com/getAlby/go-nostr"
   9  	"github.com/stretchr/testify/assert"
  10  	"github.com/stretchr/testify/require"
  11  
  12  	"time"
  13  
  14  	"github.com/getAlby/hub/constants"
  15  	"github.com/getAlby/hub/db"
  16  
  17  	"crypto/sha256"
  18  	"encoding/hex"
  19  
  20  	"github.com/getAlby/hub/nip47/models"
  21  	"github.com/getAlby/hub/tests"
  22  )
  23  
  24  const nip47SettleHoldInvoiceJson = `
  25  {
  26  "method": "settle_hold_invoice",
  27  "params": {
  28  "preimage": "1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"
  29  }
  30  }
  31  `
  32  
  33  const testSettlePreimage = "1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"
  34  const testSettlePaymentHash = "b7e060a60bb7a82f536a73c17bde37a1b6cf5769ee4a8325bff76c55a95b6aa4"
  35  
  36  type settleHoldInvoiceTestSetup struct {
  37  	ctx            context.Context
  38  	svc            *tests.TestService
  39  	nip47Request   *models.Request
  40  	app            *db.App
  41  	dbRequestEvent *db.RequestEvent
  42  	publishCalled  bool
  43  	response       *models.Response
  44  }
  45  
  46  func setupSettleHoldInvoiceTest(t *testing.T, preimage string, paymentHashToCreate string, initialTransactionState string) *settleHoldInvoiceTestSetup {
  47  	ctx := context.TODO()
  48  	svc, err := tests.CreateTestService(t)
  49  	require.NoError(t, err)
  50  
  51  	nip47Request := &models.Request{}
  52  	requestJson := `
  53  {
  54  "method": "settle_hold_invoice",
  55  "params": {
  56  "preimage": "` + preimage + `"
  57  }
  58  }
  59  `
  60  	err = json.Unmarshal([]byte(requestJson), nip47Request)
  61  	require.NoError(t, err)
  62  
  63  	app, _, err := tests.CreateApp(svc)
  64  	require.NoError(t, err)
  65  
  66  	appPermission := &db.AppPermission{
  67  		AppId: app.ID,
  68  		Scope: constants.MAKE_INVOICE_SCOPE,
  69  	}
  70  	err = svc.DB.Create(appPermission).Error
  71  	require.NoError(t, err)
  72  
  73  	if paymentHashToCreate != "" && initialTransactionState != "" {
  74  		expiresAtVar := time.Now().Add(1 * time.Hour)
  75  		appIDForTx := app.ID
  76  		holdInvoice := &db.Transaction{
  77  			AppId:       &appIDForTx,
  78  			Type:        constants.TRANSACTION_TYPE_INCOMING,
  79  			State:       initialTransactionState,
  80  			PaymentHash: paymentHashToCreate,
  81  			AmountMsat:  1000,
  82  			ExpiresAt:   &expiresAtVar,
  83  		}
  84  		err = svc.DB.Create(holdInvoice).Error
  85  		require.NoError(t, err)
  86  	}
  87  
  88  	dbRequestEvent := &db.RequestEvent{
  89  		AppId: &app.ID,
  90  	}
  91  	err = svc.DB.Create(&dbRequestEvent).Error
  92  	require.NoError(t, err)
  93  
  94  	setup := &settleHoldInvoiceTestSetup{
  95  		ctx:            ctx,
  96  		svc:            svc,
  97  		nip47Request:   nip47Request,
  98  		app:            app,
  99  		dbRequestEvent: dbRequestEvent,
 100  	}
 101  	return setup
 102  }
 103  
 104  func (s *settleHoldInvoiceTestSetup) TearDown() {
 105  	s.svc.Remove()
 106  }
 107  
 108  func (s *settleHoldInvoiceTestSetup) PublishResponse(response *models.Response, tags nostr.Tags) {
 109  	s.publishCalled = true
 110  	s.response = response
 111  }
 112  
 113  func TestHandleSettleHoldInvoiceEvent(t *testing.T) {
 114  	preimageBytesForCheck, err := hex.DecodeString(testSettlePreimage)
 115  	require.NoError(t, err)
 116  	calculatedHashBytesForCheck := sha256.Sum256(preimageBytesForCheck)
 117  	calculatedPaymentHashForCheck := hex.EncodeToString(calculatedHashBytesForCheck[:])
 118  	assert.Equal(t, testSettlePaymentHash, calculatedPaymentHashForCheck)
 119  
 120  	setup := setupSettleHoldInvoiceTest(t, testSettlePreimage, testSettlePaymentHash, constants.TRANSACTION_STATE_ACCEPTED)
 121  	defer setup.TearDown()
 122  
 123  	controller := NewTestNip47Controller(setup.svc)
 124  
 125  	controller.HandleSettleHoldInvoiceEvent(setup.ctx, setup.nip47Request, setup.dbRequestEvent.ID, *setup.dbRequestEvent.AppId, setup.PublishResponse)
 126  
 127  	assert.True(t, setup.publishCalled)
 128  	assert.Nil(t, setup.response.Error)
 129  	assert.Equal(t, &settleHoldInvoiceResponse{}, setup.response.Result)
 130  
 131  	var settledTx db.Transaction
 132  	err = setup.svc.DB.First(&settledTx, "payment_hash = ?", testSettlePaymentHash).Error
 133  	assert.NoError(t, err)
 134  	assert.Equal(t, constants.TRANSACTION_STATE_SETTLED, settledTx.State)
 135  	assert.NotNil(t, settledTx.Preimage)
 136  	assert.Equal(t, testSettlePreimage, *settledTx.Preimage)
 137  }
 138  
 139  func TestHandleSettleHoldInvoiceEvent_InvalidPreimage(t *testing.T) {
 140  	invalidPreimage := "invalidpreimageinvalidpreimageinvalidpreimageinvalidpreimageinvalid"
 141  	setup := setupSettleHoldInvoiceTest(t, invalidPreimage, testSettlePaymentHash, constants.TRANSACTION_STATE_ACCEPTED)
 142  	defer setup.TearDown()
 143  
 144  	controller := NewTestNip47Controller(setup.svc)
 145  
 146  	controller.HandleSettleHoldInvoiceEvent(setup.ctx, setup.nip47Request, setup.dbRequestEvent.ID, *setup.dbRequestEvent.AppId, setup.PublishResponse)
 147  
 148  	assert.True(t, setup.publishCalled)
 149  	require.NotNil(t, setup.response.Error)
 150  	assert.Equal(t, constants.ERROR_INTERNAL, setup.response.Error.Code)
 151  }
 152