{
  "name": "YST Whale Alert Monitor",
  "nodes": [
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "minutes",
              "minutesInterval": 5
            }
          ]
        }
      },
      "id": "b2c3d4e5-0002-0002-0002-000000000001",
      "name": "Schedule Trigger (5min)",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.1,
      "position": [
        240,
        380
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.mainnet-beta.solana.com",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"getSignaturesForAddress\",\"params\":[\"jYwmSavfx69a35JEkpyrxu9JUjvswEvfnhLCDV9vREV\",{\"limit\":25}]}",
        "options": {
          "timeout": 30000,
          "batching": {
            "batch": {
              "batchSize": 1,
              "batchInterval": 2000
            }
          }
        }
      },
      "id": "b2c3d4e5-0002-0002-0002-000000000011",
      "name": "RPC getSignaturesForAddress",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        490,
        380
      ],
      "continueOnFail": true
    },
    {
      "parameters": {
        "jsCode": "// Parse signatures list and skip already-seen ones using static data\nconst rpcData = $input.first().json;\nconst signatures = rpcData?.result || [];\n\nif (!signatures.length) {\n  return [{ json: { sigs: [], hasNew: false } }];\n}\n\n// Load seen signatures from static data\nconst staticData = $getWorkflowStaticData('global');\nif (!staticData.seenSigs) staticData.seenSigs = [];\n\n// Keep only the last 200 to avoid unbounded growth\nconst seenSet = new Set(staticData.seenSigs);\nconst newSigs = signatures\n  .map(s => s.signature)\n  .filter(sig => sig && !seenSet.has(sig));\n\nif (newSigs.length === 0) {\n  return [{ json: { sigs: [], hasNew: false } }];\n}\n\n// Store new sigs\nconst merged = [...staticData.seenSigs, ...newSigs];\nstaticData.seenSigs = merged.slice(-200);\n\n// Return each new sig as a separate item for getTransaction calls\n// Limit to 3 per run to stay within public Solana RPC rate limits\nconst limited = newSigs.slice(0, 3);\nreturn limited.map(sig => ({ json: { signature: sig, hasNew: true } }));"
      },
      "id": "b2c3d4e5-0002-0002-0002-000000000012",
      "name": "Filter New Signatures",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        740,
        380
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict"
          },
          "conditions": [
            {
              "id": "has-new-sigs",
              "leftValue": "={{ $json.hasNew }}",
              "rightValue": true,
              "operator": {
                "type": "boolean",
                "operation": "equals"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "id": "b2c3d4e5-0002-0002-0002-000000000013",
      "name": "Has New Signatures?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        990,
        380
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.mainnet-beta.solana.com",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"getTransaction\",\"params\":[\"{{ $json.signature }}\",{\"encoding\":\"jsonParsed\",\"maxSupportedTransactionVersion\":0}]}",
        "options": {
          "timeout": 30000,
          "batching": {
            "batch": {
              "batchSize": 1,
              "batchInterval": 2000
            }
          }
        }
      },
      "id": "b2c3d4e5-0002-0002-0002-000000000014",
      "name": "RPC getTransaction",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1240,
        280
      ],
      "continueOnFail": true
    },
    {
      "parameters": {
        "jsCode": "// Parse transaction data and detect whale-level YST transfers\nconst txData = $input.first().json;\nconst tx = txData?.result;\n\nif (!tx) return [{ json: { skip: true, reason: 'Transaction not found or still processing' } }];\n\nconst txHash = tx.transaction?.signatures?.[0] || '';\nconst blockTime = tx.blockTime ? new Date(tx.blockTime * 1000).toISOString() : new Date().toISOString();\n\n// Parse token balances to find YST transfers\nconst preBalances = tx.meta?.preTokenBalances || [];\nconst postBalances = tx.meta?.postTokenBalances || [];\n\nconst YST_MINT = 'jYwmSavfx69a35JEkpyrxu9JUjvswEvfnhLCDV9vREV';\nconst WHALE_THRESHOLD = 1000000;   // 1M YST\nconst MEGA_WHALE_THRESHOLD = 10000000; // 10M YST\n\n// Build maps by accountIndex+mint\nconst preMap = {};\nfor (const b of preBalances) {\n  if (b.mint === YST_MINT) {\n    preMap[b.accountIndex] = parseFloat(b.uiTokenAmount?.uiAmount || 0);\n  }\n}\n\nconst results = [];\nfor (const post of postBalances) {\n  if (post.mint !== YST_MINT) continue;\n  const preAmt = preMap[post.accountIndex] || 0;\n  const postAmt = parseFloat(post.uiTokenAmount?.uiAmount || 0);\n  const diff = Math.abs(postAmt - preAmt);\n\n  if (diff >= WHALE_THRESHOLD) {\n    const accountKeys = tx.transaction?.message?.accountKeys || [];\n    const ownerKey = post.owner || accountKeys[post.accountIndex]?.pubkey || 'Unknown';\n    const shortAddr = ownerKey.length > 8\n      ? ownerKey.slice(0, 4) + '...' + ownerKey.slice(-4)\n      : ownerKey;\n\n    results.push({\n      json: {\n        txHash,\n        wallet: ownerKey,\n        shortAddr,\n        amount: diff,\n        isMegaWhale: diff >= MEGA_WHALE_THRESHOLD,\n        timestamp: blockTime,\n        solscanUrl: `https://solscan.io/tx/${txHash}`,\n        skip: false\n      }\n    });\n  }\n}\n\nif (results.length === 0) {\n  return [{ json: { skip: true, reason: 'No whale-level YST transfer in this tx' } }];\n}\n\nreturn results;"
      },
      "id": "b2c3d4e5-0002-0002-0002-000000000002",
      "name": "Detect Whale Transfers",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1490,
        280
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict"
          },
          "conditions": [
            {
              "id": "whale-filter-skip",
              "leftValue": "={{ $json.skip }}",
              "rightValue": true,
              "operator": {
                "type": "boolean",
                "operation": "equals"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "id": "b2c3d4e5-0002-0002-0002-000000000003",
      "name": "Skip if no whale",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        1740,
        280
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict"
          },
          "conditions": [
            {
              "id": "mega-whale-check",
              "leftValue": "={{ $json.isMegaWhale }}",
              "rightValue": true,
              "operator": {
                "type": "boolean",
                "operation": "equals"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "id": "b2c3d4e5-0002-0002-0002-000000000004",
      "name": "Mega Whale or Whale?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        1990,
        280
      ]
    },
    {
      "parameters": {
        "jsCode": "// Format mega whale alert message (>= 10M YST)\nconst d = $input.first().json;\nconst amountFormatted = new Intl.NumberFormat('en-US').format(Math.round(d.amount));\n\nreturn [{\n  json: {\n    ...d,\n    telegramMessage: `\ud83d\udea8\ud83d\udc0b MEGA WHALE ALERT \ud83d\udc0b\ud83d\udea8\\n\\n\ud83d\udcb0 ${amountFormatted} $YST moved\\n\ud83c\udfe0 Wallet: \\`${d.shortAddr}\\`\\n\u23f1 Time: ${d.timestamp}\\n\ud83d\udd17 [View on Solscan](${d.solscanUrl})\\n\\n#YST #YakkStudios #Solana`\n  }\n}];"
      },
      "id": "b2c3d4e5-0002-0002-0002-000000000005",
      "name": "Format Mega Whale Message",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        2240,
        180
      ]
    },
    {
      "parameters": {
        "jsCode": "// Format standard whale alert message (>= 1M YST)\nconst d = $input.first().json;\nconst amountFormatted = new Intl.NumberFormat('en-US').format(Math.round(d.amount));\n\nreturn [{\n  json: {\n    ...d,\n    telegramMessage: `\ud83d\udc0b WHALE ALERT\\n\\n\ud83d\udcb0 ${amountFormatted} $YST moved\\n\ud83c\udfe0 Wallet: \\`${d.shortAddr}\\`\\n\u23f1 Time: ${d.timestamp}\\n\ud83d\udd17 [View on Solscan](${d.solscanUrl})\\n\\n#YST #YakkStudios #Solana`\n  }\n}];"
      },
      "id": "b2c3d4e5-0002-0002-0002-000000000006",
      "name": "Format Whale Message",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        2240,
        380
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "=https://api.telegram.org/bot{{ $credentials.httpHeaderAuth.value }}/sendMessage",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\"chat_id\":\"@yakkstudios\",\"text\":\"{{ $json.telegramMessage }}\",\"parse_mode\":\"Markdown\",\"disable_web_page_preview\":false}",
        "options": {
          "timeout": 10000,
          "continueOnFail": true
        }
      },
      "id": "b2c3d4e5-0002-0002-0002-000000000007",
      "name": "Telegram Mega Whale Alert",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        2490,
        180
      ],
      "notes": "Create a Header Auth credential named 'Telegram Bot Token' with Name: Authorization, Value: <your_bot_token> (no Bearer prefix). Paste bot token directly.",
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "method": "POST",
        "url": "=https://api.telegram.org/bot{{ $credentials.httpHeaderAuth.value }}/sendMessage",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\"chat_id\":\"@yakkstudios\",\"text\":\"{{ $json.telegramMessage }}\",\"parse_mode\":\"Markdown\",\"disable_web_page_preview\":false}",
        "options": {
          "timeout": 10000,
          "continueOnFail": true
        }
      },
      "id": "b2c3d4e5-0002-0002-0002-000000000008",
      "name": "Telegram Whale Alert",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        2490,
        380
      ],
      "notes": "Create a Header Auth credential named 'Telegram Bot Token' with Name: Authorization, Value: <your_bot_token>.",
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://yakkstudios.xyz/api/whale-feed",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\"txHash\":\"{{ $json.txHash }}\",\"wallet\":\"{{ $json.wallet }}\",\"amount\":{{ $json.amount }},\"isMegaWhale\":{{ $json.isMegaWhale }},\"timestamp\":\"{{ $json.timestamp }}\",\"solscanUrl\":\"{{ $json.solscanUrl }}\"}",
        "options": {
          "timeout": 5000,
          "continueOnFail": true
        }
      },
      "id": "b2c3d4e5-0002-0002-0002-000000000009",
      "name": "POST to DApp Live Feed",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        2740,
        280
      ]
    }
  ],
  "connections": {
    "Schedule Trigger (5min)": {
      "main": [
        [
          {
            "node": "RPC getSignaturesForAddress",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "RPC getSignaturesForAddress": {
      "main": [
        [
          {
            "node": "Filter New Signatures",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Filter New Signatures": {
      "main": [
        [
          {
            "node": "Has New Signatures?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Has New Signatures?": {
      "main": [
        [
          {
            "node": "RPC getTransaction",
            "type": "main",
            "index": 0
          }
        ],
        []
      ]
    },
    "RPC getTransaction": {
      "main": [
        [
          {
            "node": "Detect Whale Transfers",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Detect Whale Transfers": {
      "main": [
        [
          {
            "node": "Skip if no whale",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Skip if no whale": {
      "main": [
        [],
        [
          {
            "node": "Mega Whale or Whale?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Mega Whale or Whale?": {
      "main": [
        [
          {
            "node": "Format Mega Whale Message",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Format Whale Message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format Mega Whale Message": {
      "main": [
        [
          {
            "node": "Telegram Mega Whale Alert",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format Whale Message": {
      "main": [
        [
          {
            "node": "Telegram Whale Alert",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Telegram Mega Whale Alert": {
      "main": [
        [
          {
            "node": "POST to DApp Live Feed",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Telegram Whale Alert": {
      "main": [
        [
          {
            "node": "POST to DApp Live Feed",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1",
    "saveManualExecutions": true,
    "callerPolicy": "workflowsFromSameOwner",
    "errorWorkflow": ""
  },
  "staticData": null,
  "tags": [
    {
      "createdAt": "2026-03-29T02:00:00.000Z",
      "updatedAt": "2026-03-29T02:00:00.000Z",
      "id": "yst-tag-1",
      "name": "YakkStudios"
    }
  ],
  "triggerCount": 1,
  "updatedAt": "2026-03-29T02:00:00.000Z",
  "versionId": "whale-alert-monitor-v2",
  "active": false
}