diff --git a/vigil/SKILL.md b/vigil/SKILL.md new file mode 100644 index 0000000000..a0d82340bd --- /dev/null +++ b/vigil/SKILL.md @@ -0,0 +1,166 @@ +--- +name: VIGIL Security Scanner +description: Onchain security scanner on Base — scan token approvals, detect honeypots, analyze contracts for rugpull indicators, and score contract safety. Keyless read-only scanning via VIGIL API. Revoke actions require Bankr auth and are gated separately. +var: "" +tags: [crypto, security, base, defi] +capabilities: [external_api, sends_notifications] +--- +> **${var}** — Wallet address (`0x...`) or token contract address on Base to scan. Required. If empty, log `VIGIL_NO_TARGET` and exit cleanly (no notify). + +VIGIL is an onchain security scanner for DeFi traders on Base. It provides nine read-only scanning tools and one write action (revoke) that requires explicit Bankr authentication. + +**Read-only tools (this skill):** +1. Approval Scanner — list all ERC-20/ERC-721 approvals, flag unlimited allowances +2. Token Scanner — analyze contracts for rugpull indicators (hidden mint, proxy, tax manipulation, blacklist) +3. Honeypot Detector — simulate buy/sell to detect trap tokens +4. Safety Score — 0-100 composite rating based on code, ownership, liquidity, holders +5. Wallet Report — full security posture assessment +6. Wallet Monitor — real-time alerts for new approvals, risky interactions, and balance changes +7. Token Market — price, liquidity, 24h volume, and pool age via DexScreener (no API key) +8. Deployer Check — contract verification, name, and deployer reputation via Basescan +9. Batch Scan — score multiple tokens in one call, ranked by risk + +**Write action (separate, not included here):** +10. Approval Revoker — revoke dangerous approvals via Bankr transaction signing. This is a state-changing onchain transaction and is NOT part of this read-only skill. + +Read the last 2 days of `memory/logs/` so a repeat scan can note newly-granted or newly-revoked approvals. + +## Config + +- Target = `${var}`. Can be a wallet address or token contract address. +- Chain = Base (`chainid=8453`, explorer `basescan.org`). +- VIGIL API: `https://mcp.vigil.codes` (HTTPS, SSE transport) +- GitHub: `https://github.com/vigilcodes/vigil-mcp` + +## Steps + +### 1. Validate input (strict — rejects injection) + +The target MUST be exactly `0x` followed by 40 hex characters. The regex +below rejects any input containing quotes, spaces, or shell metacharacters, +so it is safe to interpolate into the JSON payloads in later steps. Reject +anything else and exit cleanly. + +```bash +TARGET="${var}" + +# Strict allowlist: 0x + exactly 40 hex chars. Nothing else can pass. +if ! printf '%s' "$TARGET" | grep -qiE '^0x[0-9a-f]{40}$'; then + echo "VIGIL_INVALID_TARGET: not a valid 0x address" + exit 0 +fi + +# Normalise to lowercase for consistent calls. +TARGET="$(printf '%s' "$TARGET" | tr '[:upper:]' '[:lower:]')" +``` + +Because `$TARGET` is now guaranteed to match `^0x[0-9a-f]{40}$`, it contains +no characters that could break the JSON body or the shell. A single address +can be either a wallet or a token contract, so run the relevant tools and +read each tool's own result — do not assume a type up front. + +### 1b. Safe call helper (checks errors before reading results) + +Every step below uses this helper. It fails loudly on a non-200 HTTP status +or a JSON-RPC `error` body instead of silently passing `null` to `jq`, so a +broken call is never reported as a clean scan. + +```bash +VIGIL_API="https://mcp.vigil.codes/tools/call" + +vigil_call () { + # $1 = tool name, $2 = JSON arguments object + local name="$1" args="$2" body http code + body=$(curl -m 30 -s -w '\n%{http_code}' "$VIGIL_API" \ + -H "Content-Type: application/json" \ + -d "{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"tools/call\",\"params\":{\"name\":\"$name\",\"arguments\":$args}}") + code=$(printf '%s' "$body" | tail -n1) + http=$(printf '%s' "$body" | sed '$d') + + if [ "$code" != "200" ]; then + echo "VIGIL_HTTP_ERROR ($code) calling $name"; return 1 + fi + if printf '%s' "$http" | jq -e '.error' >/dev/null 2>&1; then + echo "VIGIL_RPC_ERROR: $(printf '%s' "$http" | jq -c '.error')"; return 1 + fi + printf '%s' "$http" | jq '.result' +} +``` + +### 2. Scan approvals (wallet) + +```bash +vigil_call scan_approvals '{"wallet": "'"$TARGET"'", "chain": "base"}' +``` + +### 3. Scan token safety + +```bash +vigil_call scan_token '{"token": "'"$TARGET"'", "chain": "base"}' +``` + +### 4. Check honeypot + +```bash +vigil_call detect_honeypot '{"token": "'"$TARGET"'", "chain": "base"}' +``` + +### 5. Get safety score + +```bash +vigil_call safety_score '{"contract": "'"$TARGET"'", "chain": "base"}' +``` + +### 6. Generate wallet report + +```bash +vigil_call wallet_report '{"wallet": "'"$TARGET"'", "chain": "base"}' +``` + +### 7. Monitor wallet (real-time alerts) + +```bash +vigil_call monitor_wallet '{"wallet": "'"$TARGET"'", "chain": "base", "lookback_blocks": 1000}' +``` + +### 8. Token market context (price + liquidity) + +```bash +vigil_call token_market '{"token": "'"$TARGET"'", "chain": "base"}' +``` + +### 9. Deployer reputation (verification + age) + +```bash +vigil_call deployer_check '{"contract": "'"$TARGET"'", "chain": "base"}' +``` + +### 10. Batch scan multiple tokens + +```bash +vigil_call batch_scan '{"tokens": ["'"$TARGET"'"], "chain": "base"}' +``` + +## Output Format + +VIGIL returns JSON with: + +- `approvals` — list of token approvals with risk levels +- `safety_score` — 0-100 composite rating +- `honeypot` — boolean + reason if detected +- `rugpull_indicators` — list of suspicious patterns found +- `recommendations` — action items + +## Risk Levels + +| Level | Icon | Meaning | +|-------|------|---------| +| CRITICAL | 🔴 | Active threat — revoke immediately | +| HIGH | 🟠 | Dangerous pattern — likely exploit vector | +| MEDIUM | 🟡 | Suspicious — proceed with caution | +| LOW | 🟢 | Minor concern — monitor | +| SAFE | ✅ | No issues detected | + +## Important: Revocation is NOT included + +The Approval Revoker tool performs state-changing onchain transactions via Bankr. It is intentionally excluded from this read-only skill. To revoke approvals, use the separate `vigil-revoke` skill (requires `BANKR_API_KEY` and explicit user confirmation). diff --git a/vigil/references/api-reference.md b/vigil/references/api-reference.md new file mode 100644 index 0000000000..dcca1cea82 --- /dev/null +++ b/vigil/references/api-reference.md @@ -0,0 +1,241 @@ +# VIGIL API Reference + +Base URL: `https://api.bankr.bot/vigil` + +Authentication: `Authorization: Bearer ` (for write operations) + +## Endpoints + +### GET /approvals +List all token approvals for a wallet. + +**Params:** +| Param | Type | Required | Description | +|-------|------|----------|-------------| +| wallet | address | Yes | Wallet address | +| chain | string | No | base, ethereum, polygon, arbitrum (default: base) | +| risk | string | No | Filter: critical, high, medium, low | + +**Response:** +```json +{ + "approvals": [ + { + "token_address": "0x...", + "token_symbol": "USDC", + "token_name": "USD Coin", + "spender_address": "0x...", + "spender_name": "Uniswap V3 Router", + "amount": "unlimited", + "amount_usd": 15000.00, + "risk": "critical", + "approved_at": "2026-01-15T10:30:00Z", + "last_used": "2026-05-20T14:22:00Z" + } + ], + "total": 12, + "summary": { + "critical": 2, + "high": 3, + "medium": 4, + "low": 3 + } +} +``` + +--- + +### GET /token/scan +Scan a token contract for rugpull/honeypot indicators. + +**Params:** +| Param | Type | Required | Description | +|-------|------|----------|-------------| +| address | address | Yes | Token contract address | +| chain | string | No | Chain (default: base) | + +**Response:** +```json +{ + "token_name": "SafeMoon2", + "token_symbol": "SMOON2", + "safety_score": 23, + "risk_level": "critical", + "findings": [ + { + "severity": "critical", + "category": "ownership", + "message": "Owner can mint unlimited tokens" + }, + { + "severity": "high", + "category": "liquidity", + "message": "Liquidity not locked — removable at any time" + } + ], + "contract": { + "owner": "0x...", + "is_proxy": true, + "verified": false, + "ownership_renounced": false + }, + "liquidity": { + "total_locked_usd": 0, + "lock_duration": "none", + "lp_holders": 1 + }, + "holders": { + "top10_percentage": 95.2, + "total": 47, + "whales": 3 + }, + "tax": { + "buy": 5, + "sell": 15, + "modifiable": true + }, + "honeypot": { + "detected": false, + "reason": null + }, + "recommendation": "DO NOT BUY — Owner has unrestricted minting power and liquidity is unlocked" +} +``` + +--- + +### GET /token/honeypot +Dedicated honeypot detection via buy/sell simulation. + +**Params:** +| Param | Type | Required | Description | +|-------|------|----------|-------------| +| address | address | Yes | Token address | +| chain | string | No | Chain (default: base) | + +**Response:** +```json +{ + "is_honeypot": true, + "can_buy": true, + "can_sell": false, + "buy_tax": 5, + "sell_tax": 99, + "block_reason": "Transfer function contains blacklist check that blocks sells from non-whitelisted addresses", + "simulations": [ + {"action": "buy_0.1_eth", "success": true, "gas_used": 185000}, + {"action": "sell_100%", "success": false, "gas_used": 0, "error": "execution reverted: blacklisted"} + ], + "high_tax_warning": false +} +``` + +--- + +### GET /score +Get safety score for a contract. + +**Params:** +| Param | Type | Required | Description | +|-------|------|----------|-------------| +| address | address | Yes | Contract address | +| chain | string | No | Chain (default: base) | + +**Response:** +```json +{ + "score": 72, + "risk_level": "medium", + "breakdown": [ + {"category": "Code Quality", "score": 85, "note": "Verified, no critical bugs"}, + {"category": "Ownership", "score": 60, "note": "Owner has some privileges"}, + {"category": "Liquidity", "score": 80, "note": "80% locked for 6 months"}, + {"category": "Distribution", "score": 65, "note": "Top 10 hold 45%"}, + {"category": "History", "score": 70, "note": "Deployer has 2 prior contracts"} + ], + "risk_factors": [ + "Owner can adjust tax up to 25%", + "Proxy contract — implementation can be changed" + ], + "positive_factors": [ + "Liquidity locked for 6 months", + "Contract verified on explorer", + "No mint function" + ], + "recommendation": "MODERATE RISK — Proceed with small position size only" +} +``` + +--- + +### GET /report +Full wallet security report. + +**Params:** +| Param | Type | Required | Description | +|-------|------|----------|-------------| +| wallet | address | Yes | Wallet address | +| chain | string | No | Chain (default: base) | + +--- + +### POST /revoke/build +Build unsigned revocation transaction. + +**Body:** +```json +{ + "token": "0x...", + "spender": "0x...", + "chain": "base" +} +``` + +--- + +### POST /revoke/submit +Sign and submit revocation via Bankr. + +**Body:** +```json +{ + "unsigned_tx": "0x...", + "chain": "base" +} +``` + +--- + +### POST /report/submit +Submit a scam report to the community database. + +**Body:** +```json +{ + "token": "0x...", + "evidence_type": "honeypot|rugpull|phishing|scam|fake", + "description": "Brief description of the scam", + "chain": "base" +} +``` + +## Rate Limits + +| Tier | Requests/min | Scans/day | +|------|-------------|-----------| +| Free | 10 | 5 | +| Scout (100+ $VIGIL) | 50 | 50 | +| Guardian (500+ $VIGIL) | 200 | 200 | +| Sentinel (1000+ $VIGIL) | 1000 | Unlimited | +| Archon (5000+ $VIGIL) | Unlimited | Unlimited | + +## Error Codes + +| Code | Description | +|------|-------------| +| 400 | Invalid parameters | +| 401 | Invalid or missing API key | +| 403 | Tier quota exceeded | +| 404 | Token/wallet not found | +| 429 | Rate limit exceeded | +| 500 | Internal server error | diff --git a/vigil/references/bankr-integration.md b/vigil/references/bankr-integration.md new file mode 100644 index 0000000000..ff1d4c5ff9 --- /dev/null +++ b/vigil/references/bankr-integration.md @@ -0,0 +1,92 @@ +# VIGIL — Bankr Integration Guide + +## Overview + +VIGIL integrates with Bankr for: +1. **Transaction signing** — Approval revocations go through Bankr's wallet API +2. **API key authentication** — VIGIL uses the same `BANKR_API_KEY` +3. **Chain routing** — Leverages Bankr's multi-chain RPC infrastructure + +## Setup + +### 1. Get Bankr API Key (only needed for revocations) + +```bash +# If you don't have a key yet +bankr login email your@email.com +# Follow the OTP flow, enable --read-write +``` + +Read-only scans (token, honeypot, score, approvals, report, market, +deployer, scam check) need **no key** — they hit the public VIGIL endpoint +at `https://mcp.vigil.codes`. + +### 2. Configure VIGIL + +```bash +# Required only for revoke actions (signed via Bankr) +export BANKR_API_KEY=bk_your_key_here + +# Optional: override the public read-only endpoint +export VIGIL_ENDPOINT=https://mcp.vigil.codes/tools/call +``` + +### 3. Make scripts executable + +```bash +cd ~/.hermes/skills/bankr-vigil +chmod +x scripts/*.sh +``` + +## Usage Patterns + +### Pattern 1: Scan Before Trading + +Before buying a new token, always scan it first: + +```bash +# Step 1: Safety score + rugpull indicators +./scripts/vigil-token.sh 0xTokenAddr base + +# Step 2: Honeypot check (buy + sell simulation) +./scripts/vigil-honeypot.sh 0xTokenAddr base + +# Step 3: Market context — thin liquidity / brand-new pool is a red flag +./scripts/vigil-market.sh 0xTokenAddr base + +# Step 4: Deployer reputation + community scam reports +./scripts/vigil-deployer.sh 0xTokenAddr base +./scripts/vigil-check-scam.sh 0xTokenAddr base + +# Step 5: If all clear, trade via Bankr +bankr agent "buy 0.01 ETH of 0xTokenAddr on base" +``` + +### Pattern 2: Regular Wallet Audit + +Run a weekly security check on your wallet: + +```bash +# Full security report +./scripts/vigil-report.sh 0xYourWallet base + +# Revoke risky approvals (scan via VIGIL, sign via Bankr) +./scripts/vigil-batch-revoke.sh 0xYourWallet base --risk-level critical +``` + +### Pattern 3: Alert Setup + +Configure monitoring for your wallet: + +```bash +# (Requires PULSE skill — future integration) +# Set up alerts for new risky approvals +pulse add --trigger "new_approval(risk=critical)" --wallet 0xYourWallet --notify telegram +``` + +## Security Notes + +- VIGIL scripts never store your private keys +- Revocations are signed by Bankr (your key stays in Bankr's secure enclave) +- API calls use HTTPS only +- No data is shared with third parties diff --git a/vigil/references/contracts.md b/vigil/references/contracts.md new file mode 100644 index 0000000000..76a8c6d65a --- /dev/null +++ b/vigil/references/contracts.md @@ -0,0 +1,37 @@ +# VIGIL Contract Addresses + +## Base Mainnet + +| Contract | Address | Status | +|----------|---------|--------| +| $VIGIL Token (ERC-20) | `0xPENDING_DEPLOYMENT` | Not deployed | +| VIGIL Staking | `0xPENDING_DEPLOYMENT` | Not deployed | +| VIGIL Governance | TBD | Planned | +| VIGIL Treasury (Multi-sig) | TBD | Planned | + +## Deployment Checklist + +- [ ] Deploy `VigilToken.sol` with treasury address +- [ ] Deploy `VigilStaking.sol` with token address +- [ ] Grant `MINTER_ROLE` to staking contract (for bounty payouts) +- [ ] Fund staking reward pool with initial VIGIL allocation +- [ ] Add initial liquidity on Aerodrome (VIGIL/USDC pair) +- [ ] Lock LP tokens for 12 months +- [ ] Verify all contracts on BaseScan +- [ ] Transfer admin to multi-sig treasury + +## Verification Commands + +```bash +# Verify token contract +npx hardhat verify --network base "" + +# Verify staking contract +npx hardhat verify --network base "" "" +``` + +## Dependencies + +- OpenZeppelin Contracts v5.x +- Solidity ^0.8.20 +- Base chain (Coinbase L2) diff --git a/vigil/scripts/_vigil_lib.sh b/vigil/scripts/_vigil_lib.sh new file mode 100755 index 0000000000..a16ff4615a --- /dev/null +++ b/vigil/scripts/_vigil_lib.sh @@ -0,0 +1,63 @@ +#!/usr/bin/env bash +# _vigil_lib.sh — shared helpers for VIGIL Bankr skill scripts. +# +# Source this from each script: . "$(dirname "$0")/_vigil_lib.sh" +# +# Provides: +# vigil_validate_addr -> echoes lowercase 0x addr, or exits 1 +# vigil_validate_chain -> echoes chain, or exits 1 +# vigil_call -> echoes JSON result, or exits 1 on error +# risk_icon -> echoes an emoji for a risk level + +# Public read-only endpoint (JSON-RPC 2.0). No API key required. +VIGIL_ENDPOINT="${VIGIL_ENDPOINT:-https://mcp.vigil.codes/tools/call}" + +# Strict allowlist: 0x + exactly 40 hex chars. Rejects quotes, spaces, and +# any shell/JSON metacharacter, so the value is safe to interpolate. +vigil_validate_addr () { + local addr="$1" + if ! printf '%s' "$addr" | grep -qiE '^0x[0-9a-f]{40}$'; then + echo "Error: invalid address '$addr' (expected 0x + 40 hex chars)" >&2 + exit 1 + fi + printf '%s' "$addr" | tr '[:upper:]' '[:lower:]' +} + +vigil_validate_chain () { + local chain="${1:-base}" + case "$chain" in + base|ethereum|polygon|arbitrum) printf '%s' "$chain" ;; + *) echo "Error: unsupported chain '$chain' (use base|ethereum|polygon|arbitrum)" >&2; exit 1 ;; + esac +} + +# vigil_call +# Posts a JSON-RPC tools/call and returns the .result object. Fails loudly on +# a non-200 HTTP status or a JSON-RPC error body instead of emitting null. +vigil_call () { + local name="$1" args="$2" body http code + body=$(curl -m 40 -s -w '\n%{http_code}' "$VIGIL_ENDPOINT" \ + -H "Content-Type: application/json" \ + -d "{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"tools/call\",\"params\":{\"name\":\"$name\",\"arguments\":$args}}") || { + echo "Error: request to $VIGIL_ENDPOINT failed" >&2; exit 1; } + code=$(printf '%s' "$body" | tail -n1) + http=$(printf '%s' "$body" | sed '$d') + if [ "$code" != "200" ]; then + echo "Error: HTTP $code calling $name" >&2; exit 1 + fi + if printf '%s' "$http" | jq -e '.error' >/dev/null 2>&1; then + echo "Error: $(printf '%s' "$http" | jq -c '.error')" >&2; exit 1 + fi + printf '%s' "$http" | jq '.result' +} + +risk_icon () { + case "$1" in + critical) printf '🔴' ;; + high) printf '🟠' ;; + medium) printf '🟡' ;; + low) printf '🟢' ;; + safe) printf '✅' ;; + *) printf '❓' ;; + esac +} diff --git a/vigil/scripts/vigil-approvals.sh b/vigil/scripts/vigil-approvals.sh new file mode 100755 index 0000000000..5344406d60 --- /dev/null +++ b/vigil/scripts/vigil-approvals.sh @@ -0,0 +1,37 @@ +#!/usr/bin/env bash +set -euo pipefail + +# vigil-approvals.sh — List all token approvals for a wallet. +# Usage: ./vigil-approvals.sh [chain] + +. "$(dirname "$0")/_vigil_lib.sh" + +WALLET=$(vigil_validate_addr "${1:?Usage: vigil-approvals.sh [chain]}") +CHAIN=$(vigil_validate_chain "${2:-base}") + +echo "🔍 Scanning approvals for $WALLET on $CHAIN..." +echo "" + +RESPONSE=$(vigil_call vigil_scan_approvals "{\"wallet\":\"$WALLET\",\"chain\":\"$CHAIN\"}") + +TOTAL=$(echo "$RESPONSE" | jq '.approvals | length') +CRITICAL=$(echo "$RESPONSE" | jq '[.approvals[] | select(.risk == "critical")] | length') +HIGH=$(echo "$RESPONSE" | jq '[.approvals[] | select(.risk == "high")] | length') + +echo "📊 Results: $TOTAL approvals found" +echo " 🔴 Critical: $CRITICAL 🟠 High: $HIGH" +echo "" + +if [ "$TOTAL" -gt 0 ]; then + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + echo "$RESPONSE" | jq -r '.approvals[] | + "\(.risk | if . == "critical" then "🔴 CRIT" elif . == "high" then "🟠 HIGH" elif . == "medium" then "🟡 MED " elif . == "low" then "🟢 LOW " else "✅ SAFE" end) \(.token_symbol // .token_address[0:10]) → \(.spender_name // .spender_address[0:16]) | \(if .amount == "unlimited" then "UNLIMITED" else .amount[0:12] end)"' + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + if [ "$CRITICAL" -gt 0 ] || [ "$HIGH" -gt 0 ]; then + echo "" + echo "To revoke (via Bankr): ./vigil-revoke.sh $CHAIN" + echo "To revoke all risky: ./vigil-batch-revoke.sh $WALLET $CHAIN" + fi +else + echo "✅ No active approvals found. Wallet is clean." +fi diff --git a/vigil/scripts/vigil-batch-revoke.sh b/vigil/scripts/vigil-batch-revoke.sh new file mode 100755 index 0000000000..8771d3c9ff --- /dev/null +++ b/vigil/scripts/vigil-batch-revoke.sh @@ -0,0 +1,77 @@ +#!/usr/bin/env bash +set -euo pipefail + +# vigil-batch-revoke.sh — Scan a wallet and revoke all risky approvals via Bankr. +# Usage: ./vigil-batch-revoke.sh [chain] [--risk-level critical|high|medium] +# +# Read side (scan) uses the public VIGIL endpoint; the write side (revoke) runs +# through the Bankr agent for signing. Requires the `bankr` CLI authenticated. + +. "$(dirname "$0")/_vigil_lib.sh" + +WALLET=$(vigil_validate_addr "${1:?Usage: vigil-batch-revoke.sh [chain] [--risk-level L]}") +CHAIN=$(vigil_validate_chain "${2:-base}") +RISK_LEVEL="critical" + +shift 2 || true +while [ $# -gt 0 ]; do + case "$1" in + --risk-level) RISK_LEVEL="${2:-critical}"; shift 2 ;; + *) shift ;; + esac +done +case "$RISK_LEVEL" in critical|high|medium) ;; *) echo "Error: --risk-level must be critical|high|medium" >&2; exit 1 ;; esac + +if ! command -v bankr >/dev/null 2>&1; then + echo "Error: 'bankr' CLI not found. Install/authenticate Bankr to revoke." >&2 + exit 1 +fi + +echo "🛡️ VIGIL Batch Revoker (scan + Bankr signing)" +echo " Wallet: $WALLET | Chain: $CHAIN | Risk: $RISK_LEVEL+" +echo "" + +# 1. Scan approvals via the public endpoint. +RESPONSE=$(vigil_call vigil_scan_approvals "{\"wallet\":\"$WALLET\",\"chain\":\"$CHAIN\"}") + +# 2. Filter to the requested risk level (and worse). +case "$RISK_LEVEL" in + critical) FILTER='.risk == "critical"' ;; + high) FILTER='.risk == "critical" or .risk == "high"' ;; + medium) FILTER='.risk == "critical" or .risk == "high" or .risk == "medium"' ;; +esac + +TARGETS=$(echo "$RESPONSE" | jq -c "[.approvals[] | select($FILTER)]") +COUNT=$(echo "$TARGETS" | jq 'length') + +if [ "$COUNT" -eq 0 ]; then + echo "✅ No $RISK_LEVEL+ approvals found. Wallet is clean." + exit 0 +fi + +echo "📋 Found $COUNT approval(s) to revoke:" +echo "$TARGETS" | jq -r '.[] | " \(.token_symbol // .token_address[0:10]) → \(.spender_address[0:16])"' +echo "" + +read -r -p "⚠️ Revoke all $COUNT via Bankr? (y/N) " REPLY +echo "" +case "$REPLY" in [Yy]*) ;; *) echo "Cancelled."; exit 0 ;; esac + +SUCCESS=0; FAILED=0 +while IFS= read -r approval; do + TOKEN=$(echo "$approval" | jq -r '.token_address') + SPENDER=$(echo "$approval" | jq -r '.spender_address') + SYMBOL=$(echo "$approval" | jq -r '.token_symbol // .token_address[0:10]') + echo " Revoking $SYMBOL..." + if bankr agent "revoke the ERC-20 approval for token $TOKEN granted to spender $SPENDER on $CHAIN (set allowance to 0)"; then + SUCCESS=$((SUCCESS + 1)) + else + echo " ❌ failed"; FAILED=$((FAILED + 1)) + fi + sleep 2 +done < <(echo "$TARGETS" | jq -c '.[]') + +echo "" +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo " ✅ Revoked: $SUCCESS ❌ Failed: $FAILED" +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" diff --git a/vigil/scripts/vigil-check-scam.sh b/vigil/scripts/vigil-check-scam.sh new file mode 100755 index 0000000000..746c339b5b --- /dev/null +++ b/vigil/scripts/vigil-check-scam.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash +set -euo pipefail + +# vigil-check-scam.sh — Check a token against the community scam database. +# Usage: ./vigil-check-scam.sh [chain] + +. "$(dirname "$0")/_vigil_lib.sh" + +TOKEN=$(vigil_validate_addr "${1:?Usage: vigil-check-scam.sh [chain]}") +CHAIN=$(vigil_validate_chain "${2:-base}") + +echo "🗂️ Checking community scam reports for $TOKEN on $CHAIN..." +echo "" + +RESPONSE=$(vigil_call vigil_check_scam "{\"token\":\"$TOKEN\",\"chain\":\"$CHAIN\"}") + +if [ "$(echo "$RESPONSE" | jq -r '.reported')" = "true" ]; then + COUNT=$(echo "$RESPONSE" | jq -r '.report_count') + echo " 🚨 REPORTED — $COUNT community report(s)" + echo " Categories: $(echo "$RESPONSE" | jq -r '.evidence_types | join(", ")')" + echo "" + echo "$RESPONSE" | jq -r '.reports[]? | " • [\(.evidence_type)] \(.description)"' +else + echo " ✅ Clean — no community scam reports for this token." +fi diff --git a/vigil/scripts/vigil-deployer.sh b/vigil/scripts/vigil-deployer.sh new file mode 100755 index 0000000000..93fb20d229 --- /dev/null +++ b/vigil/scripts/vigil-deployer.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash +set -euo pipefail + +# vigil-deployer.sh — Contract verification + deployer reputation (Basescan). +# Usage: ./vigil-deployer.sh [chain] + +. "$(dirname "$0")/_vigil_lib.sh" + +CONTRACT=$(vigil_validate_addr "${1:?Usage: vigil-deployer.sh [chain]}") +CHAIN=$(vigil_validate_chain "${2:-base}") + +echo "🏗️ Checking deployer reputation for $CONTRACT on $CHAIN..." +echo "" + +RESPONSE=$(vigil_call vigil_deployer_check "{\"contract\":\"$CONTRACT\",\"chain\":\"$CHAIN\"}") + +if [ "$(echo "$RESPONSE" | jq -r '.available')" != "true" ]; then + echo " ❓ $(echo "$RESPONSE" | jq -r '.note')" + exit 0 +fi + +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo " Contract Name: $(echo "$RESPONSE" | jq -r '.contract_name // "N/A"')" +echo " Verified: $(echo "$RESPONSE" | jq -r '.verified // false')" +echo " Deployer: $(echo "$RESPONSE" | jq -r '.deployer // "N/A"')" +echo " Age (days): $(echo "$RESPONSE" | jq -r '.age_days // "N/A"')" +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + +if [ "$(echo "$RESPONSE" | jq '.risk_factors | length')" -gt 0 ]; then + echo "" + echo "⚠️ Risk Factors:" + echo "$RESPONSE" | jq -r '.risk_factors[] | " • \(.)"' +fi +if [ "$(echo "$RESPONSE" | jq '.positive_factors | length')" -gt 0 ]; then + echo "" + echo "✅ Positive Factors:" + echo "$RESPONSE" | jq -r '.positive_factors[] | " • \(.)"' +fi +echo "" +echo " ℹ️ $(echo "$RESPONSE" | jq -r '.note')" diff --git a/vigil/scripts/vigil-honeypot.sh b/vigil/scripts/vigil-honeypot.sh new file mode 100755 index 0000000000..d921c8d93c --- /dev/null +++ b/vigil/scripts/vigil-honeypot.sh @@ -0,0 +1,49 @@ +#!/usr/bin/env bash +set -euo pipefail + +# vigil-honeypot.sh — Detect honeypot tokens (buy OK, sell blocked). +# Usage: ./vigil-honeypot.sh [chain] + +. "$(dirname "$0")/_vigil_lib.sh" + +TOKEN=$(vigil_validate_addr "${1:?Usage: vigil-honeypot.sh [chain]}") +CHAIN=$(vigil_validate_chain "${2:-base}") + +echo "🍯 Running honeypot detection on $TOKEN ($CHAIN)..." +echo "" + +RESPONSE=$(vigil_call vigil_detect_honeypot "{\"token\":\"$TOKEN\",\"chain\":\"$CHAIN\"}") + +IS_HONEYPOT=$(echo "$RESPONSE" | jq -r '.is_honeypot') +CAN_BUY=$(echo "$RESPONSE" | jq -r '.can_buy') +CAN_SELL=$(echo "$RESPONSE" | jq -r '.can_sell') +BUY_TAX=$(echo "$RESPONSE" | jq -r '.buy_tax // "N/A"') +SELL_TAX=$(echo "$RESPONSE" | jq -r '.sell_tax // "N/A"') + +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +if [ "$IS_HONEYPOT" = "true" ]; then + echo " 🍯 HONEYPOT CONFIRMED — DO NOT BUY" + echo "" + echo " Can Buy: $CAN_BUY Can Sell: $CAN_SELL" + echo " Buy Tax: $BUY_TAX Sell Tax: $SELL_TAX" + BLOCK_REASON=$(echo "$RESPONSE" | jq -r '.block_reason // empty') + [ -n "$BLOCK_REASON" ] && { echo ""; echo " Block Reason: $BLOCK_REASON"; } + echo "" + echo " ⛔ This token will trap your funds. Avoid." +elif [ "$CAN_SELL" = "true" ]; then + echo " ✅ NOT a honeypot — buy and sell both work" + echo "" + echo " Buy Tax: $BUY_TAX Sell Tax: $SELL_TAX" + HIGH_TAX=$(echo "$RESPONSE" | jq -r '.high_tax_warning // false') + [ "$HIGH_TAX" = "true" ] && { echo ""; echo " ⚠️ High tax (>10%) — may still be a soft rug"; } +else + echo " 🟠 LIKELY HONEYPOT — sell simulation failed" + echo "" + echo " Can Buy: $CAN_BUY Can Sell: $CAN_SELL" +fi +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + +echo "" +echo "🧪 Simulation Details:" +echo "$RESPONSE" | jq -r '.simulations[]? | + " \(.action): \(if .success then "✅ OK" else "❌ FAILED" end)\(if .error then " — \(.error)" else "" end)"' diff --git a/vigil/scripts/vigil-market.sh b/vigil/scripts/vigil-market.sh new file mode 100755 index 0000000000..a5ceb27a56 --- /dev/null +++ b/vigil/scripts/vigil-market.sh @@ -0,0 +1,38 @@ +#!/usr/bin/env bash +set -euo pipefail + +# vigil-market.sh — Token price, liquidity, volume, and pool age (DexScreener). +# Usage: ./vigil-market.sh [chain] + +. "$(dirname "$0")/_vigil_lib.sh" + +TOKEN=$(vigil_validate_addr "${1:?Usage: vigil-market.sh [chain]}") +CHAIN=$(vigil_validate_chain "${2:-base}") + +echo "💹 Fetching market context for $TOKEN on $CHAIN..." +echo "" + +RESPONSE=$(vigil_call vigil_token_market "{\"token\":\"$TOKEN\",\"chain\":\"$CHAIN\"}") + +if [ "$(echo "$RESPONSE" | jq -r '.found')" != "true" ]; then + echo " ❓ No DEX pairs found for this token." + exit 0 +fi + +RISK=$(echo "$RESPONSE" | jq -r '.liquidity_risk') +ICON=$(risk_icon "$RISK") + +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo " Price: \$$(echo "$RESPONSE" | jq -r '.price_usd // "N/A"')" +echo " Liquidity: \$$(echo "$RESPONSE" | jq -r '.liquidity_usd // "N/A"')" +echo " 24h Volume: \$$(echo "$RESPONSE" | jq -r '.volume_24h_usd // "N/A"')" +echo " Pool Age: $(echo "$RESPONSE" | jq -r '.pool_age_hours // "N/A"') h" +echo " Liquidity Risk: $ICON ${RISK^^}" +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + +NOTES=$(echo "$RESPONSE" | jq -r '.notes[]?') +if [ -n "$NOTES" ]; then + echo "" + echo "⚠️ Notes:" + echo "$RESPONSE" | jq -r '.notes[] | " • \(.)"' +fi diff --git a/vigil/scripts/vigil-report-scam.sh b/vigil/scripts/vigil-report-scam.sh new file mode 100755 index 0000000000..441baa7595 --- /dev/null +++ b/vigil/scripts/vigil-report-scam.sh @@ -0,0 +1,38 @@ +#!/usr/bin/env bash +set -euo pipefail + +# vigil-report-scam.sh — Submit a scam token to the VIGIL community database. +# Usage: ./vigil-report-scam.sh [chain] +# evidence_type: honeypot | rugpull | phishing | scam | fake +# +# Reporting is a write action. It is submitted through the MCP server's +# report tool. Configure VIGIL_REPORT_ENDPOINT if your server exposes it on a +# non-default path; otherwise this calls the standard tools/call route. + +. "$(dirname "$0")/_vigil_lib.sh" + +TOKEN=$(vigil_validate_addr "${1:?Usage: vigil-report-scam.sh [chain]}") +EVIDENCE="${2:?evidence_type: honeypot|rugpull|phishing|scam|fake}" +DESC="${3:?Provide a brief description of the scam evidence}" +CHAIN=$(vigil_validate_chain "${4:-base}") + +case "$EVIDENCE" in + honeypot|rugpull|phishing|scam|fake) ;; + *) echo "Error: evidence_type must be honeypot|rugpull|phishing|scam|fake" >&2; exit 1 ;; +esac + +# Escape the free-text description for safe JSON embedding. +DESC_JSON=$(printf '%s' "$DESC" | jq -Rs '.') + +echo "🚨 Submitting scam report for $TOKEN ($EVIDENCE) on $CHAIN..." +echo "" + +ARGS="{\"token\":\"$TOKEN\",\"evidence_type\":\"$EVIDENCE\",\"description\":$DESC_JSON,\"chain\":\"$CHAIN\"}" +RESPONSE=$(vigil_call vigil_report_scam "$ARGS") + +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo " ✅ $(echo "$RESPONSE" | jq -r '.status // "submitted"')" +echo " Report ID: $(echo "$RESPONSE" | jq -r '.report_id // "N/A"')" +echo " Reports for token: $(echo "$RESPONSE" | jq -r '.total_reports_for_token // 1')" +echo " Bounty: $(echo "$RESPONSE" | jq -r '.bounty // "—"')" +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" diff --git a/vigil/scripts/vigil-report.sh b/vigil/scripts/vigil-report.sh new file mode 100755 index 0000000000..8076b55442 --- /dev/null +++ b/vigil/scripts/vigil-report.sh @@ -0,0 +1,51 @@ +#!/usr/bin/env bash +set -euo pipefail + +# vigil-report.sh — Full wallet security report. +# Usage: ./vigil-report.sh [chain] + +. "$(dirname "$0")/_vigil_lib.sh" + +WALLET=$(vigil_validate_addr "${1:?Usage: vigil-report.sh [chain]}") +CHAIN=$(vigil_validate_chain "${2:-base}") + +echo "🛡️ VIGIL Security Report" +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo " Wallet: $WALLET" +echo " Chain: $CHAIN" +echo " Time: $(date -u '+%Y-%m-%d %H:%M UTC')" +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo "" + +RESPONSE=$(vigil_call vigil_wallet_report "{\"wallet\":\"$WALLET\",\"chain\":\"$CHAIN\"}") + +OVERALL=$(echo "$RESPONSE" | jq -r '.overall_score') +RISK=$(echo "$RESPONSE" | jq -r '.risk_level') +ICON=$(risk_icon "$RISK") + +echo "📊 Overall Security Score: $OVERALL/100 $ICON (${RISK^^})" +echo "" + +echo "━━━ Approvals ━━━" +echo " Total: $(echo "$RESPONSE" | jq -r '.approvals.total')" +echo " Critical: $(echo "$RESPONSE" | jq -r '.approvals.critical')" +echo " High: $(echo "$RESPONSE" | jq -r '.approvals.high')" +echo " Unlimited: $(echo "$RESPONSE" | jq -r '.approvals.unlimited')" +echo "" + +if [ "$(echo "$RESPONSE" | jq '.top_risks | length')" -gt 0 ]; then + echo "━━━ Top Risky Approvals ━━━" + echo "$RESPONSE" | jq -r '.top_risks[:5][] | + " \(if .risk == "critical" then "🔴" elif .risk == "high" then "🟠" else "🟡" end) \(.token_symbol) → \(.spender_address[0:16]) | \(if .amount == "unlimited" then "UNLIMITED ⚠️" else .amount end)"' + echo "" +fi + +if [ "$(echo "$RESPONSE" | jq '.recommendations | length')" -gt 0 ]; then + echo "━━━ Recommendations ━━━" + echo "$RESPONSE" | jq -r '.recommendations[] | " \(if .priority == "critical" then "🔴" elif .priority == "high" then "🟠" else "🟡" end) \(.action): \(.detail)"' + echo "" +fi + +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo " Run ./vigil-batch-revoke.sh $WALLET $CHAIN to fix risky approvals" +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" diff --git a/vigil/scripts/vigil-revoke.sh b/vigil/scripts/vigil-revoke.sh new file mode 100755 index 0000000000..105e4bc913 --- /dev/null +++ b/vigil/scripts/vigil-revoke.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash +set -euo pipefail + +# vigil-revoke.sh — Revoke a token approval through Bankr (signed onchain tx). +# Usage: ./vigil-revoke.sh [chain] +# +# Revocation is a STATE-CHANGING action and is intentionally NOT part of the +# read-only VIGIL endpoint. It is executed through the Bankr agent, which holds +# the signing key in its secure enclave. Requires the `bankr` CLI to be +# installed and authenticated (bankr login ... --read-write). + +. "$(dirname "$0")/_vigil_lib.sh" + +TOKEN=$(vigil_validate_addr "${1:?Usage: vigil-revoke.sh [chain]}") +SPENDER=$(vigil_validate_addr "${2:?Usage: vigil-revoke.sh [chain]}") +CHAIN=$(vigil_validate_chain "${3:-base}") + +if ! command -v bankr >/dev/null 2>&1; then + echo "Error: 'bankr' CLI not found. Install and authenticate Bankr first:" >&2 + echo " bankr login email your@email.com # then enable --read-write" >&2 + exit 1 +fi + +echo "🔓 Revoking approval via Bankr" +echo " Token: $TOKEN" +echo " Spender: $SPENDER" +echo " Chain: $CHAIN" +echo "" + +# Bankr understands natural-language intents and handles building + signing +# + submitting the revoke transaction. setApproval(spender, 0) == revoke. +exec bankr agent "revoke the ERC-20 approval for token $TOKEN granted to spender $SPENDER on $CHAIN (set allowance to 0)" diff --git a/vigil/scripts/vigil-score.sh b/vigil/scripts/vigil-score.sh new file mode 100755 index 0000000000..7dfe2a728c --- /dev/null +++ b/vigil/scripts/vigil-score.sh @@ -0,0 +1,55 @@ +#!/usr/bin/env bash +set -euo pipefail + +# vigil-score.sh — Get a 0-100 safety score for a contract. +# Usage: ./vigil-score.sh [chain] + +. "$(dirname "$0")/_vigil_lib.sh" + +CONTRACT=$(vigil_validate_addr "${1:?Usage: vigil-score.sh [chain]}") +CHAIN=$(vigil_validate_chain "${2:-base}") + +echo "📊 Getting safety score for $CONTRACT on $CHAIN..." +echo "" + +RESPONSE=$(vigil_call vigil_safety_score "{\"contract\":\"$CONTRACT\",\"chain\":\"$CHAIN\"}") + +SCORE=$(echo "$RESPONSE" | jq -r '.score') +RISK=$(echo "$RESPONSE" | jq -r '.risk_level') +ICON=$(risk_icon "$RISK") + +# Simple 20-cell bar without bc dependency. +FILLED=$(( SCORE / 5 )) +[ "$FILLED" -gt 20 ] && FILLED=20 +EMPTY=$(( 20 - FILLED )) +BAR="" +for _ in $(seq 1 "$FILLED"); do BAR="$BAR█"; done +for _ in $(seq 1 "$EMPTY"); do BAR="$BAR░"; done + +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo " $ICON Safety Score: $SCORE/100" +echo " [$BAR]" +echo " Risk Level: ${RISK^^}" +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo "" + +echo "📋 Score Breakdown:" +echo "$RESPONSE" | jq -r '.breakdown[]? | + " \(if .score >= 80 then "✅" elif .score >= 60 then "🟡" elif .score >= 40 then "🟠" else "🔴" end) \(.category): \(.score) — \(.note)"' +echo "" + +if [ "$(echo "$RESPONSE" | jq '.risk_factors | length')" -gt 0 ]; then + echo "⚠️ Risk Factors:" + echo "$RESPONSE" | jq -r '.risk_factors[] | " • \(.)"' + echo "" +fi + +if [ "$(echo "$RESPONSE" | jq '.positive_factors | length')" -gt 0 ]; then + echo "✅ Positive Factors:" + echo "$RESPONSE" | jq -r '.positive_factors[] | " • \(.)"' + echo "" +fi + +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo "$RESPONSE" | jq -r '" 💡 \(.recommendation)"' +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" diff --git a/vigil/scripts/vigil-token.sh b/vigil/scripts/vigil-token.sh new file mode 100755 index 0000000000..750bf33986 --- /dev/null +++ b/vigil/scripts/vigil-token.sh @@ -0,0 +1,42 @@ +#!/usr/bin/env bash +set -euo pipefail + +# vigil-token.sh — Scan a token contract for rugpull/honeypot indicators. +# Usage: ./vigil-token.sh [chain] + +. "$(dirname "$0")/_vigil_lib.sh" + +TOKEN=$(vigil_validate_addr "${1:?Usage: vigil-token.sh [chain]}") +CHAIN=$(vigil_validate_chain "${2:-base}") + +echo "🔍 Scanning token $TOKEN on $CHAIN..." +echo "" + +RESPONSE=$(vigil_call vigil_scan_token "{\"token\":\"$TOKEN\",\"chain\":\"$CHAIN\"}") + +SAFETY=$(echo "$RESPONSE" | jq -r '.safety_score') +RISK=$(echo "$RESPONSE" | jq -r '.risk_level') +NAME=$(echo "$RESPONSE" | jq -r '.token_name // "Unknown"') +SYMBOL=$(echo "$RESPONSE" | jq -r '.token_symbol // "???"') +ICON=$(risk_icon "$RISK") + +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo " $ICON $NAME ($SYMBOL)" +echo " Safety Score: $SAFETY/100 | Risk Level: ${RISK^^}" +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo "" + +echo "📋 Findings:" +echo "$RESPONSE" | jq -r '.findings[]? | + " \(if .severity == "critical" then "🔴" elif .severity == "high" then "🟠" elif .severity == "medium" then "🟡" else "🟢" end) [\(.category)] \(.message)"' +echo "" + +echo "📄 Contract Info:" +echo " Proxy: $(echo "$RESPONSE" | jq -r '.contract.is_proxy // false')" +echo " Verified: $(echo "$RESPONSE" | jq -r '.contract.verified // false')" +echo " Renounced: $(echo "$RESPONSE" | jq -r '.contract.ownership_renounced // false')" +echo "" + +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo "$RESPONSE" | jq -r '" 💡 \(.recommendation)"' +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"