8
n8n 中文网amn8n.com

ETH钱包监测器

中级

这是一个Content Creation, Multimodal AI领域的自动化工作流,包含 13 个节点。主要使用 Code, Discord, HttpRequest, ScheduleTrigger 等节点。 使用Etherscan、CoinGecko价格和Discord提醒的每日ETH钱包监测

前置要求
  • Discord Bot Token 或 Webhook
  • 可能需要目标 API 的认证凭证
工作流预览
可视化展示节点连接关系,支持缩放和平移
导出工作流
复制以下 JSON 配置到 n8n 导入,即可使用此工作流
{
  "meta": {
    "instanceId": "105694f414213a0eca348284005921253960bd1b0223294a4970522d0da53055",
    "templateCredsSetupCompleted": true
  },
  "nodes": [
    {
      "id": "220614c6-c32f-41ba-9669-2532c13a21f6",
      "name": "计划触发器",
      "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": "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": "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": "JavaScript代码1",
      "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": "HTTP请求1",
      "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": "JavaScript代码2",
      "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": "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": "代码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": "HTTP请求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": "便签",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1264,
        -160
      ],
      "parameters": {
        "height": 96,
        "content": "## 在此设置Coin Gecko密钥"
      },
      "typeVersion": 1
    },
    {
      "id": "39647a8d-f10f-4cc2-aefe-1f53d304e59c",
      "name": "便签1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        272,
        -240
      ],
      "parameters": {
        "height": 192,
        "content": "## 在前2个HTTP节点中添加Etherscan API密钥。同时在代码块中添加钱包地址。"
      },
      "typeVersion": 1
    },
    {
      "id": "1b94d811-6947-46a1-b6b7-e928d74b7c73",
      "name": "便签2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -176,
        -288
      ],
      "parameters": {
        "height": 256,
        "content": "## 每日ETH钱包余额发送到Discord。目前您会收到两次更新:早上和晚上各一次。"
      },
      "typeVersion": 1
    }
  ],
  "pinData": {},
  "connections": {
    "HTTP Request": {
      "main": [
        [
          {
            "node": "Code in JavaScript",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "HTTP Request1": {
      "main": [
        [
          {
            "node": "Code in JavaScript2",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code ETH Balance": {
      "main": [
        [
          {
            "node": "HTTP Request ETH Price",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "HTTP Request ETH": {
      "main": [
        [
          {
            "node": "Code ETH Balance",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Schedule Trigger": {
      "main": [
        [
          {
            "node": "HTTP Request",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code in JavaScript": {
      "main": [
        [
          {
            "node": "Code in JavaScript1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code in JavaScript1": {
      "main": [
        [
          {
            "node": "HTTP Request ETH",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code in JavaScript2": {
      "main": [
        [
          {
            "node": "Discord",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "HTTP Request ETH Price": {
      "main": [
        [
          {
            "node": "HTTP Request1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
常见问题

如何使用这个工作流?

复制上方的 JSON 配置代码,在您的 n8n 实例中创建新工作流并选择「从 JSON 导入」,粘贴配置后根据需要修改凭证设置即可。

这个工作流适合什么场景?

中级 - 内容创作, 多模态 AI

需要付费吗?

本工作流完全免费,您可以直接导入使用。但请注意,工作流中使用的第三方服务(如 OpenAI API)可能需要您自行付费。

工作流信息
难度等级
中级
节点数量13
分类2
节点类型5
难度说明

适合有一定经验的用户,包含 6-15 个节点的中等复杂度工作流

作者
Kaden Reese

Kaden Reese

@kadenreese

I 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 👇🏻

外部链接
在 n8n.io 查看

分享此工作流