This commit is contained in:
Stephen Vanderwarker 2024-12-24 17:45:28 -05:00
commit dc0a952140
3 changed files with 290 additions and 0 deletions

132
.gitignore vendored Normal file

@ -0,0 +1,132 @@
# ---> Node
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
.pnpm-debug.log*
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# Snowpack dependency directory (https://snowpack.dev/)
web_modules/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional stylelint cache
.stylelintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variable files
.env
.env.development.local
.env.test.local
.env.production.local
.env.local
# parcel-bundler cache (https://parceljs.org/)
.cache
.parcel-cache
# Next.js build output
.next
out
# Nuxt.js build / generate output
.nuxt
dist
# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and not Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public
# vuepress build output
.vuepress/dist
# vuepress v2.x temp and cache directory
.temp
.cache
# Docusaurus cache and generated files
.docusaurus
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# TernJS port file
.tern-port
# Stores VSCode versions used for testing VSCode extensions
.vscode-test
# yarn v2
.yarn/cache
.yarn/unplugged
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*

16
README.md Normal file

@ -0,0 +1,16 @@
# tickstr
A ChatGPT pipe dreamed script for:
https://github.com/nostr-protocol/nips/pull/1658
1. <code>git clone https://git.vanderwarker.family/nostr/tickstr</code>
2. <code>cd tickstr</code>
3. <code>npm i</code>
4. <code>edit settings.json</code>
5. <code>nodejs main.js</code>
6. <code>????</code>
7. <code>PROFIT!</code>
8. <code>Remember, that one sat is one sat so it doesn't matter</code>
9. <code>cd ..</code>
10. <code>rm tickstr</code>

142
main.js Normal file

@ -0,0 +1,142 @@
const WebSocket = require('ws');
const crypto = require('crypto');
const elliptic = require('elliptic');
const Buffer = require('safe-buffer').Buffer
const schnorr = require('bip-schnorr');
// Use elliptic for ECDSA signing
const EC = elliptic.ec;
const ecdsa = new EC('secp256k1');
// Your Nostr private key (replace with your own)
const privateKeyHex = ''; // 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'],['n','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 = ''; // 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');
});
}