{
  "id": "rwBmKKWS8XyIAkrL",
  "name": "My workflow 14",
  "tags": [],
  "nodes": [
    {
      "id": "ce2e7838-e9ff-49ea-93f9-11aacb58191c",
      "name": "Calculate TWAP",
      "type": "n8n-nodes-base.code",
      "position": [
        -704,
        864
      ],
      "parameters": {
        "jsCode": "// Constants\nconst MaxUint256 = (1n << 256n) - 1n;\nconst Q32 = 1n << 32n;\nconst ZERO = 0n;\nconst ONE = 1n;\n\nfunction mulShift(val, mulBy) {\n  return (val * BigInt(mulBy)) >> 128n;\n}\n\n/**\n * Returns the sqrt ratio as a Q64.96 for the given tick.\n * The sqrt ratio is computed as sqrt(1.0001)^tick\n * @param {number} tick the tick for which to compute the sqrt ratio\n */\nfunction getSqrtRatioAtTick(tick) {\n  if (!Number.isInteger(tick)) throw new Error(\"Tick must be integer\");\n  const MIN_TICK = -887272;\n  const MAX_TICK = 887272;\n\n  if (tick < MIN_TICK || tick > MAX_TICK) throw new Error(\"Tick out of bounds\");\n\n  const absTick = tick < 0 ? -tick : tick;\n\n  let ratio =\n    (absTick & 0x1) != 0\n      ? 0xfffcb933bd6fad37aa2d162d1a594001n\n      : 0x1+1234567890+1234567890n;\n  if ((absTick & 0x2) != 0) ratio = mulShift(ratio, 0xfff97272373d413259a46990580e213an);\n  if ((absTick & 0x4) != 0) ratio = mulShift(ratio, 0xfff2e50f5f656932ef12357cf3c7fdccn);\n  if ((absTick & 0x8) != 0) ratio = mulShift(ratio, 0xffe5caca7e10e4e61c3624eaa0941cd0n);\n  if ((absTick & 0x10) != 0) ratio = mulShift(ratio, 0xffcb9843d60f6159c9db58835c926644n);\n  if ((absTick & 0x20) != 0) ratio = mulShift(ratio, 0xff973b41fa98c081472e6896dfb254c0n);\n  if ((absTick & 0x40) != 0) ratio = mulShift(ratio, 0xff2ea16466c96a3843ec78b326b52861n);\n  if ((absTick & 0x80) != 0) ratio = mulShift(ratio, 0xfe5dee046a99a2a811c461f1969c3053n);\n  if ((absTick & 0x100) != 0) ratio = mulShift(ratio, 0xfcbe86c7900a88aedcffc83b479aa3a4n);\n  if ((absTick & 0x200) != 0) ratio = mulShift(ratio, 0xf987a7253ac413176f2b074cf7815e54n);\n  if ((absTick & 0x400) != 0) ratio = mulShift(ratio, 0xf3392b0822b70005940c7a398e4b70f3n);\n  if ((absTick & 0x800) != 0) ratio = mulShift(ratio, 0xe7159475a2c29b7443b29c7fa6e889d9n);\n  if ((absTick & 0x1000) != 0) ratio = mulShift(ratio, 0xd097f3bdfd2022b8845ad8f792aa5825n);\n  if ((absTick & 0x2000) != 0) ratio = mulShift(ratio, 0xa9f746462d870fdf8a65dc1f90e061e5n);\n  if ((absTick & 0x4000) != 0) ratio = mulShift(ratio, 0x70d869a156d2a1b890bb3df62baf32f7n);\n  if ((absTick & 0x8000) != 0) ratio = mulShift(ratio, 0x31be135f97d08fd981231505542fcfa6n);\n  if ((absTick & 0x10000) != 0) ratio = mulShift(ratio, 0x9aa508b5b7a84e1c677de54f3e99bc9n);\n  if ((absTick & 0x20000) != 0) ratio = mulShift(ratio, 0x5d6af8dedb81196699c329225ee604n);\n  if ((absTick & 0x40000) != 0) ratio = mulShift(ratio, 0x2216e584f5fa1ea926041bedfe98n);\n  if ((absTick & 0x80000) != 0) ratio = mulShift(ratio, 0x48a170391f7dc42444e8fa2n);\n\n  if (tick > 0) {\n    ratio = MaxUint256 / ratio;\n  }\n\n  // back to Q96\n  return ratio % Q32 > 0n ? ratio / Q32 + ONE : ratio / Q32;\n}\n\nfunction getPriceFromSqrtPriceX96(sqrtPriceX96, decimals0, decimals1) {\n  // Ensure input is BigInt\n  const sqrtPrice = BigInt(sqrtPriceX96.toString());\n\n  // (sqrtPriceX96 ^ 2)\n  const numerator = sqrtPrice * sqrtPrice;\n\n  // Denominator = 2^192\n  const denominator = 1n << 192n;\n\n  // Raw price ratio (tokenOut per tokenIn, no decimals adjusted)\n  let ratio = Number(numerator * 10n**18n / denominator) / 1e18; \n  // (we scale by 1e18 to stay precise when converting to Number)\n\n  // Adjust for token decimals\n  const decimalFactor = 10 ** (decimals0 - decimals1);\n  const price = ratio * decimalFactor;\n\n  return price;\n}\n\nconst diffTickCumulative = BigInt($('Fetch Pool TWA Observations').first().json.response[0][0]) - BigInt($('Fetch Pool TWA Observations').first().json.response[0][1]);\nconst diffSecondsPerLIquidityX128 = BigInt($('Fetch Pool TWA Observations').first().json.response[1][0]) - BigInt($('Fetch Pool TWA Observations').first().json.response[1][1]);\nconst secondsBetween = parseInt($('Swap Configs').first().json.secondsAgo);\nconst secondsBetweenX128 = BigInt(secondsBetween) << BigInt(128);\nconst averageTick = parseInt(parseFloat(diffTickCumulative)/secondsBetween);\n\n\nconst sqrtTWAPricex96 = getSqrtRatioAtTick(averageTick);\nconst TWAP = getPriceFromSqrtPriceX96(sqrtTWAPricex96, $('Swap Configs').first().json.token0Decimals, $('Swap Configs').first().json.token1Decimals);\nconst TWAL = secondsBetweenX128 / BigInt(diffSecondsPerLIquidityX128);\n\n\n$input.first().json.twap = TWAP; \n$input.first().json.sqrtTWAPriceX96 = sqrtTWAPricex96; \n$input.first().json.twal = TWAL; \n\nreturn $input.all()\n"
      },
      "typeVersion": 2
    },
    {
      "id": "d0ac3258-891a-4770-807f-9cfd70b59ca7",
      "name": "Fetch Pool TWA Observations",
      "type": "n8n-nodes-1shot.oneShot",
      "position": [
        -928,
        864
      ],
      "parameters": {
        "params": "={\n  \"secondsAgos\": [\"0\",\"{{ $json.secondsAgo }}\"]\n} ",
        "operation": "read",
        "contractMethodId": "98267bd2-13c9-4c27-bc86-ee2389da1025"
      },
      "credentials": {
        "oneShotOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "269d4c6d-8031-4341-b0cd-af77ef52985f",
      "name": "Schedule Trigger",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -1376,
        864
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "minutes",
              "minutesInterval": 30
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "c23f4ffc-8f6e-491d-ab06-85a5b4699cb6",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1328,
        336
      ],
      "parameters": {
        "width": 800,
        "height": 464,
        "content": "## Swap configs\n\nSince we are using the Uniswap protocol directly, you'll need to set a few parameters in the Swap Configs node. \n\n1. Decide on the amount of USDC to spend to enter ETH, put this in `amountUSDC`. \n2. Set your upper and lower price ranges in `upperPrice` and `lowerPrice`. \n3. Put your wallet address as the `delegator` so that the workflow can execute DCA buys on your behalf. \n4. Set the Telegram chatID for your bot to receive notifications.\n\n### Optional Parameters\nIf you want to change the chain or assets you may have to change these parameters:\n\n1. Set the correct address for the Uniswap [SwapRouter](https://docs.uniswap.org/contracts/v3/reference/deployments/) contract\n2. If you want to trade something besided ETH/USDC, you'll need to set the correct addresses for `token0`, `token1`, `token0Decimals` and `token1Decimals`.\n3. Check the `fee` for the pool you are targeting and make sure it matches. \n4. Edit the slippage percentage to your taste. "
      },
      "typeVersion": 1
    },
    {
      "id": "f3382c3e-85b0-45f2-b1fb-b466ccc9ae72",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        208,
        80
      ],
      "parameters": {
        "width": 720,
        "height": 400,
        "content": "## Connect to Your 1Shot API Account\n\nCreate an API key and secret in your 1Shot API account and connect your n8n instance by creating a credential. \n\n1. The `Fetch Pool TWA Observactions` should point to the `observe` method on your target trading pool (like this [one](https://app.uniswap.org/explore/pools/base/0xfBB6Eed8e7aa03B138556eeDaF5D271A5E1e43ef)). \n2. The `Get Sell Quote` and `Get Buy Quote` nodes should both point to the `quoteExactInputSingle` on the QuoterV2 contract.\n3. The `Give Approval to Router (Buy)` should call `approve` on USDC.\n4. The `Give Approval to Router (Sell)` should call `approve` on WETH. \n5. The `Sell ETH` and `Buy Eth` nodes should point at the `exactInputSingle` function on the Uniswap SwapRouterV2 contract. \n5. In order to get look up your remaining balance of funds that can be used for DCA purchases, point the `Check New Funds` and `Check Remaining Funds` nodes at the `balanceOf` function on USDC."
      },
      "typeVersion": 1
    },
    {
      "id": "988a0381-d6cb-4663-b6bd-7085962a026a",
      "name": "Swap Configs",
      "type": "n8n-nodes-base.code",
      "position": [
        -1152,
        864
      ],
      "parameters": {
        "jsCode": "const amountDCA = 25000000; // amount to swap each time (in atomic units of USDC)\nconst upperPrice = 4613; // in dollars\nconst lowerPrice = 4372; // in dollars\nconst slippage = 0.025 // the amount the price can move by from quote to swap (multiply by 100 for percentage)\nconst secondsAgo = 120; // the size of your TWAP window\nconst delegator = \"0x9fead8b19c044c2f404dac38b925ea16adaa2954\"; // your delegated wallet address.\nconst telegramChatId = 5034284669; // the chat id between you and your Telegram bot\nconst router = \"0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45\"; // the uniswap SwapRouterV2\nconst token0 = \"0x82aF49447D8a07e3bd95BD0d56f35241523fBab1\"; // The pool's token0\nconst token1 = \"0xaf88d065e77c8cC2239327C5EDb3A432268e5831\"; // The pool's token1\nconst token0Decimals = 18; // WETH has 18 decimals\nconst token1Decimals = 6; // USDC has 6 decimals\nconst fee = 500; // the fee of your target pool, most pools have a fee of 500\n\n$input.first().json.amountDCA = amountDCA;\n$input.first().json.upperPrice = upperPrice;\n$input.first().json.lowerPrice = lowerPrice;\n$input.first().json.telegramChatId = telegramChatId;\n$input.first().json.delegator = delegator;\n$input.first().json.router = router;\n$input.first().json.token0 = token0;\n$input.first().json.token0Decimals = token0Decimals;\n$input.first().json.token1 = token1;\n$input.first().json.token1Decimals = token1Decimals;\n$input.first().json.fee = fee;\n$input.first().json.slippage = slippage;\n$input.first().json.secondsAgo = secondsAgo;\n\nreturn $input.all();\n"
      },
      "typeVersion": 2
    },
    {
      "id": "6b937fb5-54c3-4a00-9a87-21545da46b9e",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -544,
        1648
      ],
      "parameters": {
        "width": 800,
        "content": "## Set up a 1Shot API Wallet & Import Required Methods:\n\nClick the sub-workflow trigger to setup you 1Shot API account with a server wallet and all required smart contract methods needed for range trading."
      },
      "typeVersion": 1
    },
    {
      "id": "8b61c2bb-7e6d-4187-a9f6-b8bcac7dfed9",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1568,
        1216
      ],
      "parameters": {
        "width": 768,
        "height": 560,
        "content": "## YouTube Tutorial\n\n@[youtube](Hppd04sM4xE)\n"
      },
      "typeVersion": 1
    },
    {
      "id": "fd90af4e-1631-4437-9f9c-af1764d50e60",
      "name": "Buy, Sell or Hold",
      "type": "n8n-nodes-base.switch",
      "position": [
        -32,
        864
      ],
      "parameters": {
        "rules": {
          "values": [
            {
              "outputKey": "Sell ETH",
              "conditions": {
                "options": {
                  "version": 2,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "loose"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "0080b3b6-9666-4cae-bb60-a157a3bc31c8",
                    "operator": {
                      "type": "number",
                      "operation": "gt"
                    },
                    "leftValue": "={{ $('Calculate TWAP').item.json.twap }}",
                    "rightValue": "={{ $('Swap Configs').item.json.upperPrice }}"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "Buy ETH",
              "conditions": {
                "options": {
                  "version": 2,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "loose"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "6bb3a399-cb6e-4d37-a402-867dfb857cf1",
                    "operator": {
                      "type": "number",
                      "operation": "lt"
                    },
                    "leftValue": "={{ $('Calculate TWAP').item.json.twap }}",
                    "rightValue": "={{ $('Swap Configs').item.json.lowerPrice }}"
                  }
                ]
              },
              "renameOutput": true
            }
          ]
        },
        "options": {},
        "looseTypeValidation": true
      },
      "typeVersion": 3.2
    },
    {
      "id": "55c859a3-94c7-4311-9029-92de95cc6fd8",
      "name": "Confirm Buy",
      "type": "n8n-nodes-base.telegram",
      "position": [
        640,
        1088
      ],
      "parameters": {
        "chatId": "={{ $('Swap Configs').item.json.telegramChatId }}",
        "message": "=Purchase {{ parseFloat($json.result.decodedData[0]) / 1e18 }} ETH at ${{ $('Calculate TWAP').item.json.twap }}?",
        "options": {
          "limitWaitTime": {
            "values": {
              "resumeUnit": "minutes"
            }
          }
        },
        "operation": "sendAndWait",
        "formFields": {
          "values": [
            {
              "fieldType": "dropdown",
              "fieldLabel": "Confirm",
              "fieldOptions": {
                "values": [
                  {
                    "option": "yes"
                  },
                  {
                    "option": "no"
                  }
                ]
              },
              "requiredField": true
            }
          ]
        },
        "responseType": "customForm"
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "fd9d7f1f-680f-4c83-9662-404d5b99bfe7",
      "name": "Purchase Cancelled",
      "type": "n8n-nodes-base.telegram",
      "position": [
        1088,
        1184
      ],
      "parameters": {
        "text": "Purchase cancelled",
        "chatId": "={{ $('Swap Configs').item.json.telegramChatId }}",
        "additionalFields": {}
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "85f19394-a9af-49f4-b7ea-89efed74921a",
      "name": "Buy or Cancel?",
      "type": "n8n-nodes-base.if",
      "position": [
        864,
        1088
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "f021075c-1415-4cf9-825f-eedc01e0a369",
              "operator": {
                "type": "string",
                "operation": "notEquals"
              },
              "leftValue": "={{ $json.data.Confirm }}",
              "rightValue": "no"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "9bbddf57-c29b-4e74-ab84-f695c37e202a",
      "name": "Check Remaining Funds",
      "type": "n8n-nodes-1shot.oneShot",
      "position": [
        1536,
        864
      ],
      "parameters": {
        "params": "={\n  \"account\": \"{{ $('Swap Configs').item.json.delegator }}\"\n}",
        "operation": "read",
        "contractMethodId": "bfc44279-e20b-4452-b809-d422134700b3"
      },
      "credentials": {
        "oneShotOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "414cb6e4-55cf-4da0-ad3e-c333bc34217a",
      "name": "Confirm Sell",
      "type": "n8n-nodes-base.telegram",
      "position": [
        640,
        656
      ],
      "parameters": {
        "chatId": "={{ $('Swap Configs').item.json.telegramChatId }}",
        "message": "=Purchase {{ parseFloat($json.result.decodedData[0]) / 1e18 }} ETH at ${{ $('Calculate TWAP').item.json.twap }}?",
        "options": {
          "limitWaitTime": {
            "values": {
              "resumeUnit": "minutes"
            }
          }
        },
        "operation": "sendAndWait",
        "formFields": {
          "values": [
            {
              "fieldType": "dropdown",
              "fieldLabel": "Confirm",
              "fieldOptions": {
                "values": [
                  {
                    "option": "yes"
                  },
                  {
                    "option": "no"
                  }
                ]
              },
              "requiredField": true
            }
          ]
        },
        "responseType": "customForm"
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "78b724f4-e685-431f-b509-c4f697d46521",
      "name": "Sell or Cancel?",
      "type": "n8n-nodes-base.if",
      "position": [
        864,
        656
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "f021075c-1415-4cf9-825f-eedc01e0a369",
              "operator": {
                "type": "string",
                "operation": "notEquals"
              },
              "leftValue": "={{ $json.data.Confirm }}",
              "rightValue": "no"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "cfc5e5f0-ae46-45cd-bb77-c01f863996a0",
      "name": "Sell Cancelled",
      "type": "n8n-nodes-base.telegram",
      "position": [
        1088,
        768
      ],
      "parameters": {
        "text": "Purchase cancelled",
        "chatId": "={{ $('Swap Configs').item.json.telegramChatId }}",
        "additionalFields": {}
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "e06dfd47-fb6e-4f6a-b6b1-11865ee10db6",
      "name": "Give Approval to Router (Sell)",
      "type": "n8n-nodes-1shot.oneShotSynch",
      "onError": "continueRegularOutput",
      "position": [
        1088,
        560
      ],
      "parameters": {
        "params": "={\n  \"spender\": \"{{ $('Swap Configs').item.json.router }}\", \n  \"amount\": \"{{ $('Parse Last Trade').item.json.memo.amoutOut }}\"\n} ",
        "operation": "executeAsDelegator",
        "additionalFields": {
          "memo": "=Range Trade Approve for {{ $('Swap Configs').item.json.amountDCA }} {{ $('Swap Configs').item.json.token0 }}"
        },
        "contractMethodId": "fdd46f58-7871-42e8-870a-cd8736b0d8a3",
        "delegatorWalletAddress": "={{ $('Swap Configs').item.json.delegator }}"
      },
      "credentials": {
        "oneShotOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "72ef73ef-0ebb-4764-81f7-dd5e89628c98",
      "name": "Give Approval to Router (Buy)",
      "type": "n8n-nodes-1shot.oneShotSynch",
      "onError": "continueRegularOutput",
      "position": [
        1088,
        992
      ],
      "parameters": {
        "params": "={\n  \"spender\": \"{{ $('Swap Configs').item.json.router }}\", \n  \"value\": \"{{ $('Swap Configs').item.json.amountDCA }}\"\n} ",
        "operation": "executeAsDelegator",
        "additionalFields": {
          "memo": "=Range Trade Approve for {{ $('Swap Configs').item.json.amountDCA }} {{ $('Swap Configs').item.json.token1 }}"
        },
        "contractMethodId": "e35f72f2-6b5b-43af-9382-60458448f32c",
        "delegatorWalletAddress": "={{ $('Swap Configs').item.json.delegator }}"
      },
      "credentials": {
        "oneShotOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "c50fb5a5-3564-4899-8a87-d3028ad38dc1",
      "name": "Buy ETH",
      "type": "n8n-nodes-1shot.oneShotSynch",
      "onError": "continueRegularOutput",
      "position": [
        1312,
        912
      ],
      "parameters": {
        "params": "={\n\"params\": {\n\"tokenIn\": \"{{ $('Swap Configs').item.json.token1 }}\",\n\"tokenOut\": \"{{ $('Swap Configs').item.json.token0 }}\",\n\"fee\": \"{{ $('Swap Configs').item.json.fee }}\",\n\"recipient\": \"{{ $('Swap Configs').item.json.delegator }}\",\n\"amountIn\": \"{{ $('Swap Configs').item.json.amountDCA }}\",\n\"amountOutMinimum\": \"{{ Math.ceil(parseFloat($('Get Buy Qoute').item.json.result.decodedData[0]) * ( 1 - parseFloat($('Swap Configs').item.json.slippage))) }}\",\n\"sqrtPriceLimitX96\": \"0\"\n}\n}",
        "operation": "executeAsDelegator",
        "additionalFields": {
          "memo": "={\"rangeTrade\": \"buy\", \"amountIn\": {{ $('Swap Configs').item.json.amountDCA }}, \"amoutOut\": {{ $('Get Buy Qoute').item.json.result.decodedData[0] }}, \"TWAP\": {{ $('Calculate TWAP').item.json.twap }}}"
        },
        "contractMethodId": "ba3cf19f-52cf-4104-88e8-d9be40e23fe2",
        "delegatorWalletAddress": "={{ $('Swap Configs').item.json.delegator }}"
      },
      "credentials": {
        "oneShotOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "2a80d667-b2ec-43a0-b9ff-780f978ddaa2",
      "name": "Sell ETH",
      "type": "n8n-nodes-1shot.oneShotSynch",
      "onError": "continueRegularOutput",
      "position": [
        1312,
        480
      ],
      "parameters": {
        "params": "={\n\"params\": {\n\"tokenIn\": \"{{ $('Swap Configs').item.json.token0 }}\",\n\"tokenOut\": \"{{ $('Swap Configs').item.json.token1 }}\",\n\"fee\": \"{{ $('Swap Configs').item.json.fee }}\",\n\"recipient\": \"{{ $('Swap Configs').item.json.delegator }}\",\n\"amountIn\": \"{{ $('Parse Last Trade').item.json.memo.amoutOut }}\",\n\"amountOutMinimum\": \"{{ Math.ceil(parseFloat($('Get Sell Qoute').item.json.result.decodedData[0]) * ( 1 - parseFloat($('Swap Configs').item.json.slippage))) }}\",\n\"sqrtPriceLimitX96\": \"0\"\n}\n}",
        "operation": "executeAsDelegator",
        "additionalFields": {
          "memo": "={\"rangeTrade\": \"sell\", \"amountIn\": {{ $('Parse Last Trade').item.json.memo.amoutOut }}, \"amoutOut\": {{ $('Get Sell Qoute').item.json.result.decodedData[0] }}, \"TWAP\": {{ $('Calculate TWAP').item.json.twap }}}"
        },
        "contractMethodId": "ba3cf19f-52cf-4104-88e8-d9be40e23fe2",
        "delegatorWalletAddress": "={{ $('Swap Configs').item.json.delegator }}"
      },
      "credentials": {
        "oneShotOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "564d6c6f-195b-4743-a44f-818c8a409ceb",
      "name": "Success Details (Sell)",
      "type": "n8n-nodes-base.telegram",
      "position": [
        1760,
        432
      ],
      "parameters": {
        "text": "=\u2705 Swapped `{{ $('Parse Last Trade').item.json.memo.amoutOut }}` `{{ $('Swap Configs').item.json.token0 }}` for `{{ $('Get Sell Qoute').item.json.result.decodedData[0] }}` `{{ $('Swap Configs').item.json.token1 }}`. \n\nThe `{{ $('Swap Configs').item.json.secondsAgo }}` second TWAP was `{{ $('Calculate TWAP').item.json.twap }}`. Your tx hash is `{{ $('Sell ETH').item.json.transactionHash }}`.\n\nYou have `{{ $json.response }}` of token `{{ $('Swap Configs').item.json.token0 }}` left. ",
        "chatId": "={{ $('Swap Configs').item.json.telegramChatId }}",
        "additionalFields": {}
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "5caf1b8d-514f-490a-affb-1bf2e5dd1f83",
      "name": "Success Details (Buy)",
      "type": "n8n-nodes-base.telegram",
      "position": [
        1760,
        864
      ],
      "parameters": {
        "text": "=\u2705 Swapped `{{ $('Swap Configs').item.json.amountDCA }}` `{{ $('Swap Configs').item.json.token0 }}` for `{{ $('Get Buy Qoute').item.json.result.decodedData[0] }}` `{{ $('Swap Configs').item.json.token1 }}`. \n\nThe `{{ $('Swap Configs').item.json.secondsAgo }}` second TWAP was `{{ $('Calculate TWAP').item.json.twap }}`. Your tx hash is `{{ $('Buy ETH').item.json.transactionHash }}`.\n\nYou have `{{ $json.response }}` of token `{{ $('Swap Configs').item.json.token0 }}` left. ",
        "chatId": "={{ $('Swap Configs').item.json.telegramChatId }}",
        "additionalFields": {}
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "fd79c4dc-6e89-4335-97c2-040371411b6f",
      "name": "Buy Failure Notification",
      "type": "n8n-nodes-base.telegram",
      "position": [
        1536,
        1088
      ],
      "parameters": {
        "text": "=\u274c Swap Failed",
        "chatId": "={{ $('Swap Configs').item.json.telegramChatId }}",
        "additionalFields": {}
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "e0d63f88-2224-42ad-ac1d-c04ef8ff356c",
      "name": "Sell Failure Notification",
      "type": "n8n-nodes-base.telegram",
      "position": [
        1536,
        656
      ],
      "parameters": {
        "text": "=\u274c Swap Failed",
        "chatId": "={{ $('Swap Configs').item.json.telegramChatId }}",
        "additionalFields": {}
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "e031ff10-6e4c-46aa-b86e-5d5f014e50c3",
      "name": "Check New Funds",
      "type": "n8n-nodes-1shot.oneShot",
      "position": [
        1536,
        432
      ],
      "parameters": {
        "params": "={\n  \"account\": \"{{ $('Swap Configs').item.json.delegator }}\"\n}",
        "operation": "read",
        "contractMethodId": "bfc44279-e20b-4452-b809-d422134700b3"
      },
      "credentials": {
        "oneShotOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "06a9d916-cbe3-437f-9b99-5537205bac93",
      "name": "Get Buy Qoute",
      "type": "n8n-nodes-1shot.oneShot",
      "position": [
        416,
        1088
      ],
      "parameters": {
        "params": "={\n  \"params\": \n    {\n  \"tokenIn\": \"{{ $('Swap Configs').item.json.token1 }}\",\n  \"tokenOut\": \"{{ $('Swap Configs').item.json.token0 }}\",\n  \"amountIn\": \"{{ $('Swap Configs').item.json.amountDCA }}\",\n  \"fee\": \"{{ $('Swap Configs').item.json.fee }}\",\n  \"sqrtPriceLimitX96\": \"0\"\n    }\n} ",
        "operation": "simulate",
        "contractMethodId": "48b96850-aea3-4faf-87d5-4e67f2baee89"
      },
      "credentials": {
        "oneShotOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "b93698b5-b489-409a-8ca9-b645577efc0d",
      "name": "Get Sell Qoute",
      "type": "n8n-nodes-1shot.oneShot",
      "position": [
        416,
        656
      ],
      "parameters": {
        "params": "={\n  \"params\": \n    {\n  \"tokenIn\": \"{{ $('Swap Configs').item.json.token0 }}\",\n  \"tokenOut\": \"{{ $('Swap Configs').item.json.token1 }}\",\n  \"amountIn\": \"{{ $('Parse Last Trade').item.json.memo.amoutOut }}\",\n  \"fee\": \"{{ $('Swap Configs').item.json.fee }}\",\n  \"sqrtPriceLimitX96\": \"0\"\n    }\n} ",
        "operation": "simulate",
        "contractMethodId": "48b96850-aea3-4faf-87d5-4e67f2baee89"
      },
      "credentials": {
        "oneShotOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "436a7bdb-9611-49bf-bf13-8205bae23985",
      "name": "Get Last Trade Type",
      "type": "n8n-nodes-1shot.oneShot",
      "position": [
        -480,
        864
      ],
      "parameters": {
        "memo": "rangeTrade",
        "status": "Completed",
        "chainId": 42161,
        "pageSize": 1,
        "resource": "transactions",
        "createdAfter": 1758165556,
        "createdBefore": 0
      },
      "credentials": {
        "oneShotOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1,
      "alwaysOutputData": true
    },
    {
      "id": "5011693c-edc5-435b-adc0-afbd6e837d86",
      "name": "Parse Last Trade",
      "type": "n8n-nodes-base.code",
      "position": [
        -256,
        864
      ],
      "parameters": {
        "jsCode": "try {\n  const memo = JSON.parse($input.first().json.memo)\n  console.log(\"memo:\", memo)\n  $input.first().json.memo = memo; \n} catch {\n  console.log(\"no memo\")\n}\n\nreturn $input.all();"
      },
      "typeVersion": 2
    },
    {
      "id": "2106c64e-4e47-4929-a8b0-8257eea2c513",
      "name": "Don't Repeat Buys",
      "type": "n8n-nodes-base.if",
      "position": [
        192,
        1088
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "or",
          "conditions": [
            {
              "id": "8f1a4e9c-21d1-499b-8221-318875775842",
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.memo.rangeTrade }}",
              "rightValue": "sell"
            },
            {
              "id": "7bee6833-7f7e-442e-aef2-99ccb83e34bb",
              "operator": {
                "type": "object",
                "operation": "notExists",
                "singleValue": true
              },
              "leftValue": "={{ $json.memo }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.2,
      "alwaysOutputData": true
    },
    {
      "id": "ca115115-772c-41fa-8f6e-443a54f85119",
      "name": "Don't Repeat Sells",
      "type": "n8n-nodes-base.if",
      "position": [
        192,
        656
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "8f1a4e9c-21d1-499b-8221-318875775842",
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.memo.rangeTrade }}",
              "rightValue": "buy"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "66f7bee5-ac95-4af1-aebb-370eb07ab418",
      "name": "List wallets",
      "type": "n8n-nodes-1shot.oneShot",
      "position": [
        -464,
        1872
      ],
      "parameters": {
        "chainId": 42161,
        "resource": "wallets"
      },
      "credentials": {
        "oneShotOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1,
      "alwaysOutputData": true
    },
    {
      "id": "966f9e36-7cb2-4fd3-922f-12aa9948c7c8",
      "name": "When clicking \u2018Execute workflow\u2019",
      "type": "n8n-nodes-base.manualTrigger",
      "position": [
        -688,
        1872
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "a7762d6f-cba4-440d-b395-c8bf6d425f63",
      "name": "Assure WETH Methods",
      "type": "n8n-nodes-1shot.oneShot",
      "position": [
        432,
        1488
      ],
      "parameters": {
        "chainId": 42161,
        "promptId": "a9bac97d-cf4d-4de0-8523-bad09b6b507d",
        "walletId": "={{ $('Get Wallet ID').item.json.walletId }}",
        "operation": "assureContractMethodsFromPrompt",
        "contractAddress": "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1"
      },
      "credentials": {
        "oneShotOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "b98cde01-6b97-4fd8-af01-738cbbd7d304",
      "name": "Assure USDC Methods",
      "type": "n8n-nodes-1shot.oneShot",
      "position": [
        432,
        1872
      ],
      "parameters": {
        "chainId": 42161,
        "promptId": "7d92d5db-99e3-4b1e-9cfe-74e80eeb842b",
        "walletId": "={{ $('Get Wallet ID').item.json.walletId }}",
        "operation": "assureContractMethodsFromPrompt",
        "contractAddress": "0xaf88d065e77c8cC2239327C5EDb3A432268e5831"
      },
      "credentials": {
        "oneShotOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "618bce69-c48d-4310-9f10-ae5e9b27eaa7",
      "name": "Assure QuoterV2 Methods",
      "type": "n8n-nodes-1shot.oneShot",
      "position": [
        432,
        2256
      ],
      "parameters": {
        "chainId": 42161,
        "promptId": "e439252a-a9e9-43d8-bec8-f4ce3391c49d",
        "walletId": "={{ $('Get Wallet ID').item.json.walletId }}",
        "operation": "assureContractMethodsFromPrompt",
        "contractAddress": "0x61fFE014bA17989E743c5F6cB21bF9697530B21e"
      },
      "credentials": {
        "oneShotOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "ffaa84b7-baa9-40d5-afb8-31e4cbdd1015",
      "name": "Assure SwapRouter02 Methods",
      "type": "n8n-nodes-1shot.oneShot",
      "position": [
        432,
        1680
      ],
      "parameters": {
        "chainId": 42161,
        "promptId": "4fa14406-c913-4642-991d-e310ff138a8a",
        "walletId": "={{ $('Get Wallet ID').item.json.walletId }}",
        "operation": "assureContractMethodsFromPrompt",
        "contractAddress": "0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45"
      },
      "credentials": {
        "oneShotOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "dab49392-f4dc-4640-9d60-f787fcb00245",
      "name": "Assure ETH/USDC Pool Methods",
      "type": "n8n-nodes-1shot.oneShot",
      "position": [
        432,
        2064
      ],
      "parameters": {
        "chainId": 42161,
        "promptId": "9a97c00a-797a-4dc9-9a3f-e32596cf9301",
        "walletId": "={{ $('Get Wallet ID').item.json.walletId }}",
        "operation": "assureContractMethodsFromPrompt",
        "contractAddress": "0xC6962004f452bE9203591991D15f6b388e09E8D0"
      },
      "credentials": {
        "oneShotOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "d06c5736-9e53-4613-a17c-cf1a1467085a",
      "name": "If",
      "type": "n8n-nodes-base.if",
      "position": [
        -240,
        1872
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "b2f25fac-5a5d-4963-b1f6-05c8dfce25a6",
              "operator": {
                "type": "string",
                "operation": "exists",
                "singleValue": true
              },
              "leftValue": "={{ $json.id }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "c679feaf-f1db-4391-9e98-75c0895046db",
      "name": "Create wallet",
      "type": "n8n-nodes-1shot.oneShot",
      "position": [
        -16,
        1952
      ],
      "parameters": {
        "name": "=\"{{ $today }}\"",
        "chainId": 42161,
        "resource": "wallets",
        "operation": "create",
        "description": "Range Trading Wallet"
      },
      "credentials": {
        "oneShotOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "324b3986-de38-43b6-8341-bf600094f555",
      "name": "Get Wallet ID",
      "type": "n8n-nodes-base.code",
      "position": [
        208,
        1872
      ],
      "parameters": {
        "jsCode": "let walletId; \ntry {\n  walletId = $input.first().json.id;\n} catch {\n  walletId = $input.first().json.id;\n}\n\n$input.first().json.walletId = walletId; \n\nreturn $input.all();"
      },
      "typeVersion": 2
    },
    {
      "id": "5239ceb0-6c0d-42a4-ab6b-1a48292bf412",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        160,
        848
      ],
      "parameters": {
        "width": 480,
        "content": "## First Trade Setup\n\nThis workflow will attempt to perform a WETH buy as its first trade. To change it so the first trade is a sell from WETH to USDC, remove the  condition `{{ $json.memo }} does not exist` from `Don't Repeat Buys` and add it to `Don't Repeat Sells`. "
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "a8ed007b-44d0-4da5-a0f0-f45b53d9cb36",
  "connections": {
    "If": {
      "main": [
        [
          {
            "node": "Get Wallet ID",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Create wallet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Buy ETH": {
      "main": [
        [
          {
            "node": "Check Remaining Funds",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Buy Failure Notification",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Sell ETH": {
      "main": [
        [
          {
            "node": "Check New Funds",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Sell Failure Notification",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Confirm Buy": {
      "main": [
        [
          {
            "node": "Buy or Cancel?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Confirm Sell": {
      "main": [
        [
          {
            "node": "Sell or Cancel?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "List wallets": {
      "main": [
        [
          {
            "node": "If",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Swap Configs": {
      "main": [
        [
          {
            "node": "Fetch Pool TWA Observations",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create wallet": {
      "main": [
        [
          {
            "node": "Get Wallet ID",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Buy Qoute": {
      "main": [
        [
          {
            "node": "Confirm Buy",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Wallet ID": {
      "main": [
        [
          {
            "node": "Assure WETH Methods",
            "type": "main",
            "index": 0
          },
          {
            "node": "Assure SwapRouter02 Methods",
            "type": "main",
            "index": 0
          },
          {
            "node": "Assure USDC Methods",
            "type": "main",
            "index": 0
          },
          {
            "node": "Assure ETH/USDC Pool Methods",
            "type": "main",
            "index": 0
          },
          {
            "node": "Assure QuoterV2 Methods",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Buy or Cancel?": {
      "main": [
        [
          {
            "node": "Give Approval to Router (Buy)",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Purchase Cancelled",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Calculate TWAP": {
      "main": [
        [
          {
            "node": "Get Last Trade Type",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Sell Qoute": {
      "main": [
        [
          {
            "node": "Confirm Sell",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check New Funds": {
      "main": [
        [
          {
            "node": "Success Details (Sell)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Sell or Cancel?": {
      "main": [
        [
          {
            "node": "Give Approval to Router (Sell)",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Sell Cancelled",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Last Trade": {
      "main": [
        [
          {
            "node": "Buy, Sell or Hold",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Schedule Trigger": {
      "main": [
        [
          {
            "node": "Swap Configs",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Buy, Sell or Hold": {
      "main": [
        [
          {
            "node": "Don't Repeat Sells",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Don't Repeat Buys",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Don't Repeat Buys": {
      "main": [
        [
          {
            "node": "Get Buy Qoute",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Don't Repeat Sells": {
      "main": [
        [
          {
            "node": "Get Sell Qoute",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Last Trade Type": {
      "main": [
        [
          {
            "node": "Parse Last Trade",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check Remaining Funds": {
      "main": [
        [
          {
            "node": "Success Details (Buy)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Pool TWA Observations": {
      "main": [
        [
          {
            "node": "Calculate TWAP",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Give Approval to Router (Buy)": {
      "main": [
        [
          {
            "node": "Buy ETH",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Buy Failure Notification",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Give Approval to Router (Sell)": {
      "main": [
        [
          {
            "node": "Sell ETH",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Sell Failure Notification",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "When clicking \u2018Execute workflow\u2019": {
      "main": [
        [
          {
            "node": "List wallets",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}