{"id":23107738,"url":"https://github.com/kleros/curate-telegram-bot","last_synced_at":"2025-04-03T22:44:00.889Z","repository":{"id":86709193,"uuid":"563889825","full_name":"kleros/curate-telegram-bot","owner":"kleros","description":"Tweeter bot for activity on Kleros Curate.","archived":false,"fork":false,"pushed_at":"2024-06-12T12:12:18.000Z","size":53,"stargazers_count":0,"open_issues_count":1,"forks_count":2,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-22T16:51:04.854Z","etag":null,"topics":["backend","curated-list","curated-lists-v1","notifications"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kleros.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-11-09T14:53:00.000Z","updated_at":"2024-07-31T17:34:00.000Z","dependencies_parsed_at":null,"dependency_job_id":"fb77e618-d141-4ed0-a96e-042df6cab3d2","html_url":"https://github.com/kleros/curate-telegram-bot","commit_stats":null,"previous_names":["kleros/curate-telegram-bot"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kleros%2Fcurate-telegram-bot","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kleros%2Fcurate-telegram-bot/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kleros%2Fcurate-telegram-bot/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kleros%2Fcurate-telegram-bot/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kleros","download_url":"https://codeload.github.com/kleros/curate-telegram-bot/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247092373,"owners_count":20882217,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["backend","curated-list","curated-lists-v1","notifications"],"created_at":"2024-12-17T01:15:56.051Z","updated_at":"2025-04-03T22:44:00.870Z","avatar_url":"https://github.com/kleros.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cb style=\"font-size: 32px;\"\u003eCurate Twitter Bot \u003c/b\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://standardjs.com\"\u003e\u003cimg src=\"https://img.shields.io/badge/code_style-standard-brightgreen.svg\" alt=\"JavaScript Style Guide\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://conventionalcommits.org\"\u003e\u003cimg src=\"https://img.shields.io/badge/Conventional%20Commits-1.0.0-yellow.svg\" alt=\"Conventional Commits\"\u003e\u003c/a\u003e\n  \u003ca href=\"http://commitizen.github.io/cz-cli/\"\u003e\u003cimg src=\"https://img.shields.io/badge/commitizen-friendly-brightgreen.svg\" alt=\"Commitizen Friendly\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/prettier/prettier\"\u003e\u003cimg src=\"https://img.shields.io/badge/styled_with-prettier-ff69b4.svg\" alt=\"Styled with Prettier\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\nWatch and tweet about things happening on Kleros Curate.\n\n## Prerequisites\n\n- NodeJS version 14\n\n## Get Started\n\n1.  Clone this repo.\n2.  Duplicate `.env.example`, rename it to `.env.\u003cnetworkName\u003e` and fill in the environment variables.\n3.  Run `yarn` to install dependencies.\n4.  Build it. `yarn build`\n\n\u003e This is a script that will notify for everything that happened within a period. To do so, run `yarn start`.\n\nYou can run this script as it is, or with cron. There are also `loop:\u003cnetworkName\u003e` yarn scripts to run this process automatically with pm2. Adding them is straightforward, just create a new `.env.\u003cnetworkName\u003e` and create the loop script for it.\n\nThis is an example of how to set this loop with pm2:\n\n`pm2 start yarn --interpreter bash --name ctb-xdai -- loop:xdai`\n\n## Architecture\n\nThis bot purpose is to minimize RPC calls. The previous way of obtaining events was to create many event listeners for every GTCR and LightGTCR contract. Instead, this bot relies on subgraphs to obtain event information, with entities that store timestamps in some capacity.\n\nThis bot in particular needs a database, in order to remember twitter threads belonging to specific items.\n\n## Pipeline\n\n1. Obtain previous timestamp, and store the timestamp corresponding to the present.\n2. Send a complex query to the subgraph. For each entity type, `where` clauses filter to only include entities that are relevant from `start` to `end`, which are the two timestamps that define the window of time we're interested in.\n3. As each query fetches custom information, each query has all results go through a custom method, to parse the results into an standarized form that the rest of the program can consume, called `Events` (they're not actual EVM events)\n4. These `Events` are sorted according to their timestamp.\n5. Each `Event` is now handled. It goes through a function that acts as a router, and directs each event type to be handled on its own customized way.\n\n## Curate Twitter Bot specifics\n\nThis bot uses a database to remember the last tweet that was posted on an specific item, in order to reply to it and form threads.\n\nIt also needs an RPC connection in order to obtain some information that is not available through the subgraph, such as some `metaEvidenceURIs`, and some amounts. But, RPC calls are only made to obtain info per handling, so it's considerably cheaper. (Currently, maximum 2 RPC calls per tweet).\n\n## How to migrate a bot to use this architecture\n\nTLDR: update subgraph, build queries, parsers and handlers.\n\n### Figure out what needs to be handled\n\nAnalyze the current bot, and make a list of everything that needs to be handled. Check out how it's obtaining this information.\n\n### Build the subgraph queries\n\nGo to a subgraph that is indexing the relevant contract. Build a subgraph if it doesn't exist yet. If something cannot be queried, modify the subgraph to expose this information to the queries. This usually entails creating entities that map 1:1 to events, or adding some timestamps to existing entities.\n\nIn this project, these queries are strings inside the `getEvents` function in `get-events.ts`. Note timestamps matter.\n\nYou may want to use an existing library to make these queries, it may have been a mistake to write the query strings manually and fetch with `node-fetch`.\n\n### Build the parsers\n\nEach query will net a result that needs to be parsed into an standarized format for the handlers to consume. This is done because it makes the rest of the bot straightforward and less prone to bugs.\n\nFor example, in this bot, there's a `CurateEvent` interface that all parsers return.\n\n### Build the handlers\n\nThis is completely dependant on the purpose of the bot. This bot purpose is making tweets, so all the handlers do is tweet and store the tweet id somewhere.\n\nA bot could do other things as well: call intermediate transactions, such as reward withdrawals, advancing a phase or executing a request. It could send telegram messages, send mails, etc.\n\n# Is this worth it?\n\n## Pros\n\n- This architecture looks more reliable, the pipeline is more modular.\n- It's not vulnerable to RPC degrading their service (rate limits, timeouts...).\n\n## Cons\n\n- Reliant on the subgraph. If TheGraph is bugged, it will affect it. If the subgraph is not keeping up, this bot won't keep up either.\n- Parsers are error prone, especially if there's a lot of information and and there are many parsers. I had to do a lot of manual debugging and I'm still not sure I found all of them.\n- Usually entails indexing new information on the subgraph.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkleros%2Fcurate-telegram-bot","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkleros%2Fcurate-telegram-bot","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkleros%2Fcurate-telegram-bot/lists"}