{"id":43725831,"url":"https://github.com/aboutcircles/group-tms","last_synced_at":"2026-02-05T09:04:10.753Z","repository":{"id":312891304,"uuid":"1033451335","full_name":"aboutcircles/group-tms","owner":"aboutcircles","description":"Maintains the trust relations of a circles group based on their conditions","archived":false,"fork":false,"pushed_at":"2026-01-27T13:50:13.000Z","size":219,"stargazers_count":0,"open_issues_count":0,"forks_count":1,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-01-27T21:37:50.647Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"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/aboutcircles.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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-08-06T20:48:44.000Z","updated_at":"2026-01-27T09:09:35.000Z","dependencies_parsed_at":"2025-09-02T17:38:40.330Z","dependency_job_id":"4694f43e-ba75-4343-b6a8-8c8557292754","html_url":"https://github.com/aboutcircles/group-tms","commit_stats":null,"previous_names":["aboutcircles/group-tms"],"tags_count":19,"template":false,"template_full_name":null,"purl":"pkg:github/aboutcircles/group-tms","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aboutcircles%2Fgroup-tms","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aboutcircles%2Fgroup-tms/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aboutcircles%2Fgroup-tms/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aboutcircles%2Fgroup-tms/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/aboutcircles","download_url":"https://codeload.github.com/aboutcircles/group-tms/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aboutcircles%2Fgroup-tms/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29117916,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-05T05:31:32.482Z","status":"ssl_error","status_checked_at":"2026-02-05T05:31:29.075Z","response_time":65,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":[],"created_at":"2026-02-05T09:04:10.190Z","updated_at":"2026-02-05T09:04:10.745Z","avatar_url":"https://github.com/aboutcircles.png","language":"TypeScript","funding_links":[],"categories":["Developer Tools"],"sub_categories":["Developer Demos"],"readme":"# Circles Group Trust Management Service\n\nThree specialized services for Circles protocol trust management:\n\n## CRC Backers App\n* Scans Circles **BackingCompleted**/**BackingInitiated** events\n* Filters out blacklisted backers\n* **Trusts** valid new backers into a group in batches of 50\n* Reconciles initiated-but-not-completed processes (resets CowSwap order or creates LBP)\n* Optionally notifies Slack when something looks stuck\n* Runs once a minute\n* Supports dry-run mode to exercise the logic without submitting Safe transactions\n\n## GP CRC App\n* Scans Circles **RegisterHuman** events for newly registered avatars\n* Cross-checks avatars against the blacklist service and Metri Safe GraphQL data\n* Trusts eligible avatars into the configured group in batches (default 10)\n* Supports dry-run mode and Slack notifications\n* Runs every 10 minutes\n\n## OIC App  \n* Monitors affiliate group changes and trust relationships\n* Reconciles trust between MetaOrg trustees and affiliates\n* Supports dry-run mode for testing\n* Incremental scanning with configurable refresh intervals\n* Batch processing for efficient trust operations\n\n## Requirements\n\n* Node.js **≥ 24**\n* A Circles RPC endpoint (e.g. https://rpc.aboutcircles.com/)\n* A private key that is the **group service** for the backers group\n\n## Quick start\n\n### Local Development\n\n```bash\n# 1) Install\nnpm install\n\n# 2) Configure\ntouch .env   # Check the values below and fill in your .env file\n\n# 3) Run\n\n# Option A: build then run with .env\nnpx tsc \u0026\u0026 node --env-file=.env dist/src/main.js\n\n# Option B: use scripts (also load .env)\nnpm run start:crc-backers\nnpm run start:gp-crc\nnpm run start:oic\nnpm run start:all\n```\n\n## Configuration (.env)\n\n### CRC Backers App Configuration\n\n```dotenv\n# RPC \u0026 addresses\nRPC_URL=https://rpc.aboutcircles.com/\nBACKING_FACTORY_ADDRESS=0xeced91232c609a42f6016860e8223b8aecaa7bd0\nBACKERS_GROUP_ADDRESS=0x1ACA75e38263c79d9D4F10dF0635cc6FCfe6F026\n\n# Safe execution\nCRC_BACKERS_SAFE_ADDRESS=                # Safe set as the group's service\nCRC_BACKERS_SAFE_SIGNER_PRIVATE_KEY=     # Private key for one Safe signer\n\n# Blacklist service\nBLACKLISTING_SERVICE_URL=https://squid-app-3gxnl.ondigitalocean.app/aboutcircles-advanced-analytics2/bot-analytics/classify\n\n# Scan window / timing\nSTART_AT_BLOCK=39743285\nCONFIRMATION_BLOCKS=2\nEXPECTED_SECONDS_TILL_COMPLETION=60\n\n# Notifications\nSLACK_WEBHOOK_URL=\n\n# Logging\nVERBOSE_LOGGING=1     # any truthy value enables debug/table\n\n# Operation mode\nDRY_RUN=0             # Set to \"1\" to skip Safe transactions and only log actions\n```\n\n### GP CRC App Configuration\n\n```dotenv\n# RPC \u0026 addresses\nRPC_URL=https://rpc.aboutcircles.com/\nGP_CRC_GROUP_ADDRESS=0xb629a1e86f3efada0f87c83494da8cc34c3f84ef\n\n# Safe execution (required unless dry run)\nGP_CRC_SAFE_ADDRESS=                     # Safe that controls the group's service role\nGP_CRC_SAFE_SIGNER_PRIVATE_KEY=          # Private key for a Safe signer\n\n# Metri Safe GraphQL\nMETRI_SAFE_GRAPHQL_URL=https://gnosis-e702590.dedicated.hyperindex.xyz/v1/graphql\nMETRI_SAFE_API_KEY=                      \n\n# Blacklist service\nBLACKLISTING_SERVICE_URL=https://squid-app-3gxnl.ondigitalocean.app/aboutcircles-advanced-analytics2/bot-analytics/classify\n\n# Scan window / timing\nSTART_AT_BLOCK=31734312\nCONFIRMATION_BLOCKS=10\nDRY_RUN=0                                 # Set to \"1\" to skip transactions\n\n# Notifications\nSLACK_WEBHOOK_URL=\n\n# Logging\nVERBOSE_LOGGING=1\n```\n\n### OIC App Configuration\n\n```dotenv\n# RPC \u0026 addresses\nRPC_URL=https://rpc.aboutcircles.com/\nOIC_GROUP_ADDRESS=0x4E2564e5df6C1Fb10C1A018538de36E4D5844DE5\nOIC_META_ORG_ADDRESS=                    # REQUIRED - Meta organization address\nAFFILIATE_REGISTRY_ADDRESS=0xca8222e780d046707083f51377b5fd85e2866014\n\n# Safe execution (required unless dry run)\nOIC_SAFE_ADDRESS=                        # Safe that controls the OIC group service role\nOIC_SAFE_SIGNER_PRIVATE_KEY=             # Private key for one Safe signer\n\n# Scan window / timing\nSTART_AT_BLOCK=41734312\nCONFIRMATION_BLOCKS=10\nREFRESH_INTERVAL_SEC=60\n\n# Operation mode\nDRY_RUN=0                               # Set to \"1\" for dry run mode (no actual transactions)\n\n# Notifications\nSLACK_WEBHOOK_URL=\n\n# Logging\nVERBOSE_LOGGING=1     # any truthy value enables debug/table\n```\n\n### Router TMS Configuration\n\n```dotenv\n# RPC \u0026 addresses\nRPC_URL=https://rpc.aboutcircles.com/\nROUTER_ADDRESS=0xdc287474114cc0551a81ddc2eb51783fbf34802f\nROUTER_BASE_GROUP_ADDRESS=0x1ACA75e38263c79d9D4F10dF0635cc6FCfe6F026\n\n# Safe execution (required unless dry run)\nROUTER_SAFE_ADDRESS=                       # Safe that controls the router's trusted executor\nROUTER_SAFE_SIGNER_PRIVATE_KEY=            # Private key for one Safe signer\n\n# Scan window / timing\nROUTER_POLL_INTERVAL_MS=1800000\nROUTER_ENABLE_BATCH_SIZE=50\nROUTER_FETCH_PAGE_SIZE=2000\nROUTER_BLACKLIST_CHUNK_SIZE=1000\n\n# Operation mode\nDRY_RUN=0                                  # Set to \"1\" to log actions without enabling routing\n\n# Notifications\nSLACK_WEBHOOK_URL=\n\n# Logging\nVERBOSE_LOGGING=1\n```\n\n### Gnosis Group App Configuration\n\n```dotenv\n# RPC \u0026 addresses\nRPC_URL=https://rpc.aboutcircles.com/\n\n# Safe execution\nGNOSIS_GROUP_SAFE_ADDRESS=                # Safe that owns the group service role\nGNOSIS_GROUP_SAFE_SIGNER_PRIVATE_KEY=     # Private key of a 1/n Safe signer \n\n# External services\nBLACKLISTING_SERVICE_URL=https://squid-app-3gxnl.ondigitalocean.app/aboutcircles-advanced-analytics2/bot-analytics/classify\nGNOSIS_GROUP_SCORING_URL=https://squid-app-3gxnl.ondigitalocean.app/aboutcircles-advanced-analytics2/scoring/relative_trustscore/batch\n\n# Operation mode\nGNOSIS_GROUP_DRY_RUN=0                 # Set to \"1\" to skip blacklist \u0026 scoring requests\n\n# Notifications\nGNOSIS_GROUP_SLACK_WEBHOOK_URL=        # Optional override; falls back to SLACK_WEBHOOK_URL\nSLACK_WEBHOOK_URL=\n\n# Logging\nVERBOSE_LOGGING=1\n```\n\n## What each app does\n\n### CRC Backers App\n\n* Uses a reorg buffer (`CONFIRMATION_BLOCKS`) from chain head\n * From `START_AT_BLOCK` → head:\n   * Pulls **BackingCompleted**, filters via blacklist service, dedupes already-trusted backers, and calls\n     `trustBatchWithConditions(group, addresses, expiry=max uint96)` in batches of 50\n   * Finds **BackingInitiated** without matching completion:\n       * If **past deadline** (initiated timestamp + 24h): try `createLBP()`; notify Slack on inconsistent/insufficient states\n       * If **before deadline**: try `resetCowswapOrder()` when valid; if already settled, attempt LBP creation\n* Logs summaries by default; `VERBOSE_LOGGING` prints debug and tables\n* `DRY_RUN=1` skips Safe transactions and only logs what would have been executed\n* Keeps running: initial run, then every minute\n\n### GP CRC App\n\n* Walks block ranges from `START_AT_BLOCK` to the safe head (`head - CONFIRMATION_BLOCKS`) and fetches `RegisterHuman` events via `circles_events`\n* Deduplicates avatars, checks them against the blacklist in chunks, and verifies a configured Metri Pay safe exists\n* Skips avatars without safes or already trusted in `GP_CRC_GROUP_ADDRESS`; trusts the rest in batches (default 10) with retry logic\n* Supports dry-run logging, verbose logging, and optional Slack notifications for start, shutdown, and errors\n* Runs every 10 minutes\n\n### OIC App\n\n* Monitors **AffiliateGroupChanged** events for trust relationship updates\n* Calculates desired trustees by intersecting:\n  * Addresses trusted by any MetaOrg trustee\n  * Current affiliates in the registry\n* Performs batch trust/untrust operations to reconcile differences\n* Supports incremental scanning to avoid re-processing old events\n* Can run in dry-run mode for testing without making transactions\n* Configurable refresh intervals and batch sizes\n\n## Operational notes\n\n### General\n* Make sure the configured Safe owns the appropriate **service** roles and that the signer key belongs to a Safe owner\n* Slack notifications are best-effort; failures may throw and crash the process\n* Services are designed to fail loudly on errors and require a supervisor to monitor and restart\n* Replace placeholder values (`your_private_key_here`, etc.) with actual values in Docker commands\n\n### CRC Backers App\n* `CRC_BACKERS_SAFE_ADDRESS` must be the backers group's **service** and the signer key must belong to that Safe\n* If you change the factory address, bump `START_AT_BLOCK` accordingly\n* Service is stateless and does not store data between runs\n\n### GP CRC App\n* `GP_CRC_GROUP_ADDRESS` must match the group you intend to automatically trust new avatars into\n* Provide `GP_CRC_SAFE_ADDRESS` plus `GP_CRC_SAFE_SIGNER_PRIVATE_KEY` unless `DRY_RUN=1`\n* `METRI_SAFE_GRAPHQL_URL` is required; add `METRI_SAFE_API_KEY` if the endpoint is restricted\n* `DRY_RUN=1` will log intended trust batches without submitting transactions\n\n### OIC App  \n* `OIC_SAFE_ADDRESS` must be the OIC group's **service**; the signer key must belong to that Safe\n* `OIC_META_ORG_ADDRESS` is required - this is the MetaOrg whose trustees will be monitored\n* Use `DRY_RUN=1` for testing without making actual blockchain transactions\n* Service maintains incremental state to avoid re-processing old events\n\n### Gnosis Group App\n* Fetches registered human avatars and filters out blacklisted addresses\n* Calls a relative trust scoring service to rank avatars by configured targets\n* Uses a Safe for execution; set `GNOSIS_GROUP_SAFE_ADDRESS` plus `GNOSIS_GROUP_SAFE_SIGNER_PRIVATE_KEY` for a 1/n Safe owner\n* `GNOSIS_GROUP_DRY_RUN=1` (or `DRY_RUN=1`) skips blacklist and scoring service calls while logging the batches that would be requested\n\n### Router TMS\n* `ROUTER_SAFE_ADDRESS` must control the router's executor role; signer key must belong to that Safe\n* `ROUTER_BASE_GROUP_ADDRESS` determines which base group memberships are required before enabling routing\n* Use `DRY_RUN=1` to log planned enablements without sending transactions\n\n### Docker Notes\n* The Dockerfile uses `APP_NAME` build argument to determine which app to run\n* Environment variables can be passed directly with `-e` flags instead of using `.env` files\n* The container runs as the `node` user for security\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faboutcircles%2Fgroup-tms","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faboutcircles%2Fgroup-tms","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faboutcircles%2Fgroup-tms/lists"}