diff --git a/lamassu-next/devenv.nix b/lamassu-next/devenv.nix index a85c67c..49c8eb2 100644 --- a/lamassu-next/devenv.nix +++ b/lamassu-next/devenv.nix @@ -278,6 +278,228 @@ echo "Paying invoice from Alice's node..." docker exec lamassu-lnd-alice lncli --network=regtest payinvoice --force "$1" ''; + + # Create invoice on Alice's node (for testing ATM payouts) + alice-invoice.exec = '' + AMOUNT=''${1:-1000} + MEMO=''${2:-"Test invoice"} + docker exec lamassu-lnd-alice lncli --network=regtest addinvoice --amt="$AMOUNT" --memo="$MEMO" | jq -r '.payment_request' + ''; + + # Fund ATM account in Lightning.Pub + fund-atm.exec = '' + AMOUNT=''${1:-100000} + echo "Funding ATM account with $AMOUNT sats..." + echo "" + + # Run the funding script from nostr-client package + cd packages/nostr-client + FUND_AMOUNT=$AMOUNT node fund-dev.mjs 2>&1 | tee /tmp/fund-atm-output.txt + + # Extract the invoice + INVOICE=$(grep -o 'lnbcrt[a-zA-Z0-9]*' /tmp/fund-atm-output.txt | head -1) + + if [ -z "$INVOICE" ]; then + echo "Failed to create invoice. Check the output above." + exit 1 + fi + + echo "" + echo "Invoice created. Paying from Alice..." + docker exec lamassu-lnd-alice lncli --network=regtest payinvoice --force "$INVOICE" + + echo "" + echo "ATM account funded with $AMOUNT sats!" + ''; + + # Validate entire test setup + test-setup.exec = '' + echo "" + echo "═══════════════════════════════════════════════════════════" + echo " Lamassu Next - Test Setup Validation" + echo "═══════════════════════════════════════════════════════════" + echo "" + + PASSED=0 + FAILED=0 + + check() { + if [ $1 -eq 0 ]; then + echo " ✓ $2" + PASSED=$((PASSED + 1)) + else + echo " ✗ $2" + FAILED=$((FAILED + 1)) + fi + } + + echo "1. Services" + echo "───────────────────────────────────────────────────────────" + + # Check containers + docker ps --format '{{.Names}}' | grep -q lamassu-relay + check $? "strfry relay running" + + docker ps --format '{{.Names}}' | grep -q lamassu-bitcoind + check $? "bitcoind running" + + docker ps --format '{{.Names}}' | grep -q lamassu-lnd + check $? "LND running" + + docker ps --format '{{.Names}}' | grep -q lamassu-lnd-alice + check $? "LND Alice running" + + docker ps --format '{{.Names}}' | grep -q lamassu-lightning-pub + check $? "Lightning.Pub running" + + echo "" + echo "2. Connectivity" + echo "───────────────────────────────────────────────────────────" + + # Check relay port is open + timeout 2 bash -c 'echo > /dev/tcp/localhost/7777' 2>/dev/null + check $? "Nostr relay port open" + + # Check bitcoind RPC + docker exec lamassu-bitcoind bitcoin-cli -regtest -rpcuser=lamassu -rpcpassword=lamassu getblockchaininfo >/dev/null 2>&1 + check $? "Bitcoin RPC responding" + + # Check LND + docker exec lamassu-lnd lncli --network=regtest getinfo >/dev/null 2>&1 + check $? "LND RPC responding" + + # Check Alice + docker exec lamassu-lnd-alice lncli --network=regtest getinfo >/dev/null 2>&1 + check $? "LND Alice RPC responding" + + echo "" + echo "3. Blockchain State" + echo "───────────────────────────────────────────────────────────" + + BLOCKS=$(docker exec lamassu-bitcoind bitcoin-cli -regtest -rpcuser=lamassu -rpcpassword=lamassu getblockcount 2>/dev/null) + [ "$BLOCKS" -ge 100 ] + check $? "Block height >= 100 (current: $BLOCKS)" + + # Check LND synced + LND_SYNCED=$(docker exec lamassu-lnd lncli --network=regtest getinfo 2>/dev/null | jq -r '.synced_to_chain') + [ "$LND_SYNCED" = "true" ] + check $? "LND synced to chain" + + # Check Alice synced + ALICE_SYNCED=$(docker exec lamassu-lnd-alice lncli --network=regtest getinfo 2>/dev/null | jq -r '.synced_to_chain') + [ "$ALICE_SYNCED" = "true" ] + check $? "LND Alice synced to chain" + + echo "" + echo "4. Lightning Channels" + echo "───────────────────────────────────────────────────────────" + + # Check Alice has active channels + ALICE_CHANNELS=$(docker exec lamassu-lnd-alice lncli --network=regtest listchannels 2>/dev/null | jq '.channels | length') + [ "$ALICE_CHANNELS" -ge 1 ] + check $? "Alice has active channels (count: $ALICE_CHANNELS)" + + # Check channel is active + ACTIVE_CHANNEL=$(docker exec lamassu-lnd-alice lncli --network=regtest listchannels 2>/dev/null | jq '.channels[0].active') + [ "$ACTIVE_CHANNEL" = "true" ] + check $? "Channel is active" + + # Check Alice has outbound capacity + ALICE_LOCAL=$(docker exec lamassu-lnd-alice lncli --network=regtest listchannels 2>/dev/null | jq -r '.channels[0].local_balance // 0') + [ "$ALICE_LOCAL" -ge 10000 ] + check $? "Alice has outbound capacity ($ALICE_LOCAL sats)" + + echo "" + echo "5. Payment Test" + echo "───────────────────────────────────────────────────────────" + + # Create test invoice on LND and pay from Alice + TEST_INVOICE=$(docker exec lamassu-lnd lncli --network=regtest addinvoice --amt=100 --memo="test-setup validation" 2>/dev/null | jq -r '.payment_request') + if [ -n "$TEST_INVOICE" ]; then + check 0 "Created 100 sat test invoice" + + # Pay it + PAY_RESULT=$(docker exec lamassu-lnd-alice lncli --network=regtest payinvoice --force "$TEST_INVOICE" 2>&1) + if echo "$PAY_RESULT" | grep -q "SUCCEEDED"; then + check 0 "Payment Alice → LND succeeded" + else + check 1 "Payment Alice → LND failed" + fi + else + check 1 "Failed to create test invoice" + check 1 "Payment test skipped" + fi + + echo "" + echo "═══════════════════════════════════════════════════════════" + echo " Results: $PASSED passed, $FAILED failed" + echo "═══════════════════════════════════════════════════════════" + echo "" + + if [ $FAILED -gt 0 ]; then + echo "Some checks failed. Run 'infra-up' and 'setup-channel' first." + exit 1 + else + echo "All checks passed! Ready for testing." + exit 0 + fi + ''; + + # Quick e2e payment test (ATM pays customer invoice) + test-payment.exec = '' + AMOUNT=''${1:-1000} + echo "Testing e2e payment flow ($AMOUNT sats)..." + echo "" + + # Create invoice on Alice (simulating customer's wallet) + echo "1. Creating invoice on Alice's wallet..." + INVOICE=$(docker exec lamassu-lnd-alice lncli --network=regtest addinvoice --amt="$AMOUNT" --memo="E2E test" | jq -r '.payment_request') + echo " Invoice: ''${INVOICE:0:40}..." + + # Use test-pay.mjs to pay via Lightning.Pub + echo "" + echo "2. Paying via Lightning.Pub (ATM flow)..." + cd packages/nostr-client + node test-pay.mjs "$INVOICE" + + echo "" + echo "3. Verifying payment on Alice..." + sleep 2 + PAID=$(docker exec lamassu-lnd-alice lncli --network=regtest listinvoices 2>/dev/null | jq '.invoices[-1].settled') + if [ "$PAID" = "true" ]; then + echo " ✓ Payment received!" + else + echo " ✗ Payment not received" + exit 1 + fi + ''; + + # Show node info + node-info.exec = '' + echo "" + echo "Node Information" + echo "════════════════════════════════════════════════════════" + echo "" + + echo "LND (Lightning.Pub's node):" + docker exec lamassu-lnd lncli --network=regtest getinfo 2>/dev/null | jq '{pubkey: .identity_pubkey, alias: .alias, channels: .num_active_channels, peers: .num_peers}' + + echo "" + echo "LND Alice (Payment source):" + docker exec lamassu-lnd-alice lncli --network=regtest getinfo 2>/dev/null | jq '{pubkey: .identity_pubkey, alias: .alias, channels: .num_active_channels, peers: .num_peers}' + + echo "" + echo "Channel Details:" + docker exec lamassu-lnd-alice lncli --network=regtest listchannels 2>/dev/null | jq '.channels[] | {peer: .remote_pubkey[0:16], capacity, local: .local_balance, remote: .remote_balance, active}' + + echo "" + echo "Lightning.Pub Nostr pubkey:" + echo " f454c5eec4ec4474128e19b57b45e49c3d0851d01eea960b39ce391cdba76fc6" + + echo "" + echo "ATM Dev Identity:" + echo " 4646ae5047316b4230d0086c8acec687f00b1cd9d1dc634f6cb358ac0a9a8fff" + ''; }; # ============================================ @@ -312,5 +534,12 @@ echo " alice-pay Pay invoice from Alice's node" echo " relay-test Test Nostr relay connection" echo "" + echo " Testing (E2E):" + echo " test-setup Validate test environment (services, channels, payments)" + echo " test-payment Quick e2e payment test (ATM → customer)" + echo " fund-atm Fund ATM account (default: 100k sats)" + echo " alice-invoice Create invoice on Alice's node" + echo " node-info Show node pubkeys and channel info" + echo "" ''; } diff --git a/lamassu-next/packages/nostr-client/fund-dev.mjs b/lamassu-next/packages/nostr-client/fund-dev.mjs index f464770..4d397de 100644 --- a/lamassu-next/packages/nostr-client/fund-dev.mjs +++ b/lamassu-next/packages/nostr-client/fund-dev.mjs @@ -4,7 +4,8 @@ import { randomUUID } from 'crypto' const DEV_PRIVATE_KEY = '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef' const LIGHTNING_PUB_PUBKEY = 'f454c5eec4ec4474128e19b57b45e49c3d0851d01eea960b39ce391cdba76fc6' -const RELAY_URL = 'ws://192.168.1.122:7777' +const RELAY_URL = process.env.NOSTR_RELAY_URL || 'ws://localhost:7777' +const FUND_AMOUNT = parseInt(process.env.FUND_AMOUNT || '100000', 10) async function main() { const identity = loadIdentityFromHex(DEV_PRIVATE_KEY) @@ -26,13 +27,15 @@ async function main() { params: {}, query: {}, body: { - amountSats: 100000, - memo: 'Fund dev account', + amountSats: FUND_AMOUNT, + memo: `Fund dev account (${FUND_AMOUNT} sats)`, }, authIdentifier: identity.publicKey, requestId, } + console.log('Creating invoice for', FUND_AMOUNT, 'sats') + console.log('Request structure:', JSON.stringify(rpcRequest, null, 2)) const encryptedContent = encryptContent(identity, LIGHTNING_PUB_PUBKEY, rpcRequest) diff --git a/lamassu-next/packages/nostr-client/test-pay.mjs b/lamassu-next/packages/nostr-client/test-pay.mjs index 257cfc4..fa2f53c 100644 --- a/lamassu-next/packages/nostr-client/test-pay.mjs +++ b/lamassu-next/packages/nostr-client/test-pay.mjs @@ -5,7 +5,7 @@ import { randomUUID } from 'crypto' const DEV_PRIVATE_KEY = '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef' const LIGHTNING_PUB_PUBKEY = 'f454c5eec4ec4474128e19b57b45e49c3d0851d01eea960b39ce391cdba76fc6' -const RELAY_URL = 'ws://192.168.1.122:7777' +const RELAY_URL = process.env.NOSTR_RELAY_URL || 'ws://localhost:7777' // Get a fresh invoice from Alice first: // docker exec lamassu-lnd-alice lncli --network=regtest addinvoice --amt 1000