diff --git a/test/bats/helpers/ln.bash b/test/bats/helpers/ln.bash index 38f97b8334..b25c690cb7 100644 --- a/test/bats/helpers/ln.bash +++ b/test/bats/helpers/ln.bash @@ -4,6 +4,8 @@ source $(dirname "$BASH_SOURCE")/_common.bash LND_FUNDING_TOKEN_NAME="lnd_funding" LND_FUNDING_PHONE="+16505554351" +LNDS_REST_LOG=".e2e-lnds-rest.log" + mempool_not_empty() { local txid="$(bitcoin_cli getrawmempool | jq -r ".[0]")" [[ "$txid" != "null" ]] || exit 1 @@ -179,6 +181,26 @@ lnd_outside_cli() { $@ } +lnd_outside_rest() { + local route=$1 + local endpoint="https://localhost:8080/$route" + + local data=$2 + + local macaroon_hex=$( + docker exec "${COMPOSE_PROJECT_NAME}-lnd-outside-1-1" \ + xxd -p -c 10000 /root/.lnd/admin.macaroon + ) + + docker exec "${COMPOSE_PROJECT_NAME}-lnd-outside-1-1" \ + curl -s \ + --cacert /root/.lnd/tls.cert \ + -H "Grpc-Metadata-macaroon: $macaroon_hex" \ + ${data:+ -X POST -d $data} \ + "$endpoint" \ + > "$LNDS_REST_LOG" +} + lnd_outside_2_cli() { docker exec "${COMPOSE_PROJECT_NAME}-lnd-outside-2-1" \ lncli \ diff --git a/test/bats/ln-receive.bats b/test/bats/ln-receive.bats index 80fd36f4c6..33ea027756 100644 --- a/test/bats/ln-receive.bats +++ b/test/bats/ln-receive.bats @@ -120,10 +120,10 @@ usd_amount=50 } @test "ln-receive: settle via ln for BTC wallet, amountless invoice" { - # Generate invoice token_name="$ALICE_TOKEN_NAME" btc_wallet_name="$token_name.btc_wallet_id" + # Generate invoice variables=$( jq -n \ --arg wallet_id "$(read_value $btc_wallet_name)" \ @@ -149,6 +149,51 @@ usd_amount=50 check_for_ln_update "$payment_hash" || exit 1 } +@test "ln-receive: handle less-than-1-sat ln payment for BTC wallet" { + token_name="$ALICE_TOKEN_NAME" + btc_wallet_name="$token_name.btc_wallet_id" + + # Generate amountless invoice + invoice_variables=$( + jq -n \ + --arg wallet_id "$(read_value $btc_wallet_name)" \ + '{input: {walletId: $wallet_id}}' + ) + exec_graphql "$token_name" 'ln-no-amount-invoice-create' "$invoice_variables" + invoice="$(graphql_output '.data.lnNoAmountInvoiceCreate.invoice')" + + payment_request="$(echo $invoice | jq -r '.paymentRequest')" + [[ "${payment_request}" != "null" ]] || exit 1 + payment_hash="$(echo $invoice | jq -r '.paymentHash')" + [[ "${payment_hash}" != "null" ]] || exit 1 + + # Check that invoice is retrievable from lnd1 + invoice_from_lnd=$(lnd_cli lookupinvoice "$payment_hash") + [[ -n $invoice_from_lnd ]] || exit 1 + + # Receive less-than-1-sat payment + pay_variables=$( + jq -n \ + --arg payment_request "$payment_request" \ + --arg amt_msat "995" \ + --arg timeout_seconds "5" \ + '{payment_request: $payment_request, amt_msat: $amt_msat, timeout_seconds: $timeout_seconds}'\ + | tr -d '[:space:]') + lnd_outside_rest "v2/router/send" "$pay_variables" + + # Check that payment fails + response=$(tail -n 1 "$LNDS_REST_LOG") + [[ -n $response ]] || exit 1 + pay_status=$(echo $response | jq -r '.result.status') + [[ "$pay_status" == "FAILED" ]] || exit 1 + failure_reason=$(echo $response | jq -r '.result.failure_reason') + [[ "$failure_reason" == "FAILURE_REASON_INCORRECT_PAYMENT_DETAILS" ]] || exit 1 + + # Check that invoice is removed from lnd1 + invoice_from_lnd=$(lnd_cli lookupinvoice "$payment_hash") || true + [[ -z $invoice_from_lnd ]] || exit 1 +} + @test "ln-receive: settle via ln for USD wallet, amountless invoice" { # Generate invoice token_name="$ALICE_TOKEN_NAME" diff --git a/test/legacy-integration/02-user-wallet/02-receive-lightning.spec.ts b/test/legacy-integration/02-user-wallet/02-receive-lightning.spec.ts index 695357c967..88a862779e 100644 --- a/test/legacy-integration/02-user-wallet/02-receive-lightning.spec.ts +++ b/test/legacy-integration/02-user-wallet/02-receive-lightning.spec.ts @@ -32,7 +32,6 @@ import { getDefaultWalletIdByPhone, getError, getHash, - getInvoice, getPubKey, getTransactionsForWalletId, getUsdWalletIdByPhone, @@ -281,57 +280,6 @@ describe("UserWallet - Lightning", () => { ]) }) - it("receives 'less than 1 sat amount' invoice", async () => { - const mtokens = "995" - const lnInvoice = await Wallets.addInvoiceNoAmountForSelf({ - walletId: walletIdB as WalletId, - }) - if (lnInvoice instanceof Error) throw lnInvoice - const { paymentRequest: invoice, paymentHash: hash } = lnInvoice - - safePayNoExpect({ lnd: lndOutside1, request: invoice, mtokens }) - // TODO: we could use an event instead of a sleep - await sleep(500) - - expect( - await Wallets.updatePendingInvoiceByPaymentHash({ - paymentHash: hash, - logger: baseLogger, - }), - ).not.toBeInstanceOf(Error) - // should be idempotent (not return error when called again) - expect( - await Wallets.updatePendingInvoiceByPaymentHash({ - paymentHash: hash, - logger: baseLogger, - }), - ).not.toBeInstanceOf(Error) - - // Check that no new txns are added - const ledgerTxs = await LedgerService().getTransactionsByHash(hash) - if (ledgerTxs instanceof Error) throw ledgerTxs - expect(ledgerTxs).toHaveLength(0) - - // Check that wallet invoice is deleted (was declined) - const walletInvoice = await WalletInvoicesRepository().findByPaymentHash(hash) - expect(walletInvoice).toBeInstanceOf(CouldNotFindWalletInvoiceError) - - // Check that invoice is deleted in lnd - let getInvoiceErr - try { - await getInvoice({ lnd: lnd1, id: hash }) - } catch (err) { - getInvoiceErr = err - } - expect(parseLndErrorDetails(getInvoiceErr)).toMatch( - KnownLndErrorDetails.InvoiceNotFound, - ) - - // Check that wallet balance is unchanged - const finalBalance = await getBalanceHelper(walletIdB) - expect(finalBalance).toBe(initBalanceB) - }) - it("receives spam invoice", async () => { // amount below MEMO_SPAM threshold const sats = 100