Move 9 development/testing .mjs scripts out of the package root into dev/ to keep the published package clean. Update relative imports and dev.sh reference. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
181 lines
5.9 KiB
JavaScript
181 lines
5.9 KiB
JavaScript
#!/usr/bin/env node
|
|
/**
|
|
* Test script to simulate a wallet sending an ndebit claim request
|
|
* This tests whether Lightning.Pub sends Kind 21002 responses after the fix
|
|
*/
|
|
|
|
import { Relay } from 'nostr-tools/relay'
|
|
import { nip44, finalizeEvent, generateSecretKey, getPublicKey } from 'nostr-tools'
|
|
import { decodeBech32 } from '@shocknet/clink-sdk'
|
|
|
|
const { getConversationKey, encrypt, decrypt } = nip44
|
|
|
|
const NDEBIT =
|
|
'ndebit1qgpkzardqyg8wue69uhhxarjvee8jw3hxumnwqpqf05wyqarxsdm9d62fh9lsa6wqc2r0a37cgd00mp3gnydpf5w9uusavytcn'
|
|
const RELAY_URL = 'ws://localhost:7777'
|
|
const AMOUNT_SATS = 5000 // Small test amount
|
|
|
|
// Generate a wallet keypair for this test
|
|
const WALLET_PRIVATE_KEY = generateSecretKey()
|
|
const WALLET_PUBLIC_KEY = getPublicKey(WALLET_PRIVATE_KEY)
|
|
|
|
async function main() {
|
|
console.log('🔧 Test: ndebit claim flow (NIP-44 v2)')
|
|
console.log('='.repeat(50))
|
|
|
|
// Decode ndebit to get Lightning.Pub pubkey and pointer
|
|
const decoded = decodeBech32(NDEBIT)
|
|
const LPUB_PUBKEY = decoded.data.pubkey
|
|
const POINTER = decoded.data.pointer
|
|
console.log(`\n📍 Lightning.Pub pubkey: ${LPUB_PUBKEY.slice(0, 16)}...`)
|
|
console.log(`🔑 Pointer (user ID): ${POINTER.slice(0, 16)}...`)
|
|
console.log(`👛 Test wallet pubkey: ${WALLET_PUBLIC_KEY.slice(0, 16)}...`)
|
|
console.log(`💰 Amount: ${AMOUNT_SATS} sats`)
|
|
|
|
// Connect to relay
|
|
console.log(`\n🔌 Connecting to relay: ${RELAY_URL}`)
|
|
const relay = await Relay.connect(RELAY_URL)
|
|
console.log('✅ Connected!')
|
|
|
|
// Build the debit request data (NdebitData format)
|
|
// Using newNdebitFullAccessRequest format with amount
|
|
const debitData = {
|
|
amount_sats: AMOUNT_SATS,
|
|
pointer: POINTER,
|
|
}
|
|
|
|
// Encrypt using NIP-44 v2
|
|
const conversationKey = getConversationKey(WALLET_PRIVATE_KEY, LPUB_PUBKEY)
|
|
const encryptedContent = encrypt(JSON.stringify(debitData), conversationKey)
|
|
|
|
// Build event with correct tags (including clink_version)
|
|
const event = finalizeEvent(
|
|
{
|
|
kind: 21002,
|
|
created_at: Math.floor(Date.now() / 1000),
|
|
tags: [
|
|
['p', LPUB_PUBKEY],
|
|
['clink_version', '1'],
|
|
],
|
|
content: encryptedContent,
|
|
},
|
|
WALLET_PRIVATE_KEY
|
|
)
|
|
|
|
console.log(`\n📤 Sending Kind 21002 debit request`)
|
|
console.log(` Event ID: ${event.id.slice(0, 16)}...`)
|
|
console.log(` Content length: ${encryptedContent.length} chars`)
|
|
|
|
// Subscribe for responses BEFORE sending the request
|
|
let responseReceived = false
|
|
const startTime = Date.now()
|
|
|
|
// Filter for Kind 21002 responses from Lightning.Pub that reference our event
|
|
const sub = relay.subscribe(
|
|
[
|
|
{
|
|
kinds: [21002],
|
|
authors: [LPUB_PUBKEY],
|
|
'#p': [WALLET_PUBLIC_KEY],
|
|
'#e': [event.id],
|
|
since: Math.floor(Date.now() / 1000) - 5,
|
|
},
|
|
],
|
|
{
|
|
onevent(evt) {
|
|
console.log(`\n📥 Received Kind 21002 response!`)
|
|
console.log(` Event ID: ${evt.id.slice(0, 16)}...`)
|
|
console.log(` Author: ${evt.pubkey.slice(0, 16)}...`)
|
|
|
|
// Check #e tag (should reference our original event)
|
|
const eTag = evt.tags.find((t) => t[0] === 'e')
|
|
if (eTag) {
|
|
console.log(` #e tag: ${eTag[1].slice(0, 16)}...`)
|
|
if (eTag[1] === event.id) {
|
|
console.log(' ✅ Correctly references our original event!')
|
|
}
|
|
} else {
|
|
console.log(' ⚠️ No #e tag found')
|
|
}
|
|
|
|
try {
|
|
const response = JSON.parse(decrypt(evt.content, conversationKey))
|
|
console.log(`\n📋 Response content:`)
|
|
console.log(JSON.stringify(response, null, 2))
|
|
|
|
if (response.res === 'OK') {
|
|
console.log('\n✅✅✅ SUCCESS! Lightning.Pub sent Kind 21002 response correctly!')
|
|
console.log(' The fix is working!')
|
|
} else if (response.res === 'GFY' || response.error) {
|
|
console.log(`\n⚠️ Response indicates error: ${response.error || 'unknown'}`)
|
|
console.log(' (Expected if payment denied or auth required)')
|
|
}
|
|
} catch (e) {
|
|
console.log(' ❌ Could not decrypt response:', e.message)
|
|
}
|
|
|
|
responseReceived = true
|
|
},
|
|
}
|
|
)
|
|
|
|
// Publish the debit request
|
|
await relay.publish(event)
|
|
console.log('✅ Request published!')
|
|
|
|
// Wait for response with timeout
|
|
console.log('\n⏳ Waiting for Kind 21002 response (30s timeout)...')
|
|
const timeout = 30000
|
|
const checkInterval = 1000
|
|
|
|
while (!responseReceived && Date.now() - startTime < timeout) {
|
|
await new Promise((r) => setTimeout(r, checkInterval))
|
|
const elapsed = Math.floor((Date.now() - startTime) / 1000)
|
|
process.stdout.write(`\r ${elapsed}s elapsed...`)
|
|
}
|
|
|
|
console.log('')
|
|
|
|
if (!responseReceived) {
|
|
console.log('\n❌❌❌ TIMEOUT! No Kind 21002 response received.')
|
|
console.log(' This means the fix did NOT work or there was another issue.')
|
|
|
|
// Let's check what Kind 21002 events exist
|
|
console.log('\n🔍 Checking for any Kind 21002 events on relay...')
|
|
let foundEvents = 0
|
|
const allDebitSub = relay.subscribe(
|
|
[
|
|
{
|
|
kinds: [21002],
|
|
limit: 10,
|
|
},
|
|
],
|
|
{
|
|
onevent(evt) {
|
|
foundEvents++
|
|
const pTags = evt.tags.filter((t) => t[0] === 'p').map((t) => t[1].slice(0, 8) + '...')
|
|
const eTags = evt.tags.filter((t) => t[0] === 'e').map((t) => t[1].slice(0, 8) + '...')
|
|
console.log(
|
|
` ${foundEvents}. id=${evt.id.slice(0, 12)}... by=${evt.pubkey.slice(0, 8)}... #p=${pTags.join(',')} #e=${eTags.join(',')}`
|
|
)
|
|
},
|
|
oneose() {
|
|
console.log(` (Found ${foundEvents} Kind 21002 events total)`)
|
|
},
|
|
}
|
|
)
|
|
|
|
await new Promise((r) => setTimeout(r, 3000))
|
|
allDebitSub.close()
|
|
}
|
|
|
|
sub.close()
|
|
relay.close()
|
|
console.log('\n🏁 Test complete')
|
|
process.exit(responseReceived ? 0 : 1)
|
|
}
|
|
|
|
main().catch((e) => {
|
|
console.error('Fatal error:', e)
|
|
process.exit(1)
|
|
})
|