143 lines
4.5 KiB
JavaScript
143 lines
4.5 KiB
JavaScript
const WebSocket = require('ws');
|
|
const crypto = require('crypto');
|
|
const elliptic = require('elliptic');
|
|
const Buffer = require('safe-buffer').Buffer
|
|
const schnorr = require('bip-schnorr');
|
|
const settings = require('./settings.json');
|
|
// Use elliptic for ECDSA signing
|
|
const EC = elliptic.ec;
|
|
const ecdsa = new EC('secp256k1');
|
|
|
|
// Your Nostr private key (replace with your own)
|
|
const privateKeyHex = settings.secretKey; // Use your actual private key here
|
|
|
|
// Ensure private key is a valid 32-byte hex string
|
|
if (!/^([0-9a-fA-F]{64})$/.test(privateKeyHex)) {
|
|
console.error('Invalid private key format. Ensure it is 64 hexadecimal characters.');
|
|
process.exit(1);
|
|
}
|
|
|
|
const publicKeyHex = generatePublicKey(privateKeyHex);
|
|
|
|
// Connect to Binance WebSocket
|
|
const ws = new WebSocket('wss://stream.binance.com:9443/ws/btcusdt@ticker');
|
|
|
|
// Handle WebSocket connection and data
|
|
ws.on('open', function open() {
|
|
console.log('Connected to Binance WebSocket');
|
|
});
|
|
|
|
ws.on('message', function incoming(message) {
|
|
const data = JSON.parse(message);
|
|
|
|
// Extract relevant data
|
|
const symbol = data.s;
|
|
const lastPrice = parseFloat(data.c);
|
|
const weightedAvgPrice = parseFloat(data.w);
|
|
const highPrice = parseFloat(data.h);
|
|
const lowPrice = parseFloat(data.l);
|
|
|
|
// Create Nostr event
|
|
const timestamp = Math.floor(Date.now() / 1000);
|
|
const eventContent = JSON.stringify({
|
|
symbol,
|
|
last_price: lastPrice,
|
|
weighted_avg_price: weightedAvgPrice,
|
|
high_price: highPrice,
|
|
low_price: lowPrice
|
|
});
|
|
|
|
const event = {
|
|
id: '',
|
|
pubkey: publicKeyHex, // 32-byte public key
|
|
created_at: timestamp,
|
|
kind: 31892, // Note (you can change this based on your event type)
|
|
tags: [['d','BTCUSD'],['n', 'BTC','USD'],['value', 'lastPrice']], // Optional tag (you can customize this)
|
|
content: eventContent,
|
|
sig: '' // Initialize sig here, it will be added after content
|
|
};
|
|
|
|
// Compute event ID (sha256 of serialized event)
|
|
const serializedEvent = serializeEvent(publicKeyHex, timestamp, event.kind, event.tags, eventContent);
|
|
const eventId = crypto.createHash('sha256').update(serializedEvent).digest('hex');
|
|
event.id = eventId;
|
|
|
|
// Sign the event using elliptic library
|
|
event.sig = signEvent(privateKeyHex, serializedEvent, event.id);
|
|
|
|
// Print the Nostr event with signature under content
|
|
console.log('Nostr Event:', JSON.stringify(event, null, 2));
|
|
|
|
// Optionally, broadcast the event to a Nostr relay (example)
|
|
sendToRelay(event);
|
|
});
|
|
|
|
// Function to generate compressed public key from private key using elliptic
|
|
function generatePublicKey(privateKeyHex) {
|
|
const privateKey = Buffer.from(privateKeyHex, 'hex');
|
|
|
|
if (privateKey.length !== 32) {
|
|
console.error('Private key must be 32 bytes.');
|
|
process.exit(1);
|
|
}
|
|
|
|
const key = ecdsa.keyFromPrivate(privateKey);
|
|
const publicKey = key.getPublic(true, 'hex'); // Compressed format
|
|
|
|
return publicKey.slice(2); // Remove the '0x' prefix to get 32 bytes
|
|
}
|
|
|
|
// Function to serialize the event according to NIP-01
|
|
function serializeEvent(pubkey, createdAt, kind, tags, content) {
|
|
const eventData = [
|
|
0, // Prefix for NIP-01 event serialization
|
|
pubkey,
|
|
createdAt,
|
|
kind,
|
|
tags,
|
|
content
|
|
];
|
|
|
|
// Serialize the event to JSON string
|
|
let eventJson = JSON.stringify(eventData, (key, value) => {
|
|
// Escape content field (you can also add custom escaping here if necessary)
|
|
if (key === 'content') {
|
|
value = value.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
|
|
}
|
|
return value;
|
|
});
|
|
|
|
return eventJson;
|
|
}
|
|
|
|
// Function to sign the event with the private key using elliptic
|
|
function signEvent(privateKeyHex, serializedEvent, eventID) {
|
|
const message = Buffer.from(eventID, 'hex');
|
|
const signature = schnorr.sign(privateKeyHex, message);
|
|
return signature.toString('hex');
|
|
}
|
|
|
|
// Function to send the event to a Nostr relay
|
|
function sendToRelay(event) {
|
|
// Example relay URL (replace with the actual Nostr relay URL)
|
|
const relayUrl = settings.relayUri; // Replace with your relay URL
|
|
|
|
// Create a WebSocket connection to the relay
|
|
const relayWs = new WebSocket(relayUrl);
|
|
|
|
relayWs.on('open', () => {
|
|
// Once the connection is open, send the event
|
|
const eventMessage = ['EVENT', event]; // Relay expects an array with 'EVENT' and event data
|
|
relayWs.send(JSON.stringify(eventMessage));
|
|
console.log('Event sent to relay:', JSON.stringify(event, null, 2));
|
|
});
|
|
|
|
relayWs.on('error', (err) => {
|
|
console.error('Error sending event to relay:', err);
|
|
});
|
|
|
|
relayWs.on('close', () => {
|
|
console.log('Connection to relay closed');
|
|
});
|
|
}
|