ldk_test.go raw

   1  package ldk
   2  
   3  import (
   4  	"testing"
   5  
   6  	"github.com/getAlby/ldk-node-go/ldk_node"
   7  	"github.com/stretchr/testify/assert"
   8  	"github.com/stretchr/testify/require"
   9  
  10  	"github.com/getAlby/hub/tests"
  11  )
  12  
  13  func TestGetVssNodeIdentifier(t *testing.T) {
  14  	mnemonic := "thought turkey ask pottery head say catalog desk pledge elbow naive mimic"
  15  	expectedVssNodeIdentifier := "751636"
  16  
  17  	svc, err := tests.CreateTestServiceWithMnemonic(t, mnemonic, "123")
  18  	require.NoError(t, err)
  19  	defer svc.Remove()
  20  
  21  	vssNodeIdentifier, err := GetVssNodeIdentifier(svc.Keys)
  22  	require.NoError(t, err)
  23  
  24  	assert.Equal(t, expectedVssNodeIdentifier, vssNodeIdentifier)
  25  }
  26  func TestGetVssNodeIdentifier2(t *testing.T) {
  27  	mnemonic := "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"
  28  	expectedVssNodeIdentifier := "770256"
  29  
  30  	svc, err := tests.CreateTestServiceWithMnemonic(t, mnemonic, "123")
  31  	require.NoError(t, err)
  32  	defer svc.Remove()
  33  
  34  	vssNodeIdentifier, err := GetVssNodeIdentifier(svc.Keys)
  35  	require.NoError(t, err)
  36  
  37  	assert.Equal(t, expectedVssNodeIdentifier, vssNodeIdentifier)
  38  }
  39  
  40  func makeLsps2OpeningFeeParams(minFeeMsat uint64, proportional uint32, minPaymentSizeMsat uint64, maxPaymentSizeMsat uint64) ldk_node.Lsps2OpeningFeeParams {
  41  	return ldk_node.Lsps2OpeningFeeParams{
  42  		MinFeeMsat:           minFeeMsat,
  43  		Proportional:         proportional,
  44  		ValidUntil:           "2035-01-01T00:00:00Z",
  45  		MinLifetime:          4032,
  46  		MaxClientToSelfDelay: 2016,
  47  		MinPaymentSizeMsat:   minPaymentSizeMsat,
  48  		MaxPaymentSizeMsat:   maxPaymentSizeMsat,
  49  		Promise:              "promise",
  50  	}
  51  }
  52  
  53  func TestComputeLsps2MaxTotalOpeningFeeMsat(t *testing.T) {
  54  	t.Run("proportional fee above minimum fee", func(t *testing.T) {
  55  		menu := []ldk_node.Lsps2OpeningFeeParams{
  56  			// 0.5% of 10M msat = 50k msat > 10k msat minimum
  57  			makeLsps2OpeningFeeParams(10_000, 5_000, 1_000_000, 100_000_000),
  58  		}
  59  		assert.Equal(t, uint64(50_000), computeLsps2MaxTotalOpeningFeeMsat(10_000_000, menu))
  60  	})
  61  
  62  	t.Run("minimum fee above proportional fee", func(t *testing.T) {
  63  		menu := []ldk_node.Lsps2OpeningFeeParams{
  64  			// 0.5% of 1M msat = 5k msat < 10k msat minimum
  65  			makeLsps2OpeningFeeParams(10_000, 5_000, 1_000_000, 100_000_000),
  66  		}
  67  		assert.Equal(t, uint64(10_000), computeLsps2MaxTotalOpeningFeeMsat(1_000_000, menu))
  68  	})
  69  
  70  	t.Run("highest fee across menu entries", func(t *testing.T) {
  71  		menu := []ldk_node.Lsps2OpeningFeeParams{
  72  			makeLsps2OpeningFeeParams(10_000, 5_000, 1_000_000, 100_000_000),
  73  			makeLsps2OpeningFeeParams(10_000, 20_000, 1_000_000, 100_000_000),
  74  		}
  75  		assert.Equal(t, uint64(200_000), computeLsps2MaxTotalOpeningFeeMsat(10_000_000, menu))
  76  	})
  77  
  78  	t.Run("entries not covering the payment size are skipped", func(t *testing.T) {
  79  		menu := []ldk_node.Lsps2OpeningFeeParams{
  80  			makeLsps2OpeningFeeParams(10_000, 5_000, 1_000_000, 100_000_000),
  81  			// covers larger payments only, would otherwise win with 2%
  82  			makeLsps2OpeningFeeParams(10_000, 20_000, 20_000_000, 100_000_000),
  83  		}
  84  		assert.Equal(t, uint64(50_000), computeLsps2MaxTotalOpeningFeeMsat(10_000_000, menu))
  85  	})
  86  
  87  	t.Run("menu fee above ceiling is clamped to ceiling", func(t *testing.T) {
  88  		menu := []ldk_node.Lsps2OpeningFeeParams{
  89  			// 20% of 100M msat = 20M msat, above the 10% / 10M msat ceiling
  90  			makeLsps2OpeningFeeParams(5_000_000, 200_000, 1_000_000, 1_000_000_000),
  91  		}
  92  		assert.Equal(t, uint64(10_000_000), computeLsps2MaxTotalOpeningFeeMsat(100_000_000, menu))
  93  	})
  94  
  95  	t.Run("base ceiling applies when no entry covers the payment size", func(t *testing.T) {
  96  		menu := []ldk_node.Lsps2OpeningFeeParams{
  97  			makeLsps2OpeningFeeParams(10_000, 5_000, 1_000_000, 100_000_000),
  98  		}
  99  		// 10% of 200M msat = 20M msat
 100  		assert.Equal(t, uint64(20_000_000), computeLsps2MaxTotalOpeningFeeMsat(200_000_000, menu))
 101  	})
 102  
 103  	t.Run("base ceiling applies on empty menu", func(t *testing.T) {
 104  		assert.Equal(t, uint64(5_000_000), computeLsps2MaxTotalOpeningFeeMsat(10_000_000, nil))
 105  	})
 106  }
 107  
 108  func TestComputeLsps2MinPaymentSizeMsat(t *testing.T) {
 109  	t.Run("minimum fee below ceiling base", func(t *testing.T) {
 110  		// 1000 sat minimum fee: smallest usable payment nets 1 sat above the fee
 111  		params := makeLsps2OpeningFeeParams(1_000_000, 10_000, 1_000, 100_000_000_000)
 112  		minPaymentSizeMsat, ok := computeLsps2MinPaymentSizeMsat(params)
 113  		require.True(t, ok)
 114  		assert.Equal(t, uint64(1_001_000), minPaymentSizeMsat)
 115  	})
 116  
 117  	t.Run("minimum fee above ceiling base", func(t *testing.T) {
 118  		// 8000 sat minimum fee exceeds the 5000 sat ceiling base, so the
 119  		// smallest payment is where the fee equals 10% of the payment
 120  		params := makeLsps2OpeningFeeParams(8_000_000, 10_000, 1_000, 100_000_000_000)
 121  		minPaymentSizeMsat, ok := computeLsps2MinPaymentSizeMsat(params)
 122  		require.True(t, ok)
 123  		assert.Equal(t, uint64(80_000_000), minPaymentSizeMsat)
 124  	})
 125  
 126  	t.Run("proportional fee above ceiling percentage never fits", func(t *testing.T) {
 127  		// 30% proportional fee with a minimum fee above the ceiling base can
 128  		// never satisfy the 10% ceiling
 129  		params := makeLsps2OpeningFeeParams(6_000_000, 300_000, 1_000, 1_000_000_000)
 130  		_, ok := computeLsps2MinPaymentSizeMsat(params)
 131  		assert.False(t, ok)
 132  	})
 133  }
 134  
 135  func TestSanitizeChainEndpointForBitcoind(t *testing.T) {
 136  	tests := []struct {
 137  		name     string
 138  		endpoint string
 139  		rpcPort  string
 140  		expected string
 141  	}{
 142  		{
 143  			name:     "adds configured port to host",
 144  			endpoint: "127.0.0.1",
 145  			rpcPort:  "8332",
 146  			expected: "127.0.0.1:8332",
 147  		},
 148  		{
 149  			name:     "preserves endpoint port",
 150  			endpoint: "127.0.0.1:18443",
 151  			rpcPort:  "8332",
 152  			expected: "127.0.0.1:18443",
 153  		},
 154  		{
 155  			name:     "formats ipv6 host",
 156  			endpoint: "[2001:db8::1]",
 157  			rpcPort:  "8332",
 158  			expected: "[2001:db8::1]:8332",
 159  		},
 160  		{
 161  			name:     "strips credentials from url-shaped input",
 162  			endpoint: "user:pass@[2001:db8::1]:18443",
 163  			rpcPort:  "8332",
 164  			expected: "[2001:db8::1]:18443",
 165  		},
 166  	}
 167  
 168  	for _, tt := range tests {
 169  		t.Run(tt.name, func(t *testing.T) {
 170  			assert.Equal(t, tt.expected, sanitizeChainEndpoint(tt.endpoint, tt.rpcPort))
 171  		})
 172  	}
 173  }
 174  
 175  func TestSanitizeChainEndpointForURLs(t *testing.T) {
 176  	tests := []struct {
 177  		name     string
 178  		endpoint string
 179  		expected string
 180  	}{
 181  		{
 182  			name:     "keeps bare electrum endpoint unchanged",
 183  			endpoint: "electrum.example.com:50002",
 184  			expected: "electrum.example.com:50002",
 185  		},
 186  		{
 187  			name:     "strips url credentials",
 188  			endpoint: "ssl://user:pass@electrum.example.com:50002",
 189  			expected: "ssl://electrum.example.com:50002",
 190  		},
 191  		{
 192  			name:     "strips esplora credentials",
 193  			endpoint: "https://user:pass@esplora.example.com/api",
 194  			expected: "https://esplora.example.com/api",
 195  		},
 196  	}
 197  
 198  	for _, tt := range tests {
 199  		t.Run(tt.name, func(t *testing.T) {
 200  			assert.Equal(t, tt.expected, sanitizeChainEndpoint(tt.endpoint, ""))
 201  		})
 202  	}
 203  }
 204