LFG
This commit is contained in:
commit
dc0a952140
132
.gitignore
vendored
Normal file
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
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
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');
|
||||
});
|
||||
}
|
Reference in New Issue
Block a user