Moniteur de portefeuille ETH
Ceci est unContent Creation, Multimodal AIworkflow d'automatisation du domainecontenant 13 nœuds.Utilise principalement des nœuds comme Code, Discord, HttpRequest, ScheduleTrigger. Suivi quotidien de portefeuille ETH avec Etherscan, prix CoinGecko et alertes Discord
- •Token Bot Discord ou Webhook
- •Peut nécessiter les informations d'identification d'authentification de l'API cible
Nœuds utilisés (13)
Catégorie
{
"meta": {
"instanceId": "105694f414213a0eca348284005921253960bd1b0223294a4970522d0da53055",
"templateCredsSetupCompleted": true
},
"nodes": [
{
"id": "220614c6-c32f-41ba-9669-2532c13a21f6",
"name": "Déclencheur Planifié",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
0,
0
],
"parameters": {
"rule": {
"interval": [
{
"field": "cronExpression",
"expression": "45 7,17 * * *"
}
]
}
},
"typeVersion": 1.2
},
{
"id": "2fbe1f25-d09c-43da-933e-6903c6b2155b",
"name": "Requête HTTP",
"type": "n8n-nodes-base.httpRequest",
"position": [
208,
0
],
"parameters": {
"url": "=https://api.etherscan.io/v2/api?chainid=1&module=account&action=tokentx&address=YOUR_WALLET_HERE&sort=asc&apikey=YOUR_KEY_HERE",
"method": "=GET",
"options": {}
},
"typeVersion": 4.2
},
{
"id": "755d4d95-2ff5-4023-8c37-005dc7f3ea69",
"name": "Code en JavaScript",
"type": "n8n-nodes-base.code",
"position": [
416,
0
],
"parameters": {
"jsCode": "// Input: JSON response from Etherscan tokentx endpoint\nconst wallet = \"YOUR_WALLET_ADDRESS\".toLowerCase();\nconst txs = items[0].json.result; // Assuming the HTTP node passed the Etherscan JSON\n\n// Reduce transactions into balances\nconst balances = {};\n\nfor (const tx of txs) {\n const symbol = tx.tokenSymbol;\n const decimals = parseInt(tx.tokenDecimal);\n const value = BigInt(tx.value);\n\n // Initialize token entry if missing\n if (!balances[symbol]) {\n balances[symbol] = {\n contract: tx.contractAddress,\n tokenName: tx.tokenName,\n tokenSymbol: tx.tokenSymbol,\n decimals: decimals,\n raw: BigInt(0)\n };\n }\n\n // If wallet is the recipient => add\n if (tx.to.toLowerCase() === wallet) {\n balances[symbol].raw += value;\n }\n\n // If wallet is the sender => subtract\n if (tx.from.toLowerCase() === wallet) {\n balances[symbol].raw -= value;\n }\n}\n\n// Convert raw balances to human-readable\nconst results = Object.values(balances).map(t => {\n return {\n token: t.tokenSymbol,\n contract: t.contract,\n amount: Number(t.raw) / (10 ** t.decimals),\n decimals: t.decimals\n };\n});\n\n// Return in N8N format\nreturn results.map(r => ({ json: r }));\n"
},
"typeVersion": 2
},
{
"id": "4abe9847-da8e-47a2-ae69-5918545e0cc1",
"name": "Code en JavaScript1",
"type": "n8n-nodes-base.code",
"position": [
624,
0
],
"parameters": {
"jsCode": "const balances = items.map(i => i.json);\n\n// Join all contract addresses into a comma-separated string\nconst contracts = balances.map(b => b.contract).join(',');\n\n// Pass both balances and contracts downstream\nreturn [\n {\n json: {\n balances,\n contracts\n }\n }\n];\n"
},
"typeVersion": 2
},
{
"id": "dd3ca09d-2eb4-45e0-ad0d-dc9c7f093404",
"name": "Requête HTTP1",
"type": "n8n-nodes-base.httpRequest",
"position": [
1456,
0
],
"parameters": {
"url": "=https://api.coingecko.com/api/v3/simple/token_price/ethereum?contract_addresses={{ $('Code in JavaScript1').item.json.contracts }}&vs_currencies=usd",
"options": {},
"jsonHeaders": "{\n \"accept\": \"application/json\",\n \"x-cg-demo-api-key\": \"COIN_GECKO_KEY_HERE\"\n}\n",
"sendHeaders": true,
"specifyHeaders": "json"
},
"typeVersion": 4.2
},
{
"id": "21538827-f180-4012-ac7d-7567da5f251c",
"name": "Code en JavaScript2",
"type": "n8n-nodes-base.code",
"position": [
1664,
0
],
"parameters": {
"jsCode": "// ---- Pull inputs safely ----\nconst erc20 = $node[\"Code in JavaScript1\"].json?.balances ?? [];\nconst eth = $node[\"Code ETH Balance\"].json ?? null;\n\nconst cgTokenPrices = $node[\"HTTP Request1\"].json ?? {}; // { [contract]: { usd } }\nconst ethUsd = $node[\"HTTP Request ETH Price\"].json?.ethereum?.usd ?? 0;\n\n// ---- Combine balances (ETH + ERC-20) ----\nconst balances = eth ? [eth, ...erc20] : [...erc20];\n\n// ---- Build a single price map (token prices + ETH) ----\nconst priceMap = { ...cgTokenPrices };\n// Give ETH a fake \"contract\" key so it matches by contract like the tokens\nconst ETH_KEY = \"0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee\";\npriceMap[ETH_KEY] = { usd: ethUsd };\n\n// ---- Enrich balances with prices ----\nconst enriched = balances.map(b => {\n const key = (b.contract || \"\").toLowerCase();\n const usdPrice = priceMap[key]?.usd ?? 0;\n const amount = Number(b.amount || 0); // already human-readable amounts\n const usdValue = amount * usdPrice;\n\n return {\n token: b.token,\n contract: b.contract,\n amount,\n usdPrice,\n usdValue,\n };\n}).sort((a, b) => b.usdValue - a.usdValue);\n\n// ---- Totals & quick diagnostics ----\nconst totalUsd = enriched.reduce((s, t) => s + (t.usdValue || 0), 0);\nconst ethLine = enriched.find(t => t.token === \"ETH\");\nconst ethUsdValue = ethLine ? ethLine.usdValue : 0;\nconst restUsd = totalUsd - ethUsdValue;\n\n// ---- Discord message ----\nlet message = `**ETH Wallet Update 💰**\\n\\n`;\nmessage += `**Total Value:** $${totalUsd.toFixed(2)} USD\\n`;\nif (ethLine) {\n message += `• ETH: ${ethLine.amount.toFixed(6)} @ $${(ethLine.usdPrice||0).toFixed(2)} = $${ethUsdValue.toFixed(2)}\\n`;\n message += `• Other tokens (priced): $${restUsd.toFixed(2)}\\n\\n`;\n} else {\n message += `• No ETH price/balance found\\n\\n`;\n}\n\nmessage += enriched\n .filter(t => t.usdValue > 0.01)\n .map(t => `${t.token}: $${t.usdValue.toFixed(2)} (px $${t.usdPrice.toFixed(6)})`)\n .join(\"\\n\");\n\nreturn [{\n json: {\n totalUsd,\n tokens: enriched,\n discordMessage: message\n }\n}];\n"
},
"typeVersion": 2
},
{
"id": "a6dffe53-b602-40dc-bd08-87175da21bab",
"name": "Discord",
"type": "n8n-nodes-base.discord",
"position": [
1872,
0
],
"webhookId": "be4e3eba-3fcc-4329-9ba4-4aaea73cdf70",
"parameters": {
"content": "={{ $json.discordMessage }}",
"options": {},
"authentication": "webhook"
},
"credentials": {
"discordWebhookApi": {
"id": "6S341y8tVCvOIO8r",
"name": "All Ops Notis Discord Webhook"
}
},
"typeVersion": 2
},
{
"id": "f01b5fec-fdb8-42a5-9abf-6676a47ca321",
"name": "Requête HTTP ETH",
"type": "n8n-nodes-base.httpRequest",
"position": [
832,
0
],
"parameters": {
"url": "https://api.etherscan.io/v2/api?chainid=1&module=account&action=balance&address=YOUR_WALLET_HERE&apikey=YOUR_KEY_HERE",
"options": {}
},
"typeVersion": 4.2
},
{
"id": "8c0c8162-c9c4-442e-be11-1a8820ce43e4",
"name": "Code Solde ETH",
"type": "n8n-nodes-base.code",
"position": [
1040,
0
],
"parameters": {
"jsCode": "const wei = BigInt($node[\"HTTP Request ETH\"].json.result);\nconst eth = Number(wei) / 1e18;\n\nreturn [{\n json: {\n token: \"ETH\",\n contract: \"0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee\", // dummy\n amount: eth,\n decimals: 18\n }\n}];\n"
},
"typeVersion": 2
},
{
"id": "b7de03cb-f775-4aea-8445-d401ecca2f31",
"name": "Requête HTTP Prix ETH",
"type": "n8n-nodes-base.httpRequest",
"position": [
1248,
0
],
"parameters": {
"url": "https://api.coingecko.com/api/v3/simple/price?ids=ethereum&vs_currencies=usd",
"options": {},
"jsonHeaders": "{\n \"accept\": \"application/json\",\n \"x-cg-demo-api-key\": \"COIN_GEKCO_KEY_HERE\"\n}\n",
"sendHeaders": true,
"specifyHeaders": "json"
},
"typeVersion": 4.2
},
{
"id": "85e8bac4-d42a-4d36-8496-2d1e6d19ea04",
"name": "Note Adhésive",
"type": "n8n-nodes-base.stickyNote",
"position": [
1264,
-160
],
"parameters": {
"height": 96,
"content": "## Set Coin Gecko Keys Here"
},
"typeVersion": 1
},
{
"id": "39647a8d-f10f-4cc2-aefe-1f53d304e59c",
"name": "Note Adhésive1",
"type": "n8n-nodes-base.stickyNote",
"position": [
272,
-240
],
"parameters": {
"height": 192,
"content": "## Add Etherscan API Key to first 2 HTTP nodes. Add Wallet Address to Code Block as well."
},
"typeVersion": 1
},
{
"id": "1b94d811-6947-46a1-b6b7-e928d74b7c73",
"name": "Note Adhésive2",
"type": "n8n-nodes-base.stickyNote",
"position": [
-176,
-288
],
"parameters": {
"height": 256,
"content": "## Daily ETH Wallet Balance sent to Discord. Currently you get two updates. One in the Morning and Evening."
},
"typeVersion": 1
}
],
"pinData": {},
"connections": {
"2fbe1f25-d09c-43da-933e-6903c6b2155b": {
"main": [
[
{
"node": "755d4d95-2ff5-4023-8c37-005dc7f3ea69",
"type": "main",
"index": 0
}
]
]
},
"dd3ca09d-2eb4-45e0-ad0d-dc9c7f093404": {
"main": [
[
{
"node": "21538827-f180-4012-ac7d-7567da5f251c",
"type": "main",
"index": 0
}
]
]
},
"8c0c8162-c9c4-442e-be11-1a8820ce43e4": {
"main": [
[
{
"node": "b7de03cb-f775-4aea-8445-d401ecca2f31",
"type": "main",
"index": 0
}
]
]
},
"f01b5fec-fdb8-42a5-9abf-6676a47ca321": {
"main": [
[
{
"node": "8c0c8162-c9c4-442e-be11-1a8820ce43e4",
"type": "main",
"index": 0
}
]
]
},
"220614c6-c32f-41ba-9669-2532c13a21f6": {
"main": [
[
{
"node": "2fbe1f25-d09c-43da-933e-6903c6b2155b",
"type": "main",
"index": 0
}
]
]
},
"755d4d95-2ff5-4023-8c37-005dc7f3ea69": {
"main": [
[
{
"node": "4abe9847-da8e-47a2-ae69-5918545e0cc1",
"type": "main",
"index": 0
}
]
]
},
"4abe9847-da8e-47a2-ae69-5918545e0cc1": {
"main": [
[
{
"node": "f01b5fec-fdb8-42a5-9abf-6676a47ca321",
"type": "main",
"index": 0
}
]
]
},
"21538827-f180-4012-ac7d-7567da5f251c": {
"main": [
[
{
"node": "a6dffe53-b602-40dc-bd08-87175da21bab",
"type": "main",
"index": 0
}
]
]
},
"b7de03cb-f775-4aea-8445-d401ecca2f31": {
"main": [
[
{
"node": "dd3ca09d-2eb4-45e0-ad0d-dc9c7f093404",
"type": "main",
"index": 0
}
]
]
}
}
}Comment utiliser ce workflow ?
Copiez le code de configuration JSON ci-dessus, créez un nouveau workflow dans votre instance n8n et sélectionnez "Importer depuis le JSON", collez la configuration et modifiez les paramètres d'authentification selon vos besoins.
Dans quelles scénarios ce workflow est-il adapté ?
Intermédiaire - Création de contenu, IA Multimodale
Est-ce payant ?
Ce workflow est entièrement gratuit et peut être utilisé directement. Veuillez noter que les services tiers utilisés dans le workflow (comme l'API OpenAI) peuvent nécessiter un paiement de votre part.
Workflows recommandés
Kaden Reese
@kadenreeseI started automating with Python in 2020 and still use it in workflows when needed, but I’ve recently leaned into n8n for client-facing solutions. Lately I’ve focused on real estate automations, though I also build workflows for email, scraping, and other use cases. Currently Building 👇🏻
Partager ce workflow