https://github.com/aboutcircles/group-tms
Maintains the trust relations of a circles group based on their conditions
https://github.com/aboutcircles/group-tms
Last synced: 5 months ago
JSON representation
Maintains the trust relations of a circles group based on their conditions
- Host: GitHub
- URL: https://github.com/aboutcircles/group-tms
- Owner: aboutcircles
- Created: 2025-08-06T20:48:44.000Z (11 months ago)
- Default Branch: master
- Last Pushed: 2026-01-27T13:50:13.000Z (5 months ago)
- Last Synced: 2026-01-27T21:37:50.647Z (5 months ago)
- Language: TypeScript
- Size: 214 KB
- Stars: 0
- Watchers: 0
- Forks: 1
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
- awesome-circles - group-tms - Trust-Management Service: keeps a group's trust set in sync with declarative conditions. (Developer Tools / Developer Demos)
README
# Circles Group Trust Management Service
Three specialized services for Circles protocol trust management:
## CRC Backers App
* Scans Circles **BackingCompleted**/**BackingInitiated** events
* Filters out blacklisted backers
* **Trusts** valid new backers into a group in batches of 50
* Reconciles initiated-but-not-completed processes (resets CowSwap order or creates LBP)
* Optionally notifies Slack when something looks stuck
* Runs once a minute
* Supports dry-run mode to exercise the logic without submitting Safe transactions
## GP CRC App
* Scans Circles **RegisterHuman** events for newly registered avatars
* Cross-checks avatars against the blacklist service and Metri Safe GraphQL data
* Trusts eligible avatars into the configured group in batches (default 10)
* Supports dry-run mode and Slack notifications
* Runs every 10 minutes
## OIC App
* Monitors affiliate group changes and trust relationships
* Reconciles trust between MetaOrg trustees and affiliates
* Supports dry-run mode for testing
* Incremental scanning with configurable refresh intervals
* Batch processing for efficient trust operations
## Requirements
* Node.js **≥ 24**
* A Circles RPC endpoint (e.g. https://rpc.aboutcircles.com/)
* A private key that is the **group service** for the backers group
## Quick start
### Local Development
```bash
# 1) Install
npm install
# 2) Configure
touch .env # Check the values below and fill in your .env file
# 3) Run
# Option A: build then run with .env
npx tsc && node --env-file=.env dist/src/main.js
# Option B: use scripts (also load .env)
npm run start:crc-backers
npm run start:gp-crc
npm run start:oic
npm run start:all
```
## Configuration (.env)
### CRC Backers App Configuration
```dotenv
# RPC & addresses
RPC_URL=https://rpc.aboutcircles.com/
BACKING_FACTORY_ADDRESS=0xeced91232c609a42f6016860e8223b8aecaa7bd0
BACKERS_GROUP_ADDRESS=0x1ACA75e38263c79d9D4F10dF0635cc6FCfe6F026
# Safe execution
CRC_BACKERS_SAFE_ADDRESS= # Safe set as the group's service
CRC_BACKERS_SAFE_SIGNER_PRIVATE_KEY= # Private key for one Safe signer
# Blacklist service
BLACKLISTING_SERVICE_URL=https://squid-app-3gxnl.ondigitalocean.app/aboutcircles-advanced-analytics2/bot-analytics/classify
# Scan window / timing
START_AT_BLOCK=39743285
CONFIRMATION_BLOCKS=2
EXPECTED_SECONDS_TILL_COMPLETION=60
# Notifications
SLACK_WEBHOOK_URL=
# Logging
VERBOSE_LOGGING=1 # any truthy value enables debug/table
# Operation mode
DRY_RUN=0 # Set to "1" to skip Safe transactions and only log actions
```
### GP CRC App Configuration
```dotenv
# RPC & addresses
RPC_URL=https://rpc.aboutcircles.com/
GP_CRC_GROUP_ADDRESS=0xb629a1e86f3efada0f87c83494da8cc34c3f84ef
# Safe execution (required unless dry run)
GP_CRC_SAFE_ADDRESS= # Safe that controls the group's service role
GP_CRC_SAFE_SIGNER_PRIVATE_KEY= # Private key for a Safe signer
# Metri Safe GraphQL
METRI_SAFE_GRAPHQL_URL=https://gnosis-e702590.dedicated.hyperindex.xyz/v1/graphql
METRI_SAFE_API_KEY=
# Blacklist service
BLACKLISTING_SERVICE_URL=https://squid-app-3gxnl.ondigitalocean.app/aboutcircles-advanced-analytics2/bot-analytics/classify
# Scan window / timing
START_AT_BLOCK=31734312
CONFIRMATION_BLOCKS=10
DRY_RUN=0 # Set to "1" to skip transactions
# Notifications
SLACK_WEBHOOK_URL=
# Logging
VERBOSE_LOGGING=1
```
### OIC App Configuration
```dotenv
# RPC & addresses
RPC_URL=https://rpc.aboutcircles.com/
OIC_GROUP_ADDRESS=0x4E2564e5df6C1Fb10C1A018538de36E4D5844DE5
OIC_META_ORG_ADDRESS= # REQUIRED - Meta organization address
AFFILIATE_REGISTRY_ADDRESS=0xca8222e780d046707083f51377b5fd85e2866014
# Safe execution (required unless dry run)
OIC_SAFE_ADDRESS= # Safe that controls the OIC group service role
OIC_SAFE_SIGNER_PRIVATE_KEY= # Private key for one Safe signer
# Scan window / timing
START_AT_BLOCK=41734312
CONFIRMATION_BLOCKS=10
REFRESH_INTERVAL_SEC=60
# Operation mode
DRY_RUN=0 # Set to "1" for dry run mode (no actual transactions)
# Notifications
SLACK_WEBHOOK_URL=
# Logging
VERBOSE_LOGGING=1 # any truthy value enables debug/table
```
### Router TMS Configuration
```dotenv
# RPC & addresses
RPC_URL=https://rpc.aboutcircles.com/
ROUTER_ADDRESS=0xdc287474114cc0551a81ddc2eb51783fbf34802f
ROUTER_BASE_GROUP_ADDRESS=0x1ACA75e38263c79d9D4F10dF0635cc6FCfe6F026
# Safe execution (required unless dry run)
ROUTER_SAFE_ADDRESS= # Safe that controls the router's trusted executor
ROUTER_SAFE_SIGNER_PRIVATE_KEY= # Private key for one Safe signer
# Scan window / timing
ROUTER_POLL_INTERVAL_MS=1800000
ROUTER_ENABLE_BATCH_SIZE=50
ROUTER_FETCH_PAGE_SIZE=2000
ROUTER_BLACKLIST_CHUNK_SIZE=1000
# Operation mode
DRY_RUN=0 # Set to "1" to log actions without enabling routing
# Notifications
SLACK_WEBHOOK_URL=
# Logging
VERBOSE_LOGGING=1
```
### Gnosis Group App Configuration
```dotenv
# RPC & addresses
RPC_URL=https://rpc.aboutcircles.com/
# Safe execution
GNOSIS_GROUP_SAFE_ADDRESS= # Safe that owns the group service role
GNOSIS_GROUP_SAFE_SIGNER_PRIVATE_KEY= # Private key of a 1/n Safe signer
# External services
BLACKLISTING_SERVICE_URL=https://squid-app-3gxnl.ondigitalocean.app/aboutcircles-advanced-analytics2/bot-analytics/classify
GNOSIS_GROUP_SCORING_URL=https://squid-app-3gxnl.ondigitalocean.app/aboutcircles-advanced-analytics2/scoring/relative_trustscore/batch
# Operation mode
GNOSIS_GROUP_DRY_RUN=0 # Set to "1" to skip blacklist & scoring requests
# Notifications
GNOSIS_GROUP_SLACK_WEBHOOK_URL= # Optional override; falls back to SLACK_WEBHOOK_URL
SLACK_WEBHOOK_URL=
# Logging
VERBOSE_LOGGING=1
```
## What each app does
### CRC Backers App
* Uses a reorg buffer (`CONFIRMATION_BLOCKS`) from chain head
* From `START_AT_BLOCK` → head:
* Pulls **BackingCompleted**, filters via blacklist service, dedupes already-trusted backers, and calls
`trustBatchWithConditions(group, addresses, expiry=max uint96)` in batches of 50
* Finds **BackingInitiated** without matching completion:
* If **past deadline** (initiated timestamp + 24h): try `createLBP()`; notify Slack on inconsistent/insufficient states
* If **before deadline**: try `resetCowswapOrder()` when valid; if already settled, attempt LBP creation
* Logs summaries by default; `VERBOSE_LOGGING` prints debug and tables
* `DRY_RUN=1` skips Safe transactions and only logs what would have been executed
* Keeps running: initial run, then every minute
### GP CRC App
* Walks block ranges from `START_AT_BLOCK` to the safe head (`head - CONFIRMATION_BLOCKS`) and fetches `RegisterHuman` events via `circles_events`
* Deduplicates avatars, checks them against the blacklist in chunks, and verifies a configured Metri Pay safe exists
* Skips avatars without safes or already trusted in `GP_CRC_GROUP_ADDRESS`; trusts the rest in batches (default 10) with retry logic
* Supports dry-run logging, verbose logging, and optional Slack notifications for start, shutdown, and errors
* Runs every 10 minutes
### OIC App
* Monitors **AffiliateGroupChanged** events for trust relationship updates
* Calculates desired trustees by intersecting:
* Addresses trusted by any MetaOrg trustee
* Current affiliates in the registry
* Performs batch trust/untrust operations to reconcile differences
* Supports incremental scanning to avoid re-processing old events
* Can run in dry-run mode for testing without making transactions
* Configurable refresh intervals and batch sizes
## Operational notes
### General
* Make sure the configured Safe owns the appropriate **service** roles and that the signer key belongs to a Safe owner
* Slack notifications are best-effort; failures may throw and crash the process
* Services are designed to fail loudly on errors and require a supervisor to monitor and restart
* Replace placeholder values (`your_private_key_here`, etc.) with actual values in Docker commands
### CRC Backers App
* `CRC_BACKERS_SAFE_ADDRESS` must be the backers group's **service** and the signer key must belong to that Safe
* If you change the factory address, bump `START_AT_BLOCK` accordingly
* Service is stateless and does not store data between runs
### GP CRC App
* `GP_CRC_GROUP_ADDRESS` must match the group you intend to automatically trust new avatars into
* Provide `GP_CRC_SAFE_ADDRESS` plus `GP_CRC_SAFE_SIGNER_PRIVATE_KEY` unless `DRY_RUN=1`
* `METRI_SAFE_GRAPHQL_URL` is required; add `METRI_SAFE_API_KEY` if the endpoint is restricted
* `DRY_RUN=1` will log intended trust batches without submitting transactions
### OIC App
* `OIC_SAFE_ADDRESS` must be the OIC group's **service**; the signer key must belong to that Safe
* `OIC_META_ORG_ADDRESS` is required - this is the MetaOrg whose trustees will be monitored
* Use `DRY_RUN=1` for testing without making actual blockchain transactions
* Service maintains incremental state to avoid re-processing old events
### Gnosis Group App
* Fetches registered human avatars and filters out blacklisted addresses
* Calls a relative trust scoring service to rank avatars by configured targets
* Uses a Safe for execution; set `GNOSIS_GROUP_SAFE_ADDRESS` plus `GNOSIS_GROUP_SAFE_SIGNER_PRIVATE_KEY` for a 1/n Safe owner
* `GNOSIS_GROUP_DRY_RUN=1` (or `DRY_RUN=1`) skips blacklist and scoring service calls while logging the batches that would be requested
### Router TMS
* `ROUTER_SAFE_ADDRESS` must control the router's executor role; signer key must belong to that Safe
* `ROUTER_BASE_GROUP_ADDRESS` determines which base group memberships are required before enabling routing
* Use `DRY_RUN=1` to log planned enablements without sending transactions
### Docker Notes
* The Dockerfile uses `APP_NAME` build argument to determine which app to run
* Environment variables can be passed directly with `-e` flags instead of using `.env` files
* The container runs as the `node` user for security