मुख्य सामग्री पर जाएं

एक रीयल-टाइम हाइपरलिक्विड व्हेल अलर्ट बॉट बनाएं

को अपडेट
22 अप्रैल, 2026

पढ़ने में 24 मिनट लगेंगे


एक धारा, एक लागत, अनेक गंतव्य

अब आपका Quicknode स्ट्रीम एक ही पाइपलाइन से एक साथ कई गंतव्यों तक डेटा पहुंचा सकता है। डुप्लिकेट स्ट्रीम नहीं, कॉन्फ़िगरेशन में कोई बदलाव नहीं, और प्रत्येक गंतव्य के लिए कोई अतिरिक्त शुल्क नहीं। प्रति स्ट्रीम उपलब्ध गंतव्य प्लान के अनुसार भिन्न होते हैं। अधिक जानें

अवलोकन

ऑनलाइन टोकन की बड़ी गतिविधियों की निगरानी करना, जिसे अक्सर "व्हेल" गतिविधि कहा जाता है, बाजार की भावना और संभावित मूल्य कार्रवाई के बारे में मूल्यवान जानकारी प्रदान कर सकता है।

यह गाइड आपको हाइपरलिक्विड ब्लॉकचेन पर HYPE टोकन के लिए एक रीयल-टाइम व्हेल अलर्ट बॉट बनाने में मदद करेगी। आप एक ऐसा सिस्टम बनाएंगे जो न केवल बड़े ट्रांसफर का पता लगाएगा, बल्कि हाइपरकोर से लाइव USD कीमतों के साथ डेटा को और बेहतर बनाएगा और टेलीग्राम चैनल पर तुरंत नोटिफिकेशन भेजेगा। इसे हासिल करने के लिए, हम क्विकनोड स्ट्रीम्स की शक्ति और दक्षता का उपयोग करेंगे।

आप क्या करेंगे


  • एक बनाने के क्विकनोड स्ट्रीम जो प्रचार को फ़िल्टर करता है स्थानांतरण हाइपरलिक्विड ईवीएम से संबंधित घटनाएँ
  • प्रोसेसिंग से पहले HMAC हस्ताक्षर के साथ पेलोड की प्रामाणिकता सत्यापित करें।
  • हाइपरईवीएम प्रीकंपाइल्स के माध्यम से हाइपरकोर से HYPE स्पॉट मूल्य पढ़ें
  • मछली, डॉल्फ़िन और व्हेल से संबंधित विभिन्न स्तरों की जानकारी टेलीग्राम चैनल पर भेजें।

आपको क्या चाहिए होगा


  • एक क्विकनोड खाता जिसमें हाइपरलिक्विड ईवीएम एंडपॉइंट हो।
  • Node.js 20+, npm (या कोई अन्य पैकेज मैनेजर), और VS Code जैसा कोड एडिटर
  • एक टेलीग्राम खाता (यदि आप टेलीग्राम बॉट बनाना चाहते हैं)
  • जावास्क्रिप्ट का बुनियादी ज्ञान
  • अपने स्थानीय सर्वर को इंटरनेट पर उपलब्ध कराने के लिए एक टूल, जैसे कि ngrok या localtunnel (यदि आपको स्थानीय रूप से वेबहुक का परीक्षण करने की आवश्यकता है)।
Quicknode Streams क्यों?

क्विकनोड स्ट्रीम्स "पुश" मॉडल पर काम करती हैं। बार-बार ब्लॉकचेन से नया डेटा मांगने (पोलिंग) के बजाय, स्ट्रीम्स आपके लिए ब्लॉकचेन की निगरानी करती हैं और कोई घटना घटित होते ही संबंधित डेटा को आपके एप्लिकेशन तक पहुंचा देती हैं।

यह दृष्टिकोण अत्यंत कुशल है और कई महत्वपूर्ण लाभ प्रदान करता है:


  • रीयल-टाइम डेटा : पोलिंग चक्रों की विलंबता के बिना, तुरंत सूचनाएं प्राप्त करें।
  • कम लागत : यह आपको एक जटिल और संसाधन-गहन मतदान अवसंरचना के प्रबंधन से बचाता है।
  • शक्तिशाली फ़िल्टरिंग : क्विकनोड की ओर से डेटा को प्रोसेस और फ़िल्टर करें, ताकि आपके सर्वर को केवल वही सटीक जानकारी मिले जिसकी उसे आवश्यकता है।
  • किफायती : केवल प्रति इवेंट के हिसाब से भुगतान करें, जिससे यह रीयल-टाइम डेटा मॉनिटरिंग के लिए एक बजट-अनुकूल समाधान बन जाता है।

व्हेल अलर्ट बॉट प्रोजेक्ट

व्हेल अलर्ट बॉट में कई परस्पर जुड़े हुए घटक होते हैं जो वास्तविक समय की सूचनाएं प्रदान करने के लिए एक साथ काम करते हैं:

  1. हाइपरलिक्विड ब्लॉकचेन: ए स्थानांतरण आयोजन (स्थानांतरण(पता,पता,यूइंट256)HYPE टोकन के लिए ( ) तब जारी किया जाता है जब कोई ट्रांसफर होता है।

  2. फ़िल्टरिंग के साथ क्विकनोड स्ट्रीम : स्ट्रीम लगातार चेन की निगरानी करती है और हमारे द्वारा परिभाषित फ़िल्टर फ़ंक्शन के आधार पर इस घटना को कैप्चर करती है।

  3. वेबहुक डिलीवरी : क्विकनोड फ़िल्टर किए गए पेलोड को एक सुरक्षित POST अनुरोध के माध्यम से हमारे सर्वर एंडपॉइंट पर भेजता है।

  4. Node.js सर्वर : हमारा सर्वर डेटा प्राप्त करता है, वेबहुक के सुरक्षा टोकन का उपयोग करके उसकी प्रामाणिकता को सत्यापित करता है और उसे संसाधित करता है।

  5. मूल्य प्राप्त करना : सर्वर HYPE की वर्तमान USD कीमत प्राप्त करने के लिए Hyperliquid पर HyperCore प्रीकंपाइल अनुबंध को कॉल करता है।

  6. टेलीग्राम बॉट : अंत में, सर्वर एक समृद्ध, पठनीय संदेश को प्रारूपित करता है और टेलीग्राम बॉट एपीआई का उपयोग करके हमारे निर्दिष्ट चैनल पर अलर्ट भेजता है।

हाइपरलिक्विड व्हेल अलर्ट बॉट आर्किटेक्चर

यह संपूर्ण इवेंट फ्लो है जिसे हम लागू करेंगे। अब, चलिए हाइपरलिक्विड व्हेल अलर्ट बॉट बनाना शुरू करते हैं।

चरण 1: अपना टेलीग्राम बॉट और चैनल बनाएं

सबसे पहले, आपको एक टेलीग्राम बॉट और एक चैनल की आवश्यकता होगी जहां वह अलर्ट पोस्ट कर सके।

BotFather का उपयोग करके एक बॉट बनाएं


  1. टेलीग्राम खोलें और बॉटफादर को खोजें।
  2. बॉटफादर के साथ चैट शुरू करें और कमांड का उपयोग करें /नयाबॉट एक नया बॉट बनाने के लिए।
  3. अपने बॉट के लिए नाम और उपयोगकर्ता नाम सेट करने के लिए दिए गए निर्देशों का पालन करें।
  4. BotFather आपको एक बॉट टोकन प्रदान करेगा। इस टोकन को सुरक्षित रूप से सहेज कर रखें; आपको इसकी आवश्यकता होगी। .पर्यावरण फ़ाइल।

एक चैनल बनाएं


  1. टेलीग्राम में एक नया चैनल बनाएं। आप इसे सार्वजनिक या निजी बना सकते हैं।
  2. सार्वजनिक चैनल के लिए, एक यादगार उपयोगकर्ता नाम चुनें (उदाहरण के लिए, @hyperliquid_whales)। यह उपयोगकर्ता नाम आपका चैनल होगा। टेलीग्राम चैनल आईडी.
  3. किसी निजी चैनल के लिए, आपको उसकी संख्यात्मक चैट आईडी की आवश्यकता होगी। आप चैनल से किसी संदेश को बॉट पर अग्रेषित करके इसे प्राप्त कर सकते हैं। @JsonDumpCUBotऔर इसके द्वारा प्रदान की गई चैट आईडी की जाँच करना (अर्थात, forward_from_chat.id).

अपने बॉट को चैनल में जोड़ें


  1. अपने नए बनाए गए चैनल की सेटिंग्स खोलें।
  2. अपने बॉट को जोड़ें और उसे प्रशासक बनाएं।

अब आपके पास है टेलीग्राम_बॉट_टोकन और अपने टेलीग्राम चैनल आईडी.

चरण 2: अपना क्विकनोड हाइपरलिक्विड ईवीएम एंडपॉइंट बनाएं

अब, अपना क्विकनोड हाइपरलिक्विड ईवीएम एंडपॉइंट बनाएं जिसका उपयोग HYPE मूल्य डेटा प्राप्त करने के लिए हाइपरलिक्विड कोर के साथ इंटरैक्ट करने के लिए किया जाएगा।

सबसे पहले, आपको एक Quicknode अकाउंट की आवश्यकता होगी। यदि आपके पास पहले से ही एक अकाउंट है, तो बस लॉग इन करें। Quicknode डैशबोर्ड पर पहुँचने के बाद:


  • एंडपॉइंट्स पेज पर जाएं
  • न्यू एंडपॉइंट बटन पर क्लिक करें
  • हाइपरलिक्विड ईवीएम मेननेट नेटवर्क का चयन करें
  • अपना एंडपॉइंट बनाएं

एंडपॉइंट बन जाने के बाद, अपने एंडपॉइंट URL को कॉपी करके अपने पास रखें। आपको इसे अपने में जोड़ना होगा। .पर्यावरण फाइल को बाद के चरण में जमा करें।

चरण 3: अपना क्विकनोड स्ट्रीम बनाएं

अब, आइए क्विकनोड स्ट्रीम को सेटअप करें जो हाइपरलिक्विड ब्लॉकचेन की निगरानी करेगा।

स्ट्रीम बनाएं


  1. क्विकनोड डैशबोर्ड पर जाएं और स्ट्रीम सेक्शन पर जाएं।
  2. क्रिएट स्ट्रीम पर क्लिक करें और ब्लॉकचेन के रूप में हाइपरलिक्विड ईवीएम मेननेट का चयन करें।
  3. रसीदों वाले ब्लॉक को डेटासेट के रूप में चुनें
  4. फ़िल्टर लागू करने के लिए " अपने पेलोड को अनुकूलित करें" पर क्लिक करें और "अपना फ़िल्टर स्वयं लिखें" विकल्प चुनें।

अपना फ़िल्टर परिभाषित करें

इस गाइड के लिए, हम अपने स्तरीय अलर्ट लॉजिक को लागू करने के लिए एक कस्टम जावास्क्रिप्ट फ़ंक्शन बनाएंगे।

हम जिस फ़ंक्शन का उपयोग करेंगे, वह प्रत्येक नए ब्लॉक में प्रत्येक लेनदेन की जांच करता है। यह विशेष रूप से उन इवेंट लॉग की तलाश करता है जो मानक ERC20 से मेल खाते हैं। स्थानांतरण हस्ताक्षर (0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef) और इनकी उत्पत्ति होती है प्रचार टोकन अनुबंध। स्थानांतरण इवेंट में, टॉपिक्स ऐरे में प्रेषक और प्राप्तकर्ता शामिल होते हैं, जबकि लॉग.डेटा इसमें राशि दर्ज होती है। हमारा कोड इस जानकारी को डिकोड करता है, राशि की तुलना हमारे निर्धारित मानकों से करता है, और केवल तभी स्वच्छ डेटा पेलोड लौटाता है जब स्थानांतरण राशि पर्याप्त बड़ी हो। यह पूर्व-प्रसंस्करण अत्यंत कुशल है, जिससे यह सुनिश्चित होता है कि हमारा सर्वर अनावश्यक डेटा पर संसाधनों को बर्बाद न करे।

फंक्शन बॉक्स में, निम्नलिखित कोड पेस्ट करें:

// Quicknode Stream Filter for Tiered Wrapped HYPE Token Transfers
function main(payload) {
// --- Configuration ---
// The specific token contract address for Wrapped HYPE
const WHYPE_ADDRESS = "0x5555555555555555555555555555555555555555";

// Define the thresholds for each tier (with 18 decimals)
const TIER_THRESHOLDS = {
whale: BigInt("10000000000000000000000"), // 10,000 HYPE
dolphin: BigInt("5000000000000000000000"), // 5,000 HYPE
small_fish: BigInt("1000000000000000000000"), // 1,000 HYPE
};

// --- Static Data ---
const TRANSFER_SIGNATURE =
"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef";

const { data } = payload;
const block = data[0].block;
const receipts = data[0].receipts || [];

const categorizedTransfers = [];

const blockNumber = parseInt(block.number, 16);
const blockTimestamp = parseInt(block.timestamp, 16);

for (const receipt of receipts) {
for (const log of receipt.logs || []) {
// Primary filter: Is this a Transfer event from the W-HYPE contract?
if (
log.address.toLowerCase() === WHYPE_ADDRESS &&
log.topics[0] === TRANSFER_SIGNATURE
) {
const transferValue = BigInt(log.data);
let tier = null;

// Tiering Logic: Check from the highest threshold down to the lowest.
if (transferValue >= TIER_THRESHOLDS.whale) {
tier = "whale";
} else if (transferValue >= TIER_THRESHOLDS.dolphin) {
tier = "dolphin";
} else if (transferValue >= TIER_THRESHOLDS.small_fish) {
tier = "small_fish";
}

// If the transfer meets any of our thresholds, process it.
if (tier) {
const fromAddress = "0x" + log.topics[1].slice(26);
const toAddress = "0x" + log.topics[2].slice(26);

categorizedTransfers.push({
tier: tier,
tokenContract: log.address,
from: fromAddress,
to: toAddress,
value: transferValue.toString(),
transactionHash: receipt.transactionHash,
blockNumber: blockNumber,
timestamp: blockTimestamp,
});
}
}
}
}

if (categorizedTransfers.length > 0) {
return {
largeTransfers: categorizedTransfers,
};
}

return null;
}

अपने फ़िल्टर का परीक्षण करें

एक ब्लॉक का चयन करें (जैसे कि 12193297) अपने फ़िल्टर की शर्तों का परीक्षण करने और यह सत्यापित करने के लिए कि अलर्ट सही ढंग से ट्रिगर हो रहे हैं। आपको इस तरह वर्गीकृत ट्रांसफ़र वाला एक पेलोड दिखाई देना चाहिए:

{
"largeTransfers": [
{
"blockNumber": 12193297,
"from": "0x7c97cd7b57b736c6ad74fae97c0e21e856251dcf",
"tier": "small_fish",
"timestamp": 1756245832,
"to": "0xaaa2851ec59f335c8c6b4db6738c94fd0305598a",
"tokenContract": "0x5555555555555555555555555555555555555555",
"transactionHash": "0xafe522067fca99d4b44030d82885cabb757943255b991b3f2e95564807dbe0f7",
"value": "2200000000000000000000"
}
]
}

सुरक्षा टोकन प्राप्त करें और वेबहुक यूआरएल सेट करें

अगले चरण पर आगे बढ़ने पर, आपसे अपना गंतव्य चुनने के लिए कहा जाएगा। चुनें WEbhook गंतव्य प्रकार के रूप में। फिर, क्विकनोड स्वचालित रूप से एक उत्पन्न करेगा सुरक्षा टोकन आने वाले अनुरोधों की प्रामाणिकता की पुष्टि करने के लिए। इस टोकन को अपने कंप्यूटर में कॉपी करें। .पर्यावरण फ़ाइल को मान के रूप में वेबहुक_गुप्त चर।

स्ट्रीम के डेस्टिनेशन यूआरएल के लिए, आपको एक सार्वजनिक रूप से सुलभ एंडपॉइंट की आवश्यकता होगी। विकास के दौरान, आप इसका उपयोग कर सकते हैं। एनग्रोक या स्थानीय सुरंग अपने स्थानीय सर्वर को उजागर करने के लिए। आप इसे चला सकते हैं। ngrok http 3000 (यह मानते हुए कि आपका सर्वर पोर्ट 3000 पर चलता है) और सर्वर चलने के बाद HTTPS फ़ॉरवर्डिंग URL को कॉपी करें। याद रखें कि इसमें जोड़ें /वेबहुक इसके लिए (उदाहरण के लिए, https://your-ngrok-id.ngrok.io/webhook) क्योंकि यहीं पर आप अपना वेबहुक लिसनर बनाएंगे।

चूंकि हमारा सर्वर अभी तक तैयार नहीं हुआ है, इसलिए हम यहां रुकेंगे और सर्वर तैयार होने के बाद स्ट्रीम का परीक्षण और सक्रियण करने के लिए वापस आएंगे।

चरण 4: वेबहुक सर्वर का निर्माण करें

अब, आइए एक Node.js एप्लिकेशन बनाते हैं जो हमारे वेबहुक से डेटा प्राप्त करेगा और उसे प्रोसेस करेगा।

प्रोजेक्ट सेटअप और निर्भरताएँ

सबसे पहले, अपने प्रोजेक्ट के लिए एक डायरेक्टरी बनाएं और आवश्यक डिपेंडेंसी इंस्टॉल करें। आप इसका उपयोग कर सकते हैं। NPM या कोई अन्य पैकेज मैनेजर (जैसे कि धागा, पीएनपीएम, बन) ऐसा करने के लिए। उदाहरण के लिए:

mkdir hyperliquid-whale-alert-bot && सीडी हाइपरलिक्विड-व्हेल-अलर्ट-बॉट
npm init -y
npm i express dotenv node-telegram-bot-api viem
npm i -D नोडमोन

फिर, अपने को अपडेट करें package.json निम्नलिखित को शामिल करने के लिए:

"type": "module",
"scripts": {
"start": "node index.js",
"dev": "nodemon index.js"
}

परियोजना संरचना

अपने प्रोजेक्ट के लिए एक बुनियादी संरचना बनाने के लिए निम्नलिखित फाइलें बनाएं:

├── config.js // कॉन्फ़िगरेशन सेटिंग्स
├── index.js // मुख्य प्रवेश बिंदु
├── priceService.js // मूल्य संबंधी तर्क
├── security.js // सुरक्षा संबंधी तर्क
├── telegramService.js // टेलीग्राम बॉट एकीकरण
└── .env // पर्यावरण चर
└── .gitignore // गिट इग्नोर फ़ाइल

यहां एक लाइन का कमांड दिया गया है जिसे आप अपने टर्मिनल में चलाकर तुरंत ये सभी फाइलें बना सकते हैं:

.config.js, index.js, priceService.js, security.js, telegramService.js, .env, .gitignore को टच करें

# यदि टच कमांड उपलब्ध नहीं है, तो आप निम्न का उपयोग कर सकते हैं:
# (echo > config.js) && (echo > index.js) && (echo > priceService.js) && (echo > security.js) && (echo > telegramService.js) && (echo > .env) && (echo > .gitignore)

पर्यावरण चर

अपडेट करें .पर्यावरण अपने प्रोजेक्ट के रूट फ़ोल्डर में एक फ़ाइल बनाएं जिसमें आपके पर्यावरण चर संग्रहीत हों। निम्नलिखित चर जोड़ें:

# टेलीग्राम कॉन्फ़िगरेशन
TELEGRAM_BOT_TOKEN = आपका_टेलीग्राम_बॉट_टोकन
TELEGRAM_CHANNEL_ID = आपका_चैनल_आईडी

# सर्वर कॉन्फ़िगरेशन
पोर्ट = 3000

# स्ट्रीम वेबहुक सुरक्षा
वेबहुक_सीक्रेट = आपका_वैकल्पिक_वेबहुक_सीक्रेट

# हाइपरलिक्विड ईवीएम आरपीसी के लिए क्विकनोड कॉन्फ़िगरेशन
HYPERLIQUID_RPC = https://your-endpoint.quiknode.pro/your-token/

# पर्यावरण
NODE_ENV = विकास

कोड कार्यान्वयन

.gitignore

इसमें जोड़ना महत्वपूर्ण है .gitignore संवेदनशील जानकारी और अनावश्यक फ़ाइलों को कमिट करने से बचने के लिए अपनी प्रोजेक्ट में एक फ़ाइल बनाएं। .gitignore अपने प्रोजेक्ट के रूट फ़ोल्डर में एक फ़ाइल बनाएं और उसमें निम्नलिखित पंक्तियाँ जोड़ें:

नोड_मॉड्यूल
.पर्यावरण
config.js

इस फ़ाइल में आपके एप्लिकेशन के लिए कॉन्फ़िगरेशन सेटिंग्स शामिल हैं, जिनमें पर्यावरण चर और अन्य स्थिरांक शामिल हैं।

The स्थान मूल्य पूर्वसंकलन जीवन पर 0x...0808, जब ओरेकल मूल्य प्रीकंपाइल है 0x...0807आप अपने मूल्य स्रोत के आधार पर दोनों में से किसी का भी उपयोग कर सकते हैं; यह गाइड स्थानपते की पुष्टि हमेशा आधिकारिक दस्तावेजों और अद्यतन गाइडों से करें।

import dotenv from "dotenv";

// Load environment variables
dotenv.config();

export const TIERS = {
whale: {
emoji: "🐋",
label: "WHALE",
},
dolphin: {
emoji: "🐬",
label: "DOLPHIN",
},
small_fish: {
emoji: "🐟",
label: "FISH",
},
};

export const EXPLORER = {
tx: "https://hypurrscan.io/tx/",
address: "https://hypurrscan.io/address/",
block: "https://hypurrscan.io/block/",
};

export const HYPERCORE = {
SPOT_PX_PRECOMPILE: "0x0000000000000000000000000000000000000808",
HYPE_SPOT_INDEX: 107, // Mainnet HYPE spot ID
RPC_URL: process.env.HYPERLIQUID_RPC || "https://api.hyperliquid.xyz/evm",
};

export const MESSAGE_DELAY_MS = 1000; // Delay between Telegram messages

export const PORT = process.env.PORT || 3000;
priceService.js

यह सेवा हाइपरकोर से HYPE मूल्य प्राप्त करने के लिए जिम्मेदार है।

हम कॉल करेंगे स्थान मूल्य को सीधे 32-बाइट ABI-एन्कोडेड इंडेक्स के साथ प्रीकंपाइल करें। प्रीकंपाइल एक मान लौटाता है। uint64 जहां दशमलव मापन परिसंपत्ति पर निर्भर करता है szDecimals (हाइपरलिक्विड की मूल्य प्रणाली)।

// priceService.js
// Fetches HYPE price from HyperCore using precompile

import { createPublicClient, http, encodeAbiParameters, formatUnits } from "viem";
import { HYPERCORE } from "./config.js";

// Create viem client for HyperEVM
const client = createPublicClient({
transport: http(HYPERCORE.RPC_URL),
});

// Cache price for 30 seconds to avoid excessive RPC calls
let priceCache = {
price: null,
timestamp: 0,
};
const CACHE_DURATION = 30000; // 30 seconds

/**
* Fetches HYPE spot price from HyperCore precompile
* Price is returned with 6 decimals precision for HYPE
* Details: To convert to floating point numbers, divide the returned price by 10^(8 - base asset szDecimals) for spot
* Source: https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/hyperevm/interacting-with-hypercore
* @returns {Promise<number|null>} HYPE price in USD
*/
export async function getHypePrice() {
try {
// Check cache first
if (
priceCache.price &&
Date.now() - priceCache.timestamp < CACHE_DURATION
) {
console.log("Using cached HYPE price:", priceCache.price);
return priceCache.price;
}

// Encode the spot index as a uint32 parameter
const encodedIndex = encodeAbiParameters(
[{ name: "index", type: "uint32" }],
[HYPERCORE.HYPE_SPOT_INDEX]
);

// Call the spot price precompile
const result = await client.call({
to: HYPERCORE.SPOT_PX_PRECOMPILE,
data: encodedIndex,
});

// szDecimals for HYPE is 2.
const szDecimals = 2;

const priceRaw = BigInt(result.data);
const price = formatUnits(priceRaw, 8 - szDecimals); // Convert to decimal string

// Update cache
priceCache = {
price,
timestamp: Date.now(),
};

console.log(`Fetched HYPE price from HyperCore: $${price}`);
return price;
} catch (error) {
console.error("Error fetching HYPE price from HyperCore:", error);
// Return cached price if available, otherwise null
return priceCache.price || null;
}
}

/**
* Formats USD value based on HYPE amount and price
* @param {string} hypeAmount - HYPE amount as string
* @param {number} hypePrice - HYPE price in USD
* @returns {string} Formatted USD value
*/
export function formatUSD(hypeAmount, hypePrice) {
if (!hypePrice) return "";

const usdValue = parseFloat(hypeAmount) * hypePrice;
return `($${usdValue.toLocaleString("en-US", {
minimumFractionDigits: 0,
maximumFractionDigits: 0,
})})`;
}
सुरक्षा.js

इस मॉड्यूल में आने वाले वेबहुक को मान्य करने का तर्क शामिल है। क्विकनोड हेडर का उपयोग करके एचएमएसी सत्यापन की अनुशंसा करता है। X-QN-Nonce, X-QN-टाइमस्टैम्प, और एक्स-क्यूएन-हस्ताक्षर और यह मॉड्यूल उस सत्यापन को लागू करता है।

अधिक जानकारी के लिए, वैलिडेटिंग स्ट्रीम्स सिग्नेचर गाइड देखें।

// security.js
// Validates incoming webhook signatures from Quicknode

import crypto from "crypto";

/**
* Validates the webhook signature from Quicknode
* Based on Quicknode's HMAC-SHA256 signature validation
*
* @param {string} secretKey - The webhook secret key
* @param {string} payload - The request body as string
* @param {string} nonce - The nonce from headers
* @param {string} timestamp - The timestamp from headers
* @param {string} givenSignature - The signature from headers
* @returns {boolean} Whether the signature is valid
*/
export function validateWebhookSignature(
secretKey,
payload,
nonce,
timestamp,
givenSignature
) {
if (!secretKey || !nonce || !timestamp || !givenSignature) {
console.warn("⚠️ Missing required parameters for signature validation");
return false;
}

try {
// Concatenate nonce + timestamp + payload as strings
const signatureData = nonce + timestamp + payload;

// Convert to bytes
const signatureBytes = Buffer.from(signatureData);

// Create HMAC with secret key converted to bytes
const hmac = crypto.createHmac("sha256", Buffer.from(secretKey));
hmac.update(signatureBytes);
const computedSignature = hmac.digest("hex");

// Use timing-safe comparison to prevent timing attacks
const isValid = crypto.timingSafeEqual(
Buffer.from(computedSignature, "hex"),
Buffer.from(givenSignature, "hex")
);

if (isValid) {
console.log("✅ Webhook signature validated successfully");
} else {
console.error("❌ Invalid webhook signature");
}

return isValid;
} catch (error) {
console.error("Error validating webhook signature:", error);
return false;
}
}

/**
* Middleware for Express to validate webhook signatures
* Quicknode sends nonce, timestamp, and signature in headers
*/
export function webhookAuthMiddleware(req, res, next) {
// Skip validation if no secret is configured
const secretKey = process.env.WEBHOOK_SECRET;
if (!secretKey) {
console.log("ℹ️ Webhook secret not configured, skipping validation");
return next();
}

// Get Quicknode headers
const nonce = req.headers["x-qn-nonce"];
const timestamp = req.headers["x-qn-timestamp"];
const givenSignature = req.headers["x-qn-signature"];

if (!nonce || !timestamp || !givenSignature) {
console.error("🚫 Missing required Quicknode headers");
return res.status(400).json({
error: "Missing required headers",
message:
"x-qn-nonce, x-qn-timestamp, and x-qn-signature headers are required",
});
}

// Get the raw body as string
// Note: Express's JSON middleware already parsed the body, so we need to stringify it back
const payloadString = JSON.stringify(req.body);

// Validate the signature
const isValid = validateWebhookSignature(
secretKey,
payloadString,
nonce,
timestamp,
givenSignature
);

if (!isValid) {
console.error("🚫 Webhook validation failed");
return res.status(401).json({
error: "Invalid signature",
message: "The webhook signature could not be validated",
});
}

next();
}
टेलीग्रामसर्विस.js

यह मॉड्यूल अंतिम संदेश को प्रारूपित करता है और उसे आपके टेलीग्राम चैनल पर भेजता है।

// telegramService.js
// Handles Telegram bot messaging

import TelegramBot from "node-telegram-bot-api";
import { formatEther } from "viem";
import { TIERS, EXPLORER, MESSAGE_DELAY_MS } from "./config.js";
import { getHypePrice, formatUSD } from "./priceService.js";

// Initialize Telegram bot
const bot = new TelegramBot(process.env.TELEGRAM_BOT_TOKEN, { polling: false });
const CHANNEL_ID = process.env.TELEGRAM_CHANNEL_ID;

/**
* Format an address for display
*/
function formatAddress(address) {
return `${address.slice(0, 6)}...${address.slice(-4)}`;
}

/**
* Format transaction hash for display
*/
function formatTxHash(hash) {
return `${hash.slice(0, 10)}...`;
}

/**
* Display time
*/
function getTime(timestamp) {
const date = new Date(timestamp * 1000);
return date.toLocaleString("en-US");
}

/**
* Create formatted Telegram message for a transfer
*/
async function createMessage(transfer) {
const tierConfig = TIERS[transfer.tier];
const formattedValue = formatEther(BigInt(transfer.value));
const hypePrice = await getHypePrice();
const usdValue = formatUSD(formattedValue, hypePrice);

// Create message with Markdown formatting
const message = `
${tierConfig.emoji} *${tierConfig.label} ALERT* ${tierConfig.emoji}

💰 *Amount:* \`${parseFloat(formattedValue).toLocaleString("en-US", {
maximumFractionDigits: 2,
})} HYPE\` ${usdValue}

📤 *From:* [${formatAddress(transfer.from)}](${EXPLORER.address}${
transfer.from
})
📥 *To:* [${formatAddress(transfer.to)}](${EXPLORER.address}${transfer.to})

🔗 *TX:* [${formatTxHash(transfer.transactionHash)}](${EXPLORER.tx}${
transfer.transactionHash
})
📦 *Block:* [#${transfer.blockNumber}](${EXPLORER.block}${transfer.blockNumber})
⏰ *Time:* ${getTime(transfer.timestamp)}

Powered by [Hyperliquid](https://hyperliquid.xyz) & [Quicknode Streams](https://www.quicknode.com/streams)`;

return message;
}

/**
* Send message to Telegram with retry logic
*/
export async function sendMessage(message, retries = 3) {
for (let i = 0; i < retries; i++) {
try {
await bot.sendMessage(CHANNEL_ID, message, {
parse_mode: "Markdown",
disable_web_page_preview: true,
});

console.log("✅ Message sent to Telegram successfully");
return true;
} catch (error) {
console.error(`❌ Telegram send attempt ${i + 1} failed:`, error.message);

if (i < retries - 1) {
// Wait before retrying (exponential backoff)
await new Promise((resolve) =>
setTimeout(resolve, 1000 * Math.pow(2, i))
);
}
}
}

return false;
}

/**
* Process and send alerts to Telegram
*/
export async function processAlerts(transfers) {
console.log(`📨 Processing ${transfers.length} transfers for Telegram...`);

for (const transfer of transfers) {
const message = await createMessage(transfer);
const sent = await sendMessage(message);

if (!sent) {
console.error(
"Failed to send message for transfer:",
transfer.transactionHash
);
}

// Rate limiting between messages
if (transfers.indexOf(transfer) < transfers.length - 1) {
await new Promise((resolve) => setTimeout(resolve, MESSAGE_DELAY_MS));
}
}

// Send summary if there are multiple transfers
if (transfers.length > 3) {
const summaryMessage = `
📊 *Batch Summary*

Total transfers: ${transfers.length}
🐋 Whales: ${transfers.filter((t) => t.tier === "whale").length}
🐬 Dolphins: ${transfers.filter((t) => t.tier === "dolphin").length}
🐟 Fish: ${transfers.filter((t) => t.tier === "small_fish").length}

Block: #${transfers[0].blockNumber}
`;
await sendMessage(summaryMessage);
}
}
index.js

यह वह मुख्य फ़ाइल है जो सब कुछ आपस में जोड़ती है।

हम JSON मिडलवेयर से पहले एक्सप्रेस रॉ बॉडी पार्सर का उपयोग करते हैं। /वेबहुक हस्ताक्षरों को सत्यापित करने में सक्षम होने के लिए एंडपॉइंट। यह सुनिश्चित करता है कि एचएमएसी सत्यापन के लिए बॉडी अपने मूल रूप में उपलब्ध है।

// server.js
// Main webhook server for Hyperliquid whale alerts

import express from "express";
import dotenv from "dotenv";
import { PORT, HYPERCORE } from "./config.js";
import { processAlerts } from "./telegramService.js";
import { webhookAuthMiddleware } from "./security.js";

// Load environment variables
dotenv.config();

// Initialize Express app
const app = express();

// Custom middleware to capture raw body for signature validation
app.use((req, res, next) => {
if (req.path === '/webhook' && process.env.WEBHOOK_SECRET) {
// For webhook endpoint with security enabled, capture raw body
let rawBody = '';
req.setEncoding('utf8');

req.on('data', (chunk) => {
rawBody += chunk;
});

req.on('end', () => {
req.rawBody = rawBody;

// Parse JSON body
try {
req.body = JSON.parse(rawBody);
} catch (error) {
return res.status(400).json({ error: 'Invalid JSON payload' });
}

next();
});
} else {
// For other endpoints or when security is disabled, use normal JSON parsing
express.json()(req, res, next);
}
});

// Main webhook endpoint with security validation
app.post("/webhook", webhookAuthMiddleware, async (req, res) => {
try {
console.log("📨 Webhook received at", new Date().toISOString());

const { largeTransfers } = req.body;

if (!largeTransfers || largeTransfers.length === 0) {
console.log("No large transfers in this webhook");
return res.json({ success: true, processed: 0 });
}

console.log(`Processing ${largeTransfers.length} transfers...`);

// Send alerts to Telegram
await processAlerts(largeTransfers);

console.log(`✅ Processed ${largeTransfers.length} transfers successfully`);

res.json({
success: true,
processed: largeTransfers.length,
});
} catch (error) {
console.error("❌ Webhook processing error:", error);
res.status(500).json({
success: false,
error: error.message,
});
}
});

// Health check endpoint
app.get("/health", (req, res) => {
res.json({
status: "healthy",
timestamp: new Date().toISOString(),
environment: {
telegramConfigured: !!process.env.TELEGRAM_BOT_TOKEN,
webhookSecretConfigured: !!process.env.WEBHOOK_SECRET,
},
});
});

// Error handling middleware
app.use((error, req, res, next) => {
console.error("Unhandled error:", error);
res.status(500).json({
success: false,
error: "Internal server error",
});
});

// Start server
app.listen(PORT, () => {
console.log(`
╔════════════════════════════════════════════╗
║ Hyperliquid Whale Alert Server Started ║
╠════════════════════════════════════════════╣
║ Port: ${PORT}
║ Webhook: http://localhost:${PORT}/webhook ║
║ Health: http://localhost:${PORT}/health ║
╚════════════════════════════════════════════╝

Configuration:
- Telegram Bot: ${
process.env.TELEGRAM_BOT_TOKEN ? "✅ Configured" : "❌ Not configured"
}
- Telegram Channel: ${process.env.TELEGRAM_CHANNEL_ID || "Not configured"}
- Webhook Secret: ${
process.env.WEBHOOK_SECRET
? "✅ Configured"
: "⚠️ Not configured (validation disabled)"
}
- HyperCore RPC: ${HYPERCORE.RPC_URL}

Ready to receive webhooks...
`);
});

// Graceful shutdown
process.on("SIGTERM", () => {
console.log("SIGTERM received, shutting down gracefully...");
process.exit(0);
});

process.on("SIGINT", () => {
console.log("SIGINT received, shutting down gracefully...");
process.exit(0);
});

चरण 5: सिस्टम को चलाएं और उसका परीक्षण करें

अब आप अपने बॉट को जीवंत करने के लिए तैयार हैं।

अपना सर्वर शुरू करें

सर्वर शुरू करने के लिए अपने टर्मिनल में निम्नलिखित कमांड चलाएँ। नोडमोन यह फ़ाइल में बदलाव होने पर सर्वर को स्वचालित रूप से रीस्टार्ट करने की अनुमति देता है।

# नोडमॉन के साथ डेवलपमेंट मोड में शुरू करें
npm run dev

अपने लोकलहोस्ट को उजागर करें

यदि आपने ऐसा नहीं किया है, तो एक नई टर्मिनल विंडो खोलें और इसे चलाएं। ngrok http 3000HTTPS फॉरवर्डिंग URL को कॉपी करें।

अपनी स्ट्रीम का परीक्षण करें


  1. क्विकनोड डैशबोर्ड में अपने वेबहुक के पेज पर वापस जाएं।
  2. अपना ngrok URL पेस्ट करें (उदाहरण के लिए, https://your-ngrok-id.ngrok.io/webhook) को वेबहुक यूआरएल फ़ील्ड में डालें और सेव करें।
  3. अब, "नमूना पेलोड भेजें" बटन पर क्लिक करें। क्विकनोड आपके चल रहे सर्वर पर एक नमूना पेलोड भेजेगा।
  4. अपने सर्वर के कंसोल लॉग की जांच करें और अलर्ट के लिए अपने टेलीग्राम चैनल को चेक करें।

अंतिम अलर्ट कैसा दिखेगा, इसका एक उदाहरण यहां दिया गया है:

हाइपरलिक्विड व्हेल बॉट - नमूना संदेश

अपनी स्ट्रीम सक्रिय करें

सब कुछ ठीक से काम कर रहा है, यह सुनिश्चित करने के बाद, अपना स्ट्रीम बनाने के लिए "स्ट्रीम बनाएं" बटन पर क्लिक करें। आपका बॉट अब लाइव है और सभी नए HYPE ट्रांसफर की रियल-टाइम निगरानी करेगा।

समस्या निवारण

कभी-कभी, यदि आपका सर्वर या एनग्रोक यदि सिस्टम ठीक से बंद नहीं होता है, तो इसे पुनः चालू करने का प्रयास करते समय आपको "पता पहले से उपयोग में है" जैसी त्रुटि का सामना करना पड़ सकता है। इसे तुरंत ठीक करने का तरीका यहाँ बताया गया है।

चरण 1: पोर्ट को खाली करें

सबसे पहले, पोर्ट का उपयोग करके प्रोसेस आईडी (पीआईडी) का पता लगाएं, फिर उसे रोकें। नीचे दिए गए कमांड macOS/Linux के लिए हैं; आपके ऑपरेटिंग सिस्टम के आधार पर इनमें अंतर हो सकता है।

# Find the Process ID (PID) using port 3004
lsof -i :3004

# Replace <PID> with the number you found and run:
kill -9 <PID>

चरण 2: रीस्टार्ट करें और अपडेट करें

अपने सर्वर को रीस्टार्ट करें और एनग्रोक। महत्वपूर्ण: एनग्रोक यह शुरू होने पर हर बार एक नया URL बनाता है। आपको इस नए URL को कॉपी करके अपने Quicknode वेबहुक सेटिंग्स में अपडेट करना होगा।

निष्कर्ष

बधाई हो! आपने हाइपरलिक्विड ब्लॉकचेन के लिए सफलतापूर्वक एक उत्पादन-तैयार, रीयल-टाइम व्हेल अलर्ट सिस्टम बना लिया है। ऑन-चेन डेटा के लिए क्विकनोड स्ट्रीम्स , व्यावसायिक तर्क के लिए एक सुरक्षित नोड.जेएस सर्वर और सूचनाओं के लिए टेलीग्राम एपीआई की शक्ति को मिलाकर, आपने डीएफआई इकोसिस्टम की निगरानी के लिए एक उपयोगी उपकरण तैयार किया है।

यह पैटर्न लचीला है, आप टियर का विस्तार कर सकते हैं, अतिरिक्त ऑनचेन संदर्भ के साथ इसे समृद्ध कर सकते हैं, या अपने उपयोग के मामले के विकसित होने के साथ डेटा स्रोतों और गंतव्यों को बदल सकते हैं।

अगले चरण: उत्पादन परिनियोजन

जबकि एनग्रोक यह डेवलपमेंट के लिए तो बढ़िया है, लेकिन प्रोडक्शन एनवायरनमेंट के लिए आपको एक स्थायी समाधान की आवश्यकता होगी। अपने एप्लिकेशन को निम्नलिखित स्थानों पर डिप्लॉय करने पर विचार करें:


  • DigitalOcean या AWS जैसे वर्चुअल प्राइवेट सर्वर (VPS) का उपयोग करके, PM2 जैसे प्रोसेस मैनेजर के माध्यम से इसे सुचारू रूप से चलाया जा सकता है।
  • डॉकर का उपयोग करने वाली एक कंटेनरीकृत सेवा
  • Heroku या Render जैसी प्लेटफॉर्म-एज़-ए-सर्विस (PaaS)

संभावित सुधार

यह प्रोजेक्ट एक मजबूत आधार प्रदान करता है जिस पर आप आगे विस्तार कर सकते हैं। अपने बॉट को अगले स्तर तक ले जाने के लिए कुछ सुझाव यहाँ दिए गए हैं:

  • मल्टी-टोकन सपोर्ट : कोड को इस तरह से बदलें कि वह टोकन एड्रेस की एक ऐरे स्वीकार करे। इस तरह, आप अलग-अलग थ्रेशहोल्ड वाले कई टोकन की निगरानी कर सकते हैं और तदनुसार अलर्ट भेज सकते हैं।

  • ऐतिहासिक डेटा डैशबोर्ड : क्विकनोड स्ट्रीम्स न केवल रीयल-टाइम डेटा बल्कि ऐतिहासिक डेटा को भी सपोर्ट करता है। आने वाले ट्रांसफर डेटा को डेटाबेस (जैसे, PostgreSQL, MongoDB) में स्टोर करें। फिर आप ऐतिहासिक रुझानों को देखने, विशिष्ट व्हेल वॉलेट के कुल प्रवाह को ट्रैक करने और गहन ऑनचेन विश्लेषण करने के लिए एक वेब-आधारित dApp बना सकते हैं।

  • अधिक नोटिफिकेशन चैनल जोड़ें : डिस्कॉर्ड वेबहुक जैसी अन्य नोटिफिकेशन सेवाओं को एकीकृत करें।

  • स्वचालित ट्रेडिंग ट्रिगर्स : अधिक उन्नत उपयोग के लिए, आप इन अलर्ट्स का उपयोग ऑनचेन क्रियाओं को ट्रिगर करने के लिए कर सकते हैं। उदाहरण के लिए, एक बड़ा ट्रांसफर स्वैप को ट्रिगर कर सकता है।

अतिरिक्त संसाधन


अगर आपको कोई समस्या आ रही है या आपके कोई सवाल हैं, तो उन्हें हमारे Discord पर पूछें। नवीनतम जानकारी के लिए हमें X (पहले Twitter) (@Quicknode) पर फॉलो करें या हमारे Telegram अनाउंसमेंट चैनल पर हमसे जुड़ें।

हमें आपकी प्रतिक्रिया बहुत पसंद है!

अगर आपके पास कोई सुझाव या नए विषयों के लिए कोई अनुरोध हो तो हमें जरूर बताएं । हमें आपसे सुनना अच्छा लगेगा।

इस गाइड को साझा करें