Skill: belimad/pumpclaw-agent (version 1.0.1)

--- name: pumpclaw-agent description: Generate customer-ready Telegram polling bots + an Express-style web server that integrate Pump.fun Tokenized Agent payments using @pump-fun/agent-payments-sdk (build invoices, accept payments, and verify invoices on Solana). Use when asked for pump.fun / pumpfun agent integrations, tokenized agent payment flows, invoice verification, or a Telegram+web bot scaffold for Pump Tokenized Agents. --- # PumpClaw Agent — Pump.fun Tokenized Agents + Telegram + Web Server This skill stamps a reusable template project and customizes it for a customer. Template: - `assets/template/` Reference: - `references/PUMP_TOKENIZED_AGENTS.md` ## Before you start — required info Ask for these before writing code: 1. **Agent token mint address** (pump.fun Tokenized Agent mint) 2. **Payment currency** (USDC or wSOL) → determines `CURRENCY_MINT` 3. **Price** (smallest units: USDC=6 decimals, SOL=9 decimals) 4. **What to deliver after payment** (what the bot/server unlocks) 5. **Solana RPC URL** (must support `sendTransaction`) 6. **Telegram commands** the bot should expose (and where alerts/messages go) ## Safety rules (must follow) - Never log or output private keys / secret key material. - Never sign transactions on behalf of the user. - Always verify payments server-side via `validateInvoicePayment` before delivering service. - Validate `amount > 0`, and ensure `endTime > startTime`. ## Workflow ### Step 1 — Stamp the template Copy `assets/template/` into a new customer folder (project slug). ### Step 2 — Configure env vars Ensure `.env.example` includes: - `SOLANA_RPC_URL` - `AGENT_TOKEN_MINT_ADDRESS` - `CURRENCY_MINT` - `TELEGRAM_BOT_TOKEN` - `PORT` Do not create/commit real `.env`. ### Step 3 — Implement Pump Tokenized Agent payment flow Use `@pump-fun/agent-payments-sdk`: - Build payment instructions with `buildAcceptPaymentInstructions`. - Verify with `validateInvoicePayment` on the server. If a frontend wallet flow is requested, follow the Pump reference skill (see `references/PUMP_TOKENIZED_AGENTS.md`). ### Step 4 — Telegram bot (polling) Implement requested commands. Always include `/help`. ### Step 5 — Web server endpoints Always include: - `GET /health` → `{ ok: true }` Add payment-related endpoints only as requested (e.g. create invoice, verify invoice). ### Step 6 — Deliverables Provide: - the full project folder - run instructions - smoke test checklist

path: assets/template/README-FAST.md
content: # FAST PATH: standalone Telegram demo bot + local billing service

You now have:
- Billing service (localhost): http://127.0.0.1:3033
- Standalone Telegram bot script: src/standalone-telegram.cjs

## 1) Put your Telegram bot token into env

Create env file:

```bash
cd /data/.openclaw/workspace/demo-billing
cp .env.standalone.example .env.standalone
nano .env.standalone
```

Set:
- TELEGRAM_BOT_TOKEN=... (from @BotFather)

## 2) Run standalone bot

```bash
cd /data/.openclaw/workspace/demo-billing
set -a && . ./.env.standalone && set +a
node src/standalone-telegram.cjs
```

Commands:
- /deposit
- /confirm <lamports>
- /balance


path: assets/template/README.md
content: # demo-billing

Demo services for Telegram funding → per-user wallet → server pays Pump invoice → credits.

## Setup

```bash
cd demo-billing
cp .env.example .env
# edit .env and set:
# - TREASURY_SECRET_KEY_BASE58
# - API_TOKEN
npm start
```

Health check:

```bash
curl http://127.0.0.1:3033/health
```

## API
All endpoints (except /health) require header:

`x-api-[REDACTED_SECRET]`

- `POST /deposit-wallet { telegramUserId }` → `{ depositAddress }`
- `POST /fund-and-credit { telegramUserId, depositLamports }`
- `POST /balance { telegramUserId }`
- `POST /spend { telegramUserId, credits }`


path: assets/template/package-lock.json
content: {
  "name": "demo-billing",
  "version": "1.0.0",
  "lockfileVersion": 3,
  "requires": true,
  "packages": {
    "": {
      "name": "demo-billing",
      "version": "1.0.0",
      "license": "ISC",
      "dependencies": {
        "@fastify/rate-limit": "^10.3.0",
        "@pump-fun/agent-payments-sdk": "^3.0.0",
        "@solana/web3.js": "^1.98.4",
        "better-sqlite3": "^12.6.2",
        "bs58": "^6.0.0",
        "dotenv": "^17.3.1",
        "fastify": "^5.8.2",
        "fastify-rate-limit": "^5.8.0",
        "grammy": "^1.41.1",
        "zod": "^4.3.6"
      }
    },
    "node_modules/@babel/runtime": {
      "version": "7.28.6",
      "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.6.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": ">=6.9.0"
      }
    },
    "node_modules/@coral-xyz/anchor": {
      "version": "0.31.1",
      "resolved": "https://registry.npmjs.org/@coral-xyz/anchor/-/anchor-0.31.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "(MIT OR Apache-2.0)",
      "dependencies": {
        "@coral-xyz/anchor-errors": "^0.31.1",
        "@coral-xyz/borsh": "^0.31.1",
        "@noble/hashes": "^1.3.1",
        "@solana/web3.js": "^1.69.0",
        "bn.js": "^5.1.2",
        "bs58": "^4.0.1",
        "buffer-layout": "^1.2.2",
        "camelcase": "^6.3.0",
        "cross-fetch": "^3.1.5",
        "eventemitter3": "^4.0.7",
        "pako": "^2.0.3",
        "superstruct": "^0.15.4",
        "toml": "^3.0.0"
      },
      "engines": {
        "node": ">=17"
      }
    },
    "node_modules/@coral-xyz/anchor-errors": {
      "version": "0.31.1",
      "resolved": "https://registry.npmjs.org/@coral-xyz/anchor-errors/-/anchor-errors-0.31.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "Apache-2.0",
      "engines": {
        "node": ">=10"
      }
    },
    "node_modules/@coral-xyz/anchor/node_modules/base-x": {
      "version": "3.0.11",
      "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.11.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "safe-buffer": "^5.0.1"
      }
    },
    "node_modules/@coral-xyz/anchor/node_modules/bs58": {
      "version": "4.0.1",
      "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "base-x": "^3.0.2"
      }
    },
    "node_modules/@coral-xyz/borsh": {
      "version": "0.31.1",
      "resolved": "https://registry.npmjs.org/@coral-xyz/borsh/-/borsh-0.31.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "Apache-2.0",
      "dependencies": {
        "bn.js": "^5.1.2",
        "buffer-layout": "^1.2.0"
      },
      "engines": {
        "node": ">=10"
      },
      "peerDependencies": {
        "@solana/web3.js": "^1.69.0"
      }
    },
    "node_modules/@fastify/ajv-compiler": {
      "version": "4.0.5",
      "resolved": "https://registry.npmjs.org/@fastify/ajv-compiler/-/ajv-compiler-4.0.5.tgz",
      "integrity": [REDACTED_SECRET],
      "funding": [
        {
          "type": "github",
          "url": "https://github.com/sponsors/fastify"
        },
        {
          "type": "opencollective",
          "url": "https://opencollective.com/fastify"
        }
      ],
      "license": "MIT",
      "dependencies": {
        "ajv": "^8.12.0",
        "ajv-formats": "^3.0.1",
        "fast-uri": "^3.0.0"
      }
    },
    "node_modules/@fastify/error": {
      "version": "4.2.0",
      "resolved": "https://registry.npmjs.org/@fastify/error/-/error-4.2.0.tgz",
      "integrity": [REDACTED_SECRET],
      "funding": [
        {
          "type": "github",
          "url": "https://github.com/sponsors/fastify"
        },
        {
          "type": "opencollective",
          "url": "https://opencollective.com/fastify"
        }
      ],
      "license": "MIT"
    },
    "node_modules/@fastify/fast-json-stringify-compiler": {
      "version": "5.0.3",
      "resolved": "https://registry.npmjs.org/@fastify/fast-json-stringify-compiler/-/fast-json-stringify-compiler-5.0.3.tgz",
      "integrity": [REDACTED_SECRET],
      "funding": [
        {
          "type": "github",
          "url": "https://github.com/sponsors/fastify"
        },
        {
          "type": "opencollective",
          "url": "https://opencollective.com/fastify"
        }
      ],
      "license": "MIT",
      "dependencies": {
        "fast-json-stringify": "^6.0.0"
      }
    },
    "node_modules/@fastify/forwarded": {
      "version": "3.0.1",
      "resolved": "https://registry.npmjs.org/@fastify/forwarded/-/forwarded-3.0.1.tgz",
      "integrity": [REDACTED_SECRET],
      "funding": [
        {
          "type": "github",
          "url": "https://github.com/sponsors/fastify"
        },
        {
          "type": "opencollective",
          "url": "https://opencollective.com/fastify"
        }
      ],
      "license": "MIT"
    },
    "node_modules/@fastify/merge-json-schemas": {
      "version": "0.2.1",
      "resolved": "https://registry.npmjs.org/@fastify/merge-json-schemas/-/merge-json-schemas-0.2.1.tgz",
      "integrity": [REDACTED_SECRET],
      "funding": [
        {
          "type": "github",
          "url": "https://github.com/sponsors/fastify"
        },
        {
          "type": "opencollective",
          "url": "https://opencollective.com/fastify"
        }
      ],
      "license": "MIT",
      "dependencies": {
        "dequal": "^2.0.3"
      }
    },
    "node_modules/@fastify/proxy-addr": {
      "version": "5.1.0",
      "resolved": "https://registry.npmjs.org/@fastify/proxy-addr/-/proxy-addr-5.1.0.tgz",
      "integrity": [REDACTED_SECRET],
      "funding": [
        {
          "type": "github",
          "url": "https://github.com/sponsors/fastify"
        },
        {
          "type": "opencollective",
          "url": "https://opencollective.com/fastify"
        }
      ],
      "license": "MIT",
      "dependencies": {
        "@fastify/forwarded": "^3.0.0",
        "ipaddr.js": "^2.1.0"
      }
    },
    "node_modules/@fastify/rate-limit": {
      "version": "10.3.0",
      "resolved": "https://registry.npmjs.org/@fastify/rate-limit/-/rate-limit-10.3.0.tgz",
      "integrity": [REDACTED_SECRET],
      "funding": [
        {
          "type": "github",
          "url": "https://github.com/sponsors/fastify"
        },
        {
          "type": "opencollective",
          "url": "https://opencollective.com/fastify"
        }
      ],
      "license": "MIT",
      "dependencies": {
        "@lukeed/ms": "^2.0.2",
        "fastify-plugin": "^5.0.0",
        "toad-cache": "^3.7.0"
      }
    },
    "node_modules/@fastify/rate-limit/node_modules/fastify-plugin": {
      "version": "5.1.0",
      "resolved": "https://registry.npmjs.org/fastify-plugin/-/fastify-plugin-5.1.0.tgz",
      "integrity": [REDACTED_SECRET],
      "funding": [
        {
          "type": "github",
          "url": "https://github.com/sponsors/fastify"
        },
        {
          "type": "opencollective",
          "url": "https://opencollective.com/fastify"
        }
      ],
      "license": "MIT"
    },
    "node_modules/@grammyjs/types": {
      "version": "3.25.0",
      "resolved": "https://registry.npmjs.org/@grammyjs/types/-/types-3.25.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT"
    },
    "node_modules/@lukeed/ms": {
      "version": "2.0.2",
      "resolved": "https://registry.npmjs.org/@lukeed/ms/-/ms-2.0.2.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": ">=8"
      }
    },
    "node_modules/@noble/curves": {
      "version": "1.9.7",
      "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.7.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "@noble/hashes": "1.8.0"
      },
      "engines": {
        "node": "^14.21.3 || >=16"
      },
      "funding": {
        "url": "https://paulmillr.com/funding/"
      }
    },
    "node_modules/@noble/hashes": {
      "version": "1.8.0",
      "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": "^14.21.3 || >=16"
      },
      "funding": {
        "url": "https://paulmillr.com/funding/"
      }
    },
    "node_modules/@pinojs/redact": {
      "version": "0.4.0",
      "resolved": "https://registry.npmjs.org/@pinojs/redact/-/redact-0.4.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT"
    },
    "node_modules/@pump-fun/agent-payments-sdk": {
      "version": "3.0.0",
      "resolved": "https://registry.npmjs.org/@pump-fun/agent-payments-sdk/-/agent-payments-sdk-3.0.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "ISC",
      "dependencies": {
        "@coral-xyz/anchor": "^0.31.1",
        "@solana/spl-token": "^0.4.9",
        "@solana/web3.js": "^1.98.0"
      },
      "optionalDependencies": {
        "@rollup/rollup-linux-x64-gnu": "*"
      }
    },
    "node_modules/@rollup/rollup-linux-x64-gnu": {
      "version": "4.59.0",
      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.59.0.tgz",
      "integrity": [REDACTED_SECRET],
      "cpu": [
        "x64"
      ],
      "license": "MIT",
      "optional": true,
      "os": [
        "linux"
      ]
    },
    "node_modules/@solana/buffer-layout": {
      "version": "4.0.1",
      "resolved": "https://registry.npmjs.org/@solana/buffer-layout/-/buffer-layout-4.0.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "buffer": "~6.0.3"
      },
      "engines": {
        "node": ">=5.10"
      }
    },
    "node_modules/@solana/buffer-layout-utils": {
      "version": "0.2.0",
      "resolved": "https://registry.npmjs.org/@solana/buffer-layout-utils/-/buffer-layout-utils-0.2.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "Apache-2.0",
      "dependencies": {
        "@solana/buffer-layout": "^4.0.0",
        "@solana/web3.js": "^1.32.0",
        "bigint-buffer": "^1.1.5",
        "bignumber.js": "^9.0.1"
      },
      "engines": {
        "node": ">= 10"
      }
    },
    "node_modules/@solana/codecs": {
      "version": "2.0.0-rc.1",
      "resolved": "https://registry.npmjs.org/@solana/codecs/-/codecs-2.0.0-rc.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "@solana/codecs-core": "2.0.0-rc.1",
        "@solana/codecs-data-structures": "2.0.0-rc.1",
        "@solana/codecs-numbers": "2.0.0-rc.1",
        "@solana/codecs-strings": "2.0.0-rc.1",
        "@solana/options": "2.0.0-rc.1"
      },
      "peerDependencies": {
        "typescript": ">=5"
      }
    },
    "node_modules/@solana/codecs-core": {
      "version": "2.0.0-rc.1",
      "resolved": "https://registry.npmjs.org/@solana/codecs-core/-/codecs-core-2.0.0-rc.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "@solana/errors": "2.0.0-rc.1"
      },
      "peerDependencies": {
        "typescript": ">=5"
      }
    },
    "node_modules/@solana/codecs-data-structures": {
      "version": "2.0.0-rc.1",
      "resolved": "https://registry.npmjs.org/@solana/codecs-data-structures/-/codecs-data-structures-2.0.0-rc.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "@solana/codecs-core": "2.0.0-rc.1",
        "@solana/codecs-numbers": "2.0.0-rc.1",
        "@solana/errors": "2.0.0-rc.1"
      },
      "peerDependencies": {
        "typescript": ">=5"
      }
    },
    "node_modules/@solana/codecs-numbers": {
      "version": "2.0.0-rc.1",
      "resolved": "https://registry.npmjs.org/@solana/codecs-numbers/-/codecs-numbers-2.0.0-rc.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "@solana/codecs-core": "2.0.0-rc.1",
        "@solana/errors": "2.0.0-rc.1"
      },
      "peerDependencies": {
        "typescript": ">=5"
      }
    },
    "node_modules/@solana/codecs-strings": {
      "version": "2.0.0-rc.1",
      "resolved": "https://registry.npmjs.org/@solana/codecs-strings/-/codecs-strings-2.0.0-rc.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "@solana/codecs-core": "2.0.0-rc.1",
        "@solana/codecs-numbers": "2.0.0-rc.1",
        "@solana/errors": "2.0.0-rc.1"
      },
      "peerDependencies": {
        "fastestsmallesttextencoderdecoder": "^1.0.22",
        "typescript": ">=5"
      }
    },
    "node_modules/@solana/errors": {
      "version": "2.0.0-rc.1",
      "resolved": "https://registry.npmjs.org/@solana/errors/-/errors-2.0.0-rc.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "chalk": "^5.3.0",
        "commander": "^12.1.0"
      },
      "bin": {
        "errors": "bin/cli.mjs"
      },
      "peerDependencies": {
        "typescript": ">=5"
      }
    },
    "node_modules/@solana/options": {
      "version": "2.0.0-rc.1",
      "resolved": "https://registry.npmjs.org/@solana/options/-/options-2.0.0-rc.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "@solana/codecs-core": "2.0.0-rc.1",
        "@solana/codecs-data-structures": "2.0.0-rc.1",
        "@solana/codecs-numbers": "2.0.0-rc.1",
        "@solana/codecs-strings": "2.0.0-rc.1",
        "@solana/errors": "2.0.0-rc.1"
      },
      "peerDependencies": {
        "typescript": ">=5"
      }
    },
    "node_modules/@solana/spl-token": {
      "version": "0.4.14",
      "resolved": "https://registry.npmjs.org/@solana/spl-token/-/spl-token-0.4.14.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "Apache-2.0",
      "dependencies": {
        "@solana/buffer-layout": "^4.0.0",
        "@solana/buffer-layout-utils": "^0.2.0",
        "@solana/spl-token-group": "^0.0.7",
        "@solana/spl-token-metadata": "^0.1.6",
        "buffer": "^6.0.3"
      },
      "engines": {
        "node": ">=16"
      },
      "peerDependencies": {
        "@solana/web3.js": "^1.95.5"
      }
    },
    "node_modules/@solana/spl-token-group": {
      "version": "0.0.7",
      "resolved": "https://registry.npmjs.org/@solana/spl-token-group/-/spl-token-group-0.0.7.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "Apache-2.0",
      "dependencies": {
        "@solana/codecs": "2.0.0-rc.1"
      },
      "engines": {
        "node": ">=16"
      },
      "peerDependencies": {
        "@solana/web3.js": "^1.95.3"
      }
    },
    "node_modules/@solana/spl-token-metadata": {
      "version": "0.1.6",
      "resolved": "https://registry.npmjs.org/@solana/spl-token-metadata/-/spl-token-metadata-0.1.6.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "Apache-2.0",
      "dependencies": {
        "@solana/codecs": "2.0.0-rc.1"
      },
      "engines": {
        "node": ">=16"
      },
      "peerDependencies": {
        "@solana/web3.js": "^1.95.3"
      }
    },
    "node_modules/@solana/web3.js": {
      "version": "1.98.4",
      "resolved": "https://registry.npmjs.org/@solana/web3.js/-/web3.js-1.98.4.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "@babel/runtime": "^7.25.0",
        "@noble/curves": "^1.4.2",
        "@noble/hashes": "^1.4.0",
        "@solana/buffer-layout": "^4.0.1",
        "@solana/codecs-numbers": "^2.1.0",
        "agentkeepalive": "^4.5.0",
        "bn.js": "^5.2.1",
        "borsh": "^0.7.0",
        "bs58": "^4.0.1",
        "buffer": "6.0.3",
        "fast-stable-stringify": "^1.0.0",
        "jayson": "^4.1.1",
        "node-fetch": "^2.7.0",
        "rpc-websockets": "^9.0.2",
        "superstruct": "^2.0.2"
      }
    },
    "node_modules/@solana/web3.js/node_modules/@solana/codecs-core": {
      "version": "2.3.0",
      "resolved": "https://registry.npmjs.org/@solana/codecs-core/-/codecs-core-2.3.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "@solana/errors": "2.3.0"
      },
      "engines": {
        "node": ">=20.18.0"
      },
      "peerDependencies": {
        "typescript": ">=5.3.3"
      }
    },
    "node_modules/@solana/web3.js/node_modules/@solana/codecs-numbers": {
      "version": "2.3.0",
      "resolved": "https://registry.npmjs.org/@solana/codecs-numbers/-/codecs-numbers-2.3.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "@solana/codecs-core": "2.3.0",
        "@solana/errors": "2.3.0"
      },
      "engines": {
        "node": ">=20.18.0"
      },
      "peerDependencies": {
        "typescript": ">=5.3.3"
      }
    },
    "node_modules/@solana/web3.js/node_modules/@solana/errors": {
      "version": "2.3.0",
      "resolved": "https://registry.npmjs.org/@solana/errors/-/errors-2.3.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "chalk": "^5.4.1",
        "commander": "^14.0.0"
      },
      "bin": {
        "errors": "bin/cli.mjs"
      },
      "engines": {
        "node": ">=20.18.0"
      },
      "peerDependencies": {
        "typescript": ">=5.3.3"
      }
    },
    "node_modules/@solana/web3.js/node_modules/base-x": {
      "version": "3.0.11",
      "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.11.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "safe-buffer": "^5.0.1"
      }
    },
    "node_modules/@solana/web3.js/node_modules/bs58": {
      "version": "4.0.1",
      "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "base-x": "^3.0.2"
      }
    },
    "node_modules/@solana/web3.js/node_modules/commander": {
      "version": "14.0.3",
      "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.3.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": ">=20"
      }
    },
    "node_modules/@solana/web3.js/node_modules/superstruct": {
      "version": "2.0.2",
      "resolved": "https://registry.npmjs.org/superstruct/-/superstruct-2.0.2.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": ">=14.0.0"
      }
    },
    "node_modules/@swc/helpers": {
      "version": "0.5.19",
      "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.19.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "Apache-2.0",
      "dependencies": {
        "tslib": "^2.8.0"
      }
    },
    "node_modules/@types/connect": {
      "version": "3.4.38",
      "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "@types/node": "*"
      }
    },
    "node_modules/@types/node": {
      "version": "12.20.55",
      "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT"
    },
    "node_modules/@types/uuid": {
      "version": "10.0.0",
      "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-10.0.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT"
    },
    "node_modules/@types/ws": {
      "version": "7.4.7",
      "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.7.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "@types/node": "*"
      }
    },
    "node_modules/abort-controller": {
      "version": "3.0.0",
      "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "event-target-shim": "^5.0.0"
      },
      "engines": {
        "node": ">=6.5"
      }
    },
    "node_modules/abstract-logging": {
      "version": "2.0.1",
      "resolved": "https://registry.npmjs.org/abstract-logging/-/abstract-logging-2.0.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT"
    },
    "node_modules/agentkeepalive": {
      "version": "4.6.0",
      "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.6.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "humanize-ms": "^1.2.1"
      },
      "engines": {
        "node": ">= 8.0.0"
      }
    },
    "node_modules/ajv": {
      "version": "8.18.0",
      "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "fast-deep-equal": "^3.1.3",
        "fast-uri": "^3.0.1",
        "json-schema-traverse": "^1.0.0",
        "require-from-string": "^2.0.2"
      },
      "funding": {
        "type": "github",
        "url": "https://github.com/sponsors/epoberezkin"
      }
    },
    "node_modules/ajv-formats": {
      "version": "3.0.1",
      "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "ajv": "^8.0.0"
      },
      "peerDependencies": {
        "ajv": "^8.0.0"
      },
      "peerDependenciesMeta": {
        "ajv": {
          "optional": true
        }
      }
    },
    "node_modules/atomic-sleep": {
      "version": "1.0.0",
      "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": ">=8.0.0"
      }
    },
    "node_modules/avvio": {
      "version": "9.2.0",
      "resolved": "https://registry.npmjs.org/avvio/-/avvio-9.2.0.tgz",
      "integrity": [REDACTED_SECRET],
      "funding": [
        {
          "type": "github",
          "url": "https://github.com/sponsors/fastify"
        },
        {
          "type": "opencollective",
          "url": "https://opencollective.com/fastify"
        }
      ],
      "license": "MIT",
      "dependencies": {
        "@fastify/error": "^4.0.0",
        "fastq": "^1.17.1"
      }
    },
    "node_modules/base-x": {
      "version": "5.0.1",
      "resolved": "https://registry.npmjs.org/base-x/-/base-x-5.0.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT"
    },
    "node_modules/base64-js": {
      "version": "1.5.1",
      "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
      "integrity": [REDACTED_SECRET],
      "funding": [
        {
          "type": "github",
          "url": "https://github.com/sponsors/feross"
        },
        {
          "type": "patreon",
          "url": "https://www.patreon.com/feross"
        },
        {
          "type": "consulting",
          "url": "https://feross.org/support"
        }
      ],
      "license": "MIT"
    },
    "node_modules/better-sqlite3": {
      "version": "12.6.2",
      "resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-12.6.2.tgz",
      "integrity": [REDACTED_SECRET],
      "hasInstallScript": true,
      "license": "MIT",
      "dependencies": {
        "bindings": "^1.5.0",
        "prebuild-install": "^7.1.1"
      },
      "engines": {
        "node": "20.x || 22.x || 23.x || 24.x || 25.x"
      }
    },
    "node_modules/bigint-buffer": {
      "version": "1.1.5",
      "resolved": "https://registry.npmjs.org/bigint-buffer/-/bigint-buffer-1.1.5.tgz",
      "integrity": [REDACTED_SECRET],
      "hasInstallScript": true,
      "license": "Apache-2.0",
      "dependencies": {
        "bindings": "^1.3.0"
      },
      "engines": {
        "node": ">= 10.0.0"
      }
    },
    "node_modules/bignumber.js": {
      "version": "9.3.1",
      "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": "*"
      }
    },
    "node_modules/bindings": {
      "version": "1.5.0",
      "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "file-uri-to-path": "1.0.0"
      }
    },
    "node_modules/bl": {
      "version": "4.1.0",
      "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "buffer": "^5.5.0",
        "inherits": "^2.0.4",
        "readable-stream": "^3.4.0"
      }
    },
    "node_modules/bl/node_modules/buffer": {
      "version": "5.7.1",
      "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
      "integrity": [REDACTED_SECRET],
      "funding": [
        {
          "type": "github",
          "url": "https://github.com/sponsors/feross"
        },
        {
          "type": "patreon",
          "url": "https://www.patreon.com/feross"
        },
        {
          "type": "consulting",
          "url": "https://feross.org/support"
        }
      ],
      "license": "MIT",
      "dependencies": {
        "base64-js": "^1.3.1",
        "ieee754": "^1.1.13"
      }
    },
    "node_modules/bn.js": {
      "version": "5.2.3",
      "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.3.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT"
    },
    "node_modules/borsh": {
      "version": "0.7.0",
      "resolved": "https://registry.npmjs.org/borsh/-/borsh-0.7.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "Apache-2.0",
      "dependencies": {
        "bn.js": "^5.2.0",
        "bs58": "^4.0.0",
        "text-encoding-utf-8": "^1.0.2"
      }
    },
    "node_modules/borsh/node_modules/base-x": {
      "version": "3.0.11",
      "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.11.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "safe-buffer": "^5.0.1"
      }
    },
    "node_modules/borsh/node_modules/bs58": {
      "version": "4.0.1",
      "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "base-x": "^3.0.2"
      }
    },
    "node_modules/bs58": {
      "version": "6.0.0",
      "resolved": "https://registry.npmjs.org/bs58/-/bs58-6.0.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "base-x": "^5.0.0"
      }
    },
    "node_modules/buffer": {
      "version": "6.0.3",
      "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
      "integrity": [REDACTED_SECRET],
      "funding": [
        {
          "type": "github",
          "url": "https://github.com/sponsors/feross"
        },
        {
          "type": "patreon",
          "url": "https://www.patreon.com/feross"
        },
        {
          "type": "consulting",
          "url": "https://feross.org/support"
        }
      ],
      "license": "MIT",
      "dependencies": {
        "base64-js": "^1.3.1",
        "ieee754": "^1.2.1"
      }
    },
    "node_modules/buffer-layout": {
      "version": "1.2.2",
      "resolved": "https://registry.npmjs.org/buffer-layout/-/buffer-layout-1.2.2.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": ">=4.5"
      }
    },
    "node_modules/bufferutil": {
      "version": "4.1.0",
      "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.1.0.tgz",
      "integrity": [REDACTED_SECRET],
      "hasInstallScript": true,
      "license": "MIT",
      "optional": true,
      "dependencies": {
        "node-gyp-build": "^4.3.0"
      },
      "engines": {
        "node": ">=6.14.2"
      }
    },
    "node_modules/camelcase": {
      "version": "6.3.0",
      "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": ">=10"
      },
      "funding": {
        "url": "https://github.com/sponsors/sindresorhus"
      }
    },
    "node_modules/chalk": {
      "version": "5.6.2",
      "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": "^12.17.0 || ^14.13 || >=16.0.0"
      },
      "funding": {
        "url": "https://github.com/chalk/chalk?sponsor=1"
      }
    },
    "node_modules/chownr": {
      "version": "1.1.4",
      "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "ISC"
    },
    "node_modules/commander": {
      "version": "12.1.0",
      "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": ">=18"
      }
    },
    "node_modules/cookie": {
      "version": "1.1.1",
      "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": ">=18"
      },
      "funding": {
        "type": "opencollective",
        "url": "https://opencollective.com/express"
      }
    },
    "node_modules/cross-fetch": {
      "version": "3.2.0",
      "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.2.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "node-fetch": "^2.7.0"
      }
    },
    "node_modules/debug": {
      "version": "4.4.3",
      "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "ms": "^2.1.3"
      },
      "engines": {
        "node": ">=6.0"
      },
      "peerDependenciesMeta": {
        "supports-color": {
          "optional": true
        }
      }
    },
    "node_modules/decompress-response": {
      "version": "6.0.0",
      "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "mimic-response": "^3.1.0"
      },
      "engines": {
        "node": ">=10"
      },
      "funding": {
        "url": "https://github.com/sponsors/sindresorhus"
      }
    },
    "node_modules/deep-extend": {
      "version": "0.6.0",
      "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": ">=4.0.0"
      }
    },
    "node_modules/delay": {
      "version": "5.0.0",
      "resolved": "https://registry.npmjs.org/delay/-/delay-5.0.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": ">=10"
      },
      "funding": {
        "url": "https://github.com/sponsors/sindresorhus"
      }
    },
    "node_modules/dequal": {
      "version": "2.0.3",
      "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": ">=6"
      }
    },
    "node_modules/detect-libc": {
      "version": "2.1.2",
      "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "Apache-2.0",
      "engines": {
        "node": ">=8"
      }
    },
    "node_modules/dotenv": {
      "version": "17.3.1",
      "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.3.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "BSD-2-Clause",
      "engines": {
        "node": ">=12"
      },
      "funding": {
        "url": "https://dotenvx.com"
      }
    },
    "node_modules/end-of-stream": {
      "version": "1.4.5",
      "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "once": "^1.4.0"
      }
    },
    "node_modules/es6-promise": {
      "version": "4.2.8",
      "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT"
    },
    "node_modules/es6-promisify": {
      "version": "5.0.0",
      "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "es6-promise": "^4.0.3"
      }
    },
    "node_modules/event-target-shim": {
      "version": "5.0.1",
      "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": ">=6"
      }
    },
    "node_modules/eventemitter3": {
      "version": "4.0.7",
      "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT"
    },
    "node_modules/expand-template": {
      "version": "2.0.3",
      "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "(MIT OR WTFPL)",
      "engines": {
        "node": ">=6"
      }
    },
    "node_modules/eyes": {
      "version": "0.1.8",
      "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz",
      "integrity": [REDACTED_SECRET],
      "engines": {
        "node": "> 0.1.90"
      }
    },
    "node_modules/fast-decode-uri-component": {
      "version": "1.0.1",
      "resolved": "https://registry.npmjs.org/fast-decode-uri-component/-/fast-decode-uri-component-1.0.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT"
    },
    "node_modules/fast-deep-equal": {
      "version": "3.1.3",
      "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT"
    },
    "node_modules/fast-json-stringify": {
      "version": "6.3.0",
      "resolved": "https://registry.npmjs.org/fast-json-stringify/-/fast-json-stringify-6.3.0.tgz",
      "integrity": [REDACTED_SECRET],
      "funding": [
        {
          "type": "github",
          "url": "https://github.com/sponsors/fastify"
        },
        {
          "type": "opencollective",
          "url": "https://opencollective.com/fastify"
        }
      ],
      "license": "MIT",
      "dependencies": {
        "@fastify/merge-json-schemas": "^0.2.0",
        "ajv": "^8.12.0",
        "ajv-formats": "^3.0.1",
        "fast-uri": "^3.0.0",
        "json-schema-ref-resolver": "^3.0.0",
        "rfdc": "^1.2.0"
      }
    },
    "node_modules/fast-querystring": {
      "version": "1.1.2",
      "resolved": "https://registry.npmjs.org/fast-querystring/-/fast-querystring-1.1.2.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "fast-decode-uri-component": "^1.0.1"
      }
    },
    "node_modules/fast-stable-stringify": {
      "version": "1.0.0",
      "resolved": "https://registry.npmjs.org/fast-stable-stringify/-/fast-stable-stringify-1.0.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT"
    },
    "node_modules/fast-uri": {
      "version": "3.1.0",
      "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz",
      "integrity": [REDACTED_SECRET],
      "funding": [
        {
          "type": "github",
          "url": "https://github.com/sponsors/fastify"
        },
        {
          "type": "opencollective",
          "url": "https://opencollective.com/fastify"
        }
      ],
      "license": "BSD-3-Clause"
    },
    "node_modules/fastestsmallesttextencoderdecoder": {
      "version": "1.0.22",
      "resolved": "https://registry.npmjs.org/fastestsmallesttextencoderdecoder/-/fastestsmallesttextencoderdecoder-1.0.22.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "CC0-1.0",
      "peer": true
    },
    "node_modules/fastify": {
      "version": "5.8.2",
      "resolved": "https://registry.npmjs.org/fastify/-/fastify-5.8.2.tgz",
      "integrity": [REDACTED_SECRET],
      "funding": [
        {
          "type": "github",
          "url": "https://github.com/sponsors/fastify"
        },
        {
          "type": "opencollective",
          "url": "https://opencollective.com/fastify"
        }
      ],
      "license": "MIT",
      "dependencies": {
        "@fastify/ajv-compiler": "^4.0.5",
        "@fastify/error": "^4.0.0",
        "@fastify/fast-json-stringify-compiler": "^5.0.0",
        "@fastify/proxy-addr": "^5.0.0",
        "abstract-logging": "^2.0.1",
        "avvio": "^9.0.0",
        "fast-json-stringify": "^6.0.0",
        "find-my-way": "^9.0.0",
        "light-my-request": "^6.0.0",
        "pino": "^9.14.0 || ^10.1.0",
        "process-warning": "^5.0.0",
        "rfdc": "^1.3.1",
        "secure-json-parse": "^4.0.0",
        "semver": "^7.6.0",
        "toad-cache": "^3.7.0"
      }
    },
    "node_modules/fastify-plugin": {
      "version": "3.0.1",
      "resolved": "https://registry.npmjs.org/fastify-plugin/-/fastify-plugin-3.0.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT"
    },
    "node_modules/fastify-rate-limit": {
      "version": "5.8.0",
      "resolved": "https://registry.npmjs.org/fastify-rate-limit/-/fastify-rate-limit-5.8.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "fastify-plugin": "^3.0.1",
        "ms": "^2.1.3",
        "tiny-lru": "^8.0.1"
      }
    },
    "node_modules/fastq": {
      "version": "1.20.1",
      "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "ISC",
      "dependencies": {
        "reusify": "^1.0.4"
      }
    },
    "node_modules/file-uri-to-path": {
      "version": "1.0.0",
      "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT"
    },
    "node_modules/find-my-way": {
      "version": "9.5.0",
      "resolved": "https://registry.npmjs.org/find-my-way/-/find-my-way-9.5.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "fast-deep-equal": "^3.1.3",
        "fast-querystring": "^1.0.0",
        "safe-regex2": "^5.0.0"
      },
      "engines": {
        "node": ">=20"
      }
    },
    "node_modules/fs-constants": {
      "version": "1.0.0",
      "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT"
    },
    "node_modules/github-from-package": {
      "version": "0.0.0",
      "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT"
    },
    "node_modules/grammy": {
      "version": "1.41.1",
      "resolved": "https://registry.npmjs.org/grammy/-/grammy-1.41.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "@grammyjs/types": "3.25.0",
        "abort-controller": "^3.0.0",
        "debug": "^4.4.3",
        "node-fetch": "^2.7.0"
      },
      "engines": {
        "node": "^12.20.0 || >=14.13.1"
      }
    },
    "node_modules/humanize-ms": {
      "version": "1.2.1",
      "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "ms": "^2.0.0"
      }
    },
    "node_modules/ieee754": {
      "version": "1.2.1",
      "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
      "integrity": [REDACTED_SECRET],
      "funding": [
        {
          "type": "github",
          "url": "https://github.com/sponsors/feross"
        },
        {
          "type": "patreon",
          "url": "https://www.patreon.com/feross"
        },
        {
          "type": "consulting",
          "url": "https://feross.org/support"
        }
      ],
      "license": "BSD-3-Clause"
    },
    "node_modules/inherits": {
      "version": "2.0.4",
      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "ISC"
    },
    "node_modules/ini": {
      "version": "1.3.8",
      "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "ISC"
    },
    "node_modules/ipaddr.js": {
      "version": "2.3.0",
      "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.3.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": ">= 10"
      }
    },
    "node_modules/isomorphic-ws": {
      "version": "4.0.1",
      "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "peerDependencies": {
        "ws": "*"
      }
    },
    "node_modules/jayson": {
      "version": "4.3.0",
      "resolved": "https://registry.npmjs.org/jayson/-/jayson-4.3.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "@types/connect": "^3.4.33",
        "@types/node": "^12.12.54",
        "@types/ws": "^7.4.4",
        "commander": "^2.20.3",
        "delay": "^5.0.0",
        "es6-promisify": "^5.0.0",
        "eyes": "^0.1.8",
        "isomorphic-ws": "^4.0.1",
        "json-stringify-safe": "^5.0.1",
        "stream-json": "^1.9.1",
        "uuid": "^8.3.2",
        "ws": "^7.5.10"
      },
      "bin": {
        "jayson": "bin/jayson.js"
      },
      "engines": {
        "node": ">=8"
      }
    },
    "node_modules/jayson/node_modules/commander": {
      "version": "2.20.3",
      "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT"
    },
    "node_modules/json-schema-ref-resolver": {
      "version": "3.0.0",
      "resolved": "https://registry.npmjs.org/json-schema-ref-resolver/-/json-schema-ref-resolver-3.0.0.tgz",
      "integrity": [REDACTED_SECRET],
      "funding": [
        {
          "type": "github",
          "url": "https://github.com/sponsors/fastify"
        },
        {
          "type": "opencollective",
          "url": "https://opencollective.com/fastify"
        }
      ],
      "license": "MIT",
      "dependencies": {
        "dequal": "^2.0.3"
      }
    },
    "node_modules/json-schema-traverse": {
      "version": "1.0.0",
      "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT"
    },
    "node_modules/json-stringify-safe": {
      "version": "5.0.1",
      "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "ISC"
    },
    "node_modules/light-my-request": {
      "version": "6.6.0",
      "resolved": "https://registry.npmjs.org/light-my-request/-/light-my-request-6.6.0.tgz",
      "integrity": [REDACTED_SECRET],
      "funding": [
        {
          "type": "github",
          "url": "https://github.com/sponsors/fastify"
        },
        {
          "type": "opencollective",
          "url": "https://opencollective.com/fastify"
        }
      ],
      "license": "BSD-3-Clause",
      "dependencies": {
        "cookie": "^1.0.1",
        "process-warning": "^4.0.0",
        "set-cookie-parser": "^2.6.0"
      }
    },
    "node_modules/light-my-request/node_modules/process-warning": {
      "version": "4.0.1",
      "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-4.0.1.tgz",
      "integrity": [REDACTED_SECRET],
      "funding": [
        {
          "type": "github",
          "url": "https://github.com/sponsors/fastify"
        },
        {
          "type": "opencollective",
          "url": "https://opencollective.com/fastify"
        }
      ],
      "license": "MIT"
    },
    "node_modules/mimic-response": {
      "version": "3.1.0",
      "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": ">=10"
      },
      "funding": {
        "url": "https://github.com/sponsors/sindresorhus"
      }
    },
    "node_modules/minimist": {
      "version": "1.2.8",
      "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/mkdirp-classic": {
      "version": "0.5.3",
      "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT"
    },
    "node_modules/ms": {
      "version": "2.1.3",
      "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT"
    },
    "node_modules/napi-build-utils": {
      "version": "2.0.0",
      "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-2.0.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT"
    },
    "node_modules/node-abi": {
      "version": "3.88.0",
      "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.88.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "semver": "^7.3.5"
      },
      "engines": {
        "node": ">=10"
      }
    },
    "node_modules/node-fetch": {
      "version": "2.7.0",
      "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "whatwg-url": "^5.0.0"
      },
      "engines": {
        "node": "4.x || >=6.0.0"
      },
      "peerDependencies": {
        "encoding": "^0.1.0"
      },
      "peerDependenciesMeta": {
        "encoding": {
          "optional": true
        }
      }
    },
    "node_modules/node-gyp-build": {
      "version": "4.8.4",
      "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "optional": true,
      "bin": {
        "node-gyp-build": "bin.js",
        "node-gyp-build-optional": "optional.js",
        "node-gyp-build-test": "build-test.js"
      }
    },
    "node_modules/on-exit-leak-free": {
      "version": "2.1.2",
      "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": ">=14.0.0"
      }
    },
    "node_modules/once": {
      "version": "1.4.0",
      "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "ISC",
      "dependencies": {
        "wrappy": "1"
      }
    },
    "node_modules/pako": {
      "version": "2.1.0",
      "resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "(MIT AND Zlib)"
    },
    "node_modules/pino": {
      "version": "10.3.1",
      "resolved": "https://registry.npmjs.org/pino/-/pino-10.3.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "@pinojs/redact": "^0.4.0",
        "atomic-sleep": "^1.0.0",
        "on-exit-leak-free": "^2.1.0",
        "pino-abstract-transport": "^3.0.0",
        "pino-std-serializers": "^7.0.0",
        "process-warning": "^5.0.0",
        "quick-format-unescaped": "^4.0.3",
        "real-require": "^0.2.0",
        "safe-stable-stringify": "^2.3.1",
        "sonic-boom": "^4.0.1",
        "thread-stream": "^4.0.0"
      },
      "bin": {
        "pino": "bin.js"
      }
    },
    "node_modules/pino-abstract-transport": {
      "version": "3.0.0",
      "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-3.0.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "split2": "^4.0.0"
      }
    },
    "node_modules/pino-std-serializers": {
      "version": "7.1.0",
      "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-7.1.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT"
    },
    "node_modules/prebuild-install": {
      "version": "7.1.3",
      "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.3.tgz",
      "integrity": [REDACTED_SECRET],
      "deprecated": "No longer maintained. Please contact the author of the relevant native addon; alternatives are available.",
      "license": "MIT",
      "dependencies": {
        "detect-libc": "^2.0.0",
        "expand-template": "^2.0.3",
        "github-from-package": "0.0.0",
        "minimist": "^1.2.3",
        "mkdirp-classic": "^0.5.3",
        "napi-build-utils": "^2.0.0",
        "node-abi": "^3.3.0",
        "pump": "^3.0.0",
        "rc": "^1.2.7",
        "simple-get": "^4.0.0",
        "tar-fs": "^2.0.0",
        "tunnel-agent": "^0.6.0"
      },
      "bin": {
        "prebuild-install": "bin.js"
      },
      "engines": {
        "node": ">=10"
      }
    },
    "node_modules/process-warning": {
      "version": "5.0.0",
      "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-5.0.0.tgz",
      "integrity": [REDACTED_SECRET],
      "funding": [
        {
          "type": "github",
          "url": "https://github.com/sponsors/fastify"
        },
        {
          "type": "opencollective",
          "url": "https://opencollective.com/fastify"
        }
      ],
      "license": "MIT"
    },
    "node_modules/pump": {
      "version": "3.0.4",
      "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "end-of-stream": "^1.1.0",
        "once": "^1.3.1"
      }
    },
    "node_modules/quick-format-unescaped": {
      "version": "4.0.4",
      "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT"
    },
    "node_modules/rc": {
      "version": "1.2.8",
      "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "(BSD-2-Clause OR MIT OR Apache-2.0)",
      "dependencies": {
        "deep-extend": "^0.6.0",
        "ini": "~1.3.0",
        "minimist": "^1.2.0",
        "strip-json-comments": "~2.0.1"
      },
      "bin": {
        "rc": "cli.js"
      }
    },
    "node_modules/readable-stream": {
      "version": "3.6.2",
      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "inherits": "^2.0.3",
        "string_decoder": "^1.1.1",
        "util-deprecate": "^1.0.1"
      },
      "engines": {
        "node": ">= 6"
      }
    },
    "node_modules/real-require": {
      "version": "0.2.0",
      "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": ">= 12.13.0"
      }
    },
    "node_modules/require-from-string": {
      "version": "2.0.2",
      "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": ">=0.10.0"
      }
    },
    "node_modules/ret": {
      "version": "0.5.0",
      "resolved": "https://registry.npmjs.org/ret/-/ret-0.5.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": ">=10"
      }
    },
    "node_modules/reusify": {
      "version": "1.1.0",
      "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "iojs": ">=1.0.0",
        "node": ">=0.10.0"
      }
    },
    "node_modules/rfdc": {
      "version": "1.4.1",
      "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT"
    },
    "node_modules/rpc-websockets": {
      "version": "9.3.5",
      "resolved": "https://registry.npmjs.org/rpc-websockets/-/rpc-websockets-9.3.5.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "LGPL-3.0-only",
      "dependencies": {
        "@swc/helpers": "^0.5.11",
        "@types/uuid": "^10.0.0",
        "@types/ws": "^8.2.2",
        "buffer": "^6.0.3",
        "eventemitter3": "^5.0.1",
        "uuid": "^11.0.0",
        "ws": "^8.5.0"
      },
      "funding": {
        "type": "paypal",
        "url": "https://paypal.me/kozjak"
      },
      "optionalDependencies": {
        "bufferutil": "^4.0.1",
        "utf-8-validate": "^6.0.0"
      }
    },
    "node_modules/rpc-websockets/node_modules/@types/ws": {
      "version": "8.18.1",
      "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "@types/node": "*"
      }
    },
    "node_modules/rpc-websockets/node_modules/eventemitter3": {
      "version": "5.0.4",
      "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT"
    },
    "node_modules/rpc-websockets/node_modules/utf-8-validate": {
      "version": "6.0.6",
      "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-6.0.6.tgz",
      "integrity": [REDACTED_SECRET],
      "hasInstallScript": true,
      "license": "MIT",
      "optional": true,
      "dependencies": {
        "node-gyp-build": "^4.3.0"
      },
      "engines": {
        "node": ">=6.14.2"
      }
    },
    "node_modules/rpc-websockets/node_modules/uuid": {
      "version": "11.1.0",
      "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz",
      "integrity": [REDACTED_SECRET],
      "funding": [
        "https://github.com/sponsors/broofa",
        "https://github.com/sponsors/ctavan"
      ],
      "license": "MIT",
      "bin": {
        "uuid": "dist/esm/bin/uuid"
      }
    },
    "node_modules/rpc-websockets/node_modules/ws": {
      "version": "8.19.0",
      "resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": ">=10.0.0"
      },
      "peerDependencies": {
        "bufferutil": "^4.0.1",
        "utf-8-validate": ">=5.0.2"
      },
      "peerDependenciesMeta": {
        "bufferutil": {
          "optional": true
        },
        "utf-8-validate": {
          "optional": true
        }
      }
    },
    "node_modules/safe-buffer": {
      "version": "5.2.1",
      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
      "integrity": [REDACTED_SECRET],
      "funding": [
        {
          "type": "github",
          "url": "https://github.com/sponsors/feross"
        },
        {
          "type": "patreon",
          "url": "https://www.patreon.com/feross"
        },
        {
          "type": "consulting",
          "url": "https://feross.org/support"
        }
      ],
      "license": "MIT"
    },
    "node_modules/safe-regex2": {
      "version": "5.1.0",
      "resolved": "https://registry.npmjs.org/safe-regex2/-/safe-regex2-5.1.0.tgz",
      "integrity": [REDACTED_SECRET],
      "funding": [
        {
          "type": "github",
          "url": "https://github.com/sponsors/fastify"
        },
        {
          "type": "opencollective",
          "url": "https://opencollective.com/fastify"
        }
      ],
      "license": "MIT",
      "dependencies": {
        "ret": "~0.5.0"
      },
      "bin": {
        "safe-regex2": "bin/safe-regex2.js"
      }
    },
    "node_modules/safe-stable-stringify": {
      "version": "2.5.0",
      "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": ">=10"
      }
    },
    "node_modules/secure-json-parse": {
      "version": "4.1.0",
      "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-4.1.0.tgz",
      "integrity": [REDACTED_SECRET],
      "funding": [
        {
          "type": "github",
          "url": "https://github.com/sponsors/fastify"
        },
        {
          "type": "opencollective",
          "url": "https://opencollective.com/fastify"
        }
      ],
      "license": "BSD-3-Clause"
    },
    "node_modules/semver": {
      "version": "7.7.4",
      "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "ISC",
      "bin": {
        "semver": "bin/semver.js"
      },
      "engines": {
        "node": ">=10"
      }
    },
    "node_modules/set-cookie-parser": {
      "version": "2.7.2",
      "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT"
    },
    "node_modules/simple-concat": {
      "version": "1.0.1",
      "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz",
      "integrity": [REDACTED_SECRET],
      "funding": [
        {
          "type": "github",
          "url": "https://github.com/sponsors/feross"
        },
        {
          "type": "patreon",
          "url": "https://www.patreon.com/feross"
        },
        {
          "type": "consulting",
          "url": "https://feross.org/support"
        }
      ],
      "license": "MIT"
    },
    "node_modules/simple-get": {
      "version": "4.0.1",
      "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz",
      "integrity": [REDACTED_SECRET],
      "funding": [
        {
          "type": "github",
          "url": "https://github.com/sponsors/feross"
        },
        {
          "type": "patreon",
          "url": "https://www.patreon.com/feross"
        },
        {
          "type": "consulting",
          "url": "https://feross.org/support"
        }
      ],
      "license": "MIT",
      "dependencies": {
        "decompress-response": "^6.0.0",
        "once": "^1.3.1",
        "simple-concat": "^1.0.0"
      }
    },
    "node_modules/sonic-boom": {
      "version": "4.2.1",
      "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-4.2.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "atomic-sleep": "^1.0.0"
      }
    },
    "node_modules/split2": {
      "version": "4.2.0",
      "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "ISC",
      "engines": {
        "node": ">= 10.x"
      }
    },
    "node_modules/stream-chain": {
      "version": "2.2.5",
      "resolved": "https://registry.npmjs.org/stream-chain/-/stream-chain-2.2.5.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "BSD-3-Clause"
    },
    "node_modules/stream-json": {
      "version": "1.9.1",
      "resolved": "https://registry.npmjs.org/stream-json/-/stream-json-1.9.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "BSD-3-Clause",
      "dependencies": {
        "stream-chain": "^2.2.5"
      }
    },
    "node_modules/string_decoder": {
      "version": "1.3.0",
      "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "safe-buffer": "~5.2.0"
      }
    },
    "node_modules/strip-json-comments": {
      "version": "2.0.1",
      "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": ">=0.10.0"
      }
    },
    "node_modules/superstruct": {
      "version": "0.15.5",
      "resolved": "https://registry.npmjs.org/superstruct/-/superstruct-0.15.5.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT"
    },
    "node_modules/tar-fs": {
      "version": "2.1.4",
      "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.4.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "chownr": "^1.1.1",
        "mkdirp-classic": "^0.5.2",
        "pump": "^3.0.0",
        "tar-stream": "^2.1.4"
      }
    },
    "node_modules/tar-stream": {
      "version": "2.2.0",
      "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "bl": "^4.0.3",
        "end-of-stream": "^1.4.1",
        "fs-constants": "^1.0.0",
        "inherits": "^2.0.3",
        "readable-stream": "^3.1.1"
      },
      "engines": {
        "node": ">=6"
      }
    },
    "node_modules/text-encoding-utf-8": {
      "version": "1.0.2",
      "resolved": "https://registry.npmjs.org/text-encoding-utf-8/-/text-encoding-utf-8-1.0.2.tgz",
      "integrity": [REDACTED_SECRET]
    },
    "node_modules/thread-stream": {
      "version": "4.0.0",
      "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-4.0.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "real-require": "^0.2.0"
      },
      "engines": {
        "node": ">=20"
      }
    },
    "node_modules/tiny-lru": {
      "version": "8.0.2",
      "resolved": "https://registry.npmjs.org/tiny-lru/-/tiny-lru-8.0.2.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "BSD-3-Clause",
      "engines": {
        "node": ">=6"
      }
    },
    "node_modules/toad-cache": {
      "version": "3.7.0",
      "resolved": "https://registry.npmjs.org/toad-cache/-/toad-cache-3.7.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": ">=12"
      }
    },
    "node_modules/toml": {
      "version": "3.0.0",
      "resolved": "https://registry.npmjs.org/toml/-/toml-3.0.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT"
    },
    "node_modules/tr46": {
      "version": "0.0.3",
      "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT"
    },
    "node_modules/tslib": {
      "version": "2.8.1",
      "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "0BSD"
    },
    "node_modules/tunnel-agent": {
      "version": "0.6.0",
      "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "Apache-2.0",
      "dependencies": {
        "safe-buffer": "^5.0.1"
      },
      "engines": {
        "node": "*"
      }
    },
    "node_modules/typescript": {
      "version": "5.9.3",
      "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "Apache-2.0",
      "peer": true,
      "bin": {
        "tsc": "bin/tsc",
        "tsserver": "bin/tsserver"
      },
      "engines": {
        "node": ">=14.17"
      }
    },
    "node_modules/utf-8-validate": {
      "version": "5.0.10",
      "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz",
      "integrity": [REDACTED_SECRET],
      "hasInstallScript": true,
      "license": "MIT",
      "optional": true,
      "peer": true,
      "dependencies": {
        "node-gyp-build": "^4.3.0"
      },
      "engines": {
        "node": ">=6.14.2"
      }
    },
    "node_modules/util-deprecate": {
      "version": "1.0.2",
      "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT"
    },
    "node_modules/uuid": {
      "version": "8.3.2",
      "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "bin": {
        "uuid": "dist/bin/uuid"
      }
    },
    "node_modules/webidl-conversions": {
      "version": "3.0.1",
      "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "BSD-2-Clause"
    },
    "node_modules/whatwg-url": {
      "version": "5.0.0",
      "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "tr46": "~0.0.3",
        "webidl-conversions": "^3.0.0"
      }
    },
    "node_modules/wrappy": {
      "version": "1.0.2",
      "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "ISC"
    },
    "node_modules/ws": {
      "version": "7.5.10",
      "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": ">=8.3.0"
      },
      "peerDependencies": {
        "bufferutil": "^4.0.1",
        "utf-8-validate": "^5.0.2"
      },
      "peerDependenciesMeta": {
        "bufferutil": {
          "optional": true
        },
        "utf-8-validate": {
          "optional": true
        }
      }
    },
    "node_modules/zod": {
      "version": "4.3.6",
      "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "funding": {
        "url": "https://github.com/sponsors/colinhacks"
      }
    }
  }
}


path: assets/template/package.json
content: {
  "name": "demo-billing",
  "version": "1.0.0",
  "description": "",
  "main": "src/server.cjs",
  "scripts": {
    "start": "node src/server.cjs"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "@fastify/rate-limit": "^10.3.0",
    "@pump-fun/agent-payments-sdk": "3.0.0",
    "@solana/web3.js": "^1.98.0",
    "better-sqlite3": "^12.6.2",
    "bs58": "^6.0.0",
    "dotenv": "^17.3.1",
    "fastify": "^5.8.2",
    "fastify-rate-limit": "^5.8.0",
    "grammy": "^1.41.1",
    "zod": "^4.3.6"
  }
}


path: assets/template/src/server.cjs
content: require('dotenv/config');

const Fastify = require('fastify');
const rateLimit = require('@fastify/rate-limit');
const Database = require('better-sqlite3');
const bs58 = require('bs58').default;
const { z } = require('zod');
const {
  Connection,
  Keypair,
  PublicKey,
  Transaction,
} = require('@solana/web3.js');
const { PumpAgent } = require('@pump-fun/agent-payments-sdk');

const envSchema = z.object({
  SOLANA_RPC_URL: z.string().url(),
  AGENT_TOKEN_MINT_ADDRESS: z.string().min(32),
  CURRENCY_MINT: z.string().min(32),
  LAMPORTS_PER_CREDIT: z.coerce.number().int().positive(),
  TREASURY_SECRET_KEY_BASE58: z.string().min(40),
  PORT: z.coerce.number().int().positive().default(3033),
  API_TOKEN: z.string().min(16),
  DB_PATH: z.string().default('./demo.db'),
});

const env = envSchema.parse(process.env);

const connection = new Connection(env.SOLANA_RPC_URL, 'confirmed');
const agentMint = new PublicKey(env.AGENT_TOKEN_MINT_ADDRESS);
const currencyMint = new PublicKey(env.CURRENCY_MINT);

const treasury = (() => {
  const [REDACTED_SECRET]);
  return Keypair.fromSecretKey(secret);
})();

const pumpAgent = new PumpAgent(agentMint, 'mainnet', connection);

const db = new Database(env.DB_PATH);

db.exec(`
CREATE TABLE IF NOT EXISTS users (
  telegram_user_id TEXT PRIMARY KEY,
  created_at INTEGER NOT NULL
);

CREATE TABLE IF NOT EXISTS deposit_wallets (
  telegram_user_id TEXT PRIMARY KEY,
  deposit_pubkey TEXT NOT NULL,
  deposit_secret_b58 TEXT NOT NULL,
  created_at INTEGER NOT NULL
);

CREATE TABLE IF NOT EXISTS credits (
  telegram_user_id TEXT PRIMARY KEY,
  balance_credits INTEGER NOT NULL
);

CREATE TABLE IF NOT EXISTS invoices (
  memo TEXT PRIMARY KEY,
  telegram_user_id TEXT NOT NULL,
  amount_lamports INTEGER NOT NULL,
  start_time INTEGER NOT NULL,
  end_time INTEGER NOT NULL,
  signature TEXT,
  status TEXT NOT NULL,
  created_at INTEGER NOT NULL
);
`);

function authHook(req, reply, done) {
  const [REDACTED_SECRET]'x-api-token'];
  if (token !== env.API_TOKEN) return reply.code(401).send({ error: 'unauthorized' });
  done();
}

function nowSec() {
  return Math.floor(Date.now() / 1000);
}

function ensureUser(telegramUserId) {
  db.prepare('INSERT OR IGNORE INTO users (telegram_user_id, created_at) VALUES (?, ?)')
    .run(telegramUserId, Date.now());
  db.prepare('INSERT OR IGNORE INTO credits (telegram_user_id, balance_credits) VALUES (?, 0)')
    .run(telegramUserId);
}

function getOrCreateDepositWallet(telegramUserId) {
  ensureUser(telegramUserId);
  const row = db.prepare('SELECT deposit_pubkey, deposit_secret_b58 FROM deposit_wallets WHERE telegram_user_id=?')
    .get(telegramUserId);
  if (row) return row;

  // DEMO: generate a new keypair per user and store secret in sqlite
  const kp = Keypair.generate();
  const secretB58 = bs58.encode(kp.secretKey);
  db.prepare('INSERT INTO deposit_wallets (telegram_user_id, deposit_pubkey, deposit_secret_b58, created_at) VALUES (?,?,?,?)')
    .run(telegramUserId, kp.publicKey.toBase58(), secretB58, Date.now());
  return { deposit_pubkey: kp.publicKey.toBase58(), deposit_secret_b58: secretB58 };
}

async function waitForDeposit(pubkeyStr, lamports, timeoutMs = 120_000) {
  const pubkey = new PublicKey(pubkeyStr);
  const start = Date.now();

  // FIX: if funds are already there (deposit happened before /confirm), accept.
  const initial = await connection.getBalance(pubkey, 'confirmed');
  if (initial >= lamports) {
    return { receivedLamports: initial, balance: initial, mode: 'absolute' };
  }

  while (Date.now() - start < timeoutMs) {
    await new Promise(r => setTimeout(r, 2500));
    const bal = await connection.getBalance(pubkey, 'confirmed');
    if (bal >= lamports) {
      return { receivedLamports: bal, balance: bal, mode: 'absolute' };
    }
  }
  return null;
}

async function buildAndPayInvoice({ payerKeypair, amountLamports }) {
  const memo = String(Math.floor(Math.random() * 900000000000) + 100000);
  const startTime = nowSec();
  const endTime = startTime + 3600; // 1 hour

  const ixs = await pumpAgent.buildAcceptPaymentInstructions({
    user: payerKeypair.publicKey,
    currencyMint,
    amount: String(amountLamports),
    memo,
    startTime: String(startTime),
    endTime: String(endTime),
  });

  const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash('confirmed');
  const tx = new Transaction({ recentBlockhash: blockhash, feePayer: payerKeypair.publicKey });
  tx.add(...ixs);
  tx.sign(payerKeypair);

  const sig = await connection.sendRawTransaction(tx.serialize(), {
    skipPreflight: false,
    preflightCommitment: 'confirmed',
  });

  await connection.confirmTransaction({ signature: sig, blockhash, lastValidBlockHeight }, 'confirmed');

  return { memo, startTime, endTime, signature: sig };
}

async function verifyInvoicePaid({ userPubkey, amountLamports, memo, startTime, endTime }) {
  return pumpAgent.validateInvoicePayment({
    user: userPubkey,
    currencyMint,
    amount: Number(amountLamports),
    memo: Number(memo),
    startTime: Number(startTime),
    endTime: Number(endTime),
  });
}

const fastify = Fastify({ logger: true });

fastify.register(rateLimit, {
  max: 60,
  timeWindow: '1 minute',
});

fastify.addHook('onRequest', (req, reply, done) => {
  if (req.url.startsWith('/health')) return done();
  return authHook(req, reply, done);
});

fastify.get('/health', async () => ({ ok: true }));

// Create/get deposit wallet
fastify.post('/deposit-wallet', async (req) => {
  const body = z.object({ telegramUserId: z.string().min(1) }).parse(req.body);
  const w = getOrCreateDepositWallet(body.telegramUserId);
  return { depositAddress: w.deposit_pubkey };
});

// Wait for deposit to the per-user wallet, then pay a Pump invoice FROM THAT WALLET.
fastify.post('/fund-and-credit', async (req) => {
  const body = z.object({
    telegramUserId: z.string().min(1),
    depositLamports: z.coerce.number().int().positive(),
    timeoutMs: z.coerce.number().int().positive().optional(),
  }).parse(req.body);

  ensureUser(body.telegramUserId);
  const w = getOrCreateDepositWallet(body.telegramUserId);

  // If we already have a verified invoice for this exact amount, just report current balance.
  const existingVerified = db.prepare(
    'SELECT memo, signature FROM invoices WHERE telegram_user_id=? AND amount_lamports=? AND status=? ORDER BY created_at DESC LIMIT 1'
  ).get(body.telegramUserId, body.depositLamports, 'verified');
  if (existingVerified) {
    const bal = db.prepare('SELECT balance_credits FROM credits WHERE telegram_user_id=?').get(body.telegramUserId);
    return {
      status: 'credited',
      creditsAdded: 0,
      balanceCredits: bal.balance_credits,
      memo: existingVerified.memo,
      signature: existingVerified.signature,
      depositAddress: w.deposit_pubkey,
    };
  }

  // If we already created an invoice for this exact amount but it wasn't verified yet, retry verification first.
  // If the existing tx failed on-chain, ignore it and create a fresh invoice.
  const existing = db.prepare(
    'SELECT memo, signature, start_time, end_time, status FROM invoices WHERE telegram_user_id=? AND amount_lamports=? ORDER BY created_at DESC LIMIT 1'
  ).get(body.telegramUserId, body.depositLamports);

  const payerKeypair = Keypair.fromSecretKey(bs58.decode(w.deposit_secret_b58));

  if (existing && existing.status === 'sent') {
    let failedOnChain = false;
    try {
      const st = await connection.getSignatureStatus(existing.signature, { searchTransactionHistory: true });
      failedOnChain = Boolean(st?.value?.err);
    } catch {}

    if (!failedOnChain) {
      const paid = await verifyInvoicePaid({
        userPubkey: payerKeypair.publicKey,
        amountLamports: body.depositLamports,
        memo: existing.memo,
        startTime: existing.start_time,
        endTime: existing.end_time,
      });

      if (paid) {
        const creditsToAdd = Math.floor(body.depositLamports / env.LAMPORTS_PER_CREDIT);
        db.prepare('UPDATE credits SET balance_credits = balance_credits + ? WHERE telegram_user_id=?')
          .run(creditsToAdd, body.telegramUserId);
        db.prepare('UPDATE invoices SET status=? WHERE memo=?').run('verified', existing.memo);
        const bal = db.prepare('SELECT balance_credits FROM credits WHERE telegram_user_id=?').get(body.telegramUserId);
        return {
          status: 'credited',
          creditsAdded: creditsToAdd,
          balanceCredits: bal.balance_credits,
          memo: existing.memo,
          signature: existing.signature,
          depositAddress: w.deposit_pubkey,
        };
      }

      return {
        status: 'invoice_not_verified_yet',
        memo: existing.memo,
        signature: existing.signature,
        depositAddress: w.deposit_pubkey,
      };
    }

    // mark failed and continue to create a new invoice
    db.prepare('UPDATE invoices SET status=? WHERE memo=?').run('failed', existing.memo);
  }

  const deposit = await waitForDeposit(w.deposit_pubkey, body.depositLamports, body.timeoutMs ?? 120_000);
  if (!deposit) {
    return { status: 'timeout', depositAddress: w.deposit_pubkey };
  }

  const { memo, startTime, endTime, signature } = await buildAndPayInvoice({
    payerKeypair,
    amountLamports: body.depositLamports,
  });

  // Note: amount_lamports stores the *deposit* lamports request (used for credit calculation)
  db.prepare('INSERT OR REPLACE INTO invoices (memo, telegram_user_id, amount_lamports, start_time, end_time, signature, status, created_at) VALUES (?,?,?,?,?,?,?,?)')
    .run(memo, body.telegramUserId, body.depositLamports, startTime, endTime, signature, 'sent', Date.now());

  const paid = await verifyInvoicePaid({
    userPubkey: payerKeypair.publicKey,
    amountLamports: body.depositLamports,
    memo,
    startTime,
    endTime,
  });

  if (!paid) {
    return { status: 'invoice_not_verified_yet', memo, signature, depositAddress: w.deposit_pubkey };
  }

  const creditsToAdd = Math.floor(body.depositLamports / env.LAMPORTS_PER_CREDIT);
  db.prepare('UPDATE credits SET balance_credits = balance_credits + ? WHERE telegram_user_id=?')
    .run(creditsToAdd, body.telegramUserId);
  db.prepare('UPDATE invoices SET status=? WHERE memo=?').run('verified', memo);

  const bal = db.prepare('SELECT balance_credits FROM credits WHERE telegram_user_id=?').get(body.telegramUserId);

  return {
    status: 'credited',
    creditsAdded: creditsToAdd,
    balanceCredits: bal.balance_credits,
    memo,
    signature,
    depositAddress: w.deposit_pubkey,
  };
});

fastify.post('/balance', async (req) => {
  const body = z.object({ telegramUserId: z.string().min(1) }).parse(req.body);
  ensureUser(body.telegramUserId);
  const bal = db.prepare('SELECT balance_credits FROM credits WHERE telegram_user_id=?').get(body.telegramUserId);
  return { balanceCredits: bal.balance_credits };
});

fastify.post('/spend', async (req) => {
  const body = z.object({ telegramUserId: z.string().min(1), credits: z.coerce.number().int().positive() }).parse(req.body);
  ensureUser(body.telegramUserId);
  const cur = db.prepare('SELECT balance_credits FROM credits WHERE telegram_user_id=?').get(body.telegramUserId);
  if (cur.balance_credits < body.credits) return { ok: false, error: 'insufficient_credits', balanceCredits: cur.balance_credits };
  db.prepare('UPDATE credits SET balance_credits = balance_credits - ? WHERE telegram_user_id=?')
    .run(body.credits, body.telegramUserId);
  const after = db.prepare('SELECT balance_credits FROM credits WHERE telegram_user_id=?').get(body.telegramUserId);
  return { ok: true, balanceCredits: after.balance_credits };
});

fastify.listen({ port: env.PORT, host: '127.0.0.1' });


path: assets/template/src/server.js
content: import 'dotenv/config';
import Fastify from 'fastify';
import rateLimit from '@fastify/rate-limit';
import Database from 'better-sqlite3';
import bs58 from 'bs58';
import { z } from 'zod';
import {
  Connection,
  Keypair,
  PublicKey,
  Transaction,
} from '@solana/web3.js';
import { PumpAgent } from '@pump-fun/agent-payments-sdk';

const envSchema = z.object({
  RPC_URL: z.string().url(),
  AGENT_TOKEN_MINT_ADDRESS: z.string().min(32),
  CURRENCY_MINT: z.string().min(32),
  LAMPORTS_PER_CREDIT: z.coerce.number().int().positive(),
  TREASURY_SECRET_KEY_BASE58: z.string().min(40),
  PORT: z.coerce.number().int().positive().default(3033),
  API_TOKEN: z.string().min(16),
  DB_PATH: z.string().default('./demo.db'),
});

const env = envSchema.parse(process.env);

const connection = new Connection(env.RPC_URL, 'confirmed');
const agentMint = new PublicKey(env.AGENT_TOKEN_MINT_ADDRESS);
const currencyMint = new PublicKey(env.CURRENCY_MINT);

const treasury = (() => {
  const [REDACTED_SECRET]);
  return Keypair.fromSecretKey(secret);
})();

const pumpAgent = new PumpAgent(agentMint, 'mainnet', connection);

const db = new Database(env.DB_PATH);

db.exec(`
CREATE TABLE IF NOT EXISTS users (
  telegram_user_id TEXT PRIMARY KEY,
  created_at INTEGER NOT NULL
);

CREATE TABLE IF NOT EXISTS deposit_wallets (
  telegram_user_id TEXT PRIMARY KEY,
  deposit_pubkey TEXT NOT NULL,
  deposit_secret_b58 TEXT NOT NULL,
  created_at INTEGER NOT NULL
);

CREATE TABLE IF NOT EXISTS credits (
  telegram_user_id TEXT PRIMARY KEY,
  balance_credits INTEGER NOT NULL
);

CREATE TABLE IF NOT EXISTS invoices (
  memo TEXT PRIMARY KEY,
  telegram_user_id TEXT NOT NULL,
  amount_lamports INTEGER NOT NULL,
  start_time INTEGER NOT NULL,
  end_time INTEGER NOT NULL,
  signature TEXT,
  status TEXT NOT NULL,
  created_at INTEGER NOT NULL
);
`);

function authHook(req, reply, done) {
  const [REDACTED_SECRET]'x-api-token'];
  if (token !== env.API_TOKEN) return reply.code(401).send({ error: 'unauthorized' });
  done();
}

function nowSec() {
  return Math.floor(Date.now() / 1000);
}

function ensureUser(telegramUserId) {
  db.prepare('INSERT OR IGNORE INTO users (telegram_user_id, created_at) VALUES (?, ?)')
    .run(telegramUserId, Date.now());
  db.prepare('INSERT OR IGNORE INTO credits (telegram_user_id, balance_credits) VALUES (?, 0)')
    .run(telegramUserId);
}

function getOrCreateDepositWallet(telegramUserId) {
  ensureUser(telegramUserId);
  const row = db.prepare('SELECT deposit_pubkey, deposit_secret_b58 FROM deposit_wallets WHERE telegram_user_id=?')
    .get(telegramUserId);
  if (row) return row;

  // demo: generate a new keypair per user and store secret in sqlite
  const kp = Keypair.generate();
  const secretB58 = bs58.encode(kp.secretKey);
  db.prepare('INSERT INTO deposit_wallets (telegram_user_id, deposit_pubkey, deposit_secret_b58, created_at) VALUES (?,?,?,?)')
    .run(telegramUserId, kp.publicKey.toBase58(), secretB58, Date.now());
  return { deposit_pubkey: kp.publicKey.toBase58(), deposit_secret_b58: secretB58 };
}

async function waitForDeposit(pubkeyStr, lamports, timeoutMs = 120_000) {
  const pubkey = new PublicKey(pubkeyStr);
  const start = Date.now();
  const startBal = await connection.getBalance(pubkey, 'confirmed');

  while (Date.now() - start < timeoutMs) {
    await new Promise(r => setTimeout(r, 2500));
    const bal = await connection.getBalance(pubkey, 'confirmed');
    if (bal - startBal >= lamports) {
      return { receivedLamports: bal - startBal, balance: bal };
    }
  }
  return null;
}

async function buildAndPayInvoice({ depositKeypair, amountLamports }) {
  const memo = String(Math.floor(Math.random() * 900000000000) + 100000);
  const startTime = nowSec();
  const endTime = startTime + 3600; // 1 hour validity

  const ixs = await pumpAgent.buildAcceptPaymentInstructions({
    user: depositKeypair.publicKey,
    currencyMint,
    amount: String(amountLamports),
    memo,
    startTime: String(startTime),
    endTime: String(endTime),
  });

  const { blockhash } = await connection.getLatestBlockhash('confirmed');
  const tx = new Transaction({ recentBlockhash: blockhash, feePayer: depositKeypair.publicKey });
  tx.add(...ixs);

  // Sign with the deposit wallet (server-controlled)
  tx.sign(depositKeypair);

  const sig = await connection.sendRawTransaction(tx.serialize(), {
    skipPreflight: false,
    preflightCommitment: 'confirmed',
  });
  await connection.confirmTransaction({ signature: sig, blockhash, lastValidBlockHeight: (await connection.getLatestBlockhash('confirmed')).lastValidBlockHeight }, 'confirmed');

  return { memo, startTime, endTime, signature: sig };
}

async function verifyInvoicePaid({ userPubkey, amountLamports, memo, startTime, endTime }) {
  return pumpAgent.validateInvoicePayment({
    user: userPubkey,
    currencyMint,
    amount: Number(amountLamports),
    memo: Number(memo),
    startTime: Number(startTime),
    endTime: Number(endTime),
  });
}

const fastify = Fastify({ logger: true });

await fastify.register(rateLimit, {
  max: 60,
  timeWindow: '1 minute',
});

fastify.addHook('onRequest', (req, reply, done) => {
  if (req.url.startsWith('/health')) return done();
  return authHook(req, reply, done);
});

fastify.get('/health', async () => ({ ok: true }));

// 1) create/get deposit wallet
fastify.post('/deposit-wallet', async (req) => {
  const body = z.object({ telegramUserId: z.string().min(1) }).parse(req.body);
  const w = getOrCreateDepositWallet(body.telegramUserId);
  return { depositAddress: w.deposit_pubkey };
});

// 2) wait for user deposit, then pay invoice from that deposit wallet, then credit
fastify.post('/fund-and-credit', async (req) => {
  const body = z.object({
    telegramUserId: z.string().min(1),
    depositLamports: z.coerce.number().int().positive(),
  }).parse(req.body);

  ensureUser(body.telegramUserId);
  const w = getOrCreateDepositWallet(body.telegramUserId);

  const deposit = await waitForDeposit(w.deposit_pubkey, body.depositLamports);
  if (!deposit) {
    return { status: 'timeout', depositAddress: w.deposit_pubkey };
  }

  const depositKeypair = Keypair.fromSecretKey(bs58.decode(w.deposit_secret_b58));

  const { memo, startTime, endTime, signature } = await buildAndPayInvoice({
    depositKeypair,
    amountLamports: body.depositLamports,
  });

  db.prepare('INSERT OR REPLACE INTO invoices (memo, telegram_user_id, amount_lamports, start_time, end_time, signature, status, created_at) VALUES (?,?,?,?,?,?,?,?)')
    .run(memo, body.telegramUserId, body.depositLamports, startTime, endTime, signature, 'sent', Date.now());

  const paid = await verifyInvoicePaid({
    userPubkey: depositKeypair.publicKey,
    amountLamports: body.depositLamports,
    memo,
    startTime,
    endTime,
  });

  if (!paid) {
    return { status: 'invoice_not_verified_yet', memo, signature, depositAddress: w.deposit_pubkey };
  }

  const creditsToAdd = Math.floor(body.depositLamports / env.LAMPORTS_PER_CREDIT);
  db.prepare('UPDATE credits SET balance_credits = balance_credits + ? WHERE telegram_user_id=?')
    .run(creditsToAdd, body.telegramUserId);
  db.prepare('UPDATE invoices SET status=? WHERE memo=?').run('verified', memo);

  const bal = db.prepare('SELECT balance_credits FROM credits WHERE telegram_user_id=?').get(body.telegramUserId);

  return {
    status: 'credited',
    creditsAdded: creditsToAdd,
    balanceCredits: bal.balance_credits,
    memo,
    signature,
    depositAddress: w.deposit_pubkey,
  };
});

fastify.post('/balance', async (req) => {
  const body = z.object({ telegramUserId: z.string().min(1) }).parse(req.body);
  ensureUser(body.telegramUserId);
  const bal = db.prepare('SELECT balance_credits FROM credits WHERE telegram_user_id=?').get(body.telegramUserId);
  return { balanceCredits: bal.balance_credits };
});

fastify.post('/spend', async (req) => {
  const body = z.object({ telegramUserId: z.string().min(1), credits: z.coerce.number().int().positive() }).parse(req.body);
  ensureUser(body.telegramUserId);
  const cur = db.prepare('SELECT balance_credits FROM credits WHERE telegram_user_id=?').get(body.telegramUserId);
  if (cur.balance_credits < body.credits) return { ok: false, error: 'insufficient_credits', balanceCredits: cur.balance_credits };
  db.prepare('UPDATE credits SET balance_credits = balance_credits - ? WHERE telegram_user_id=?')
    .run(body.credits, body.telegramUserId);
  const after = db.prepare('SELECT balance_credits FROM credits WHERE telegram_user_id=?').get(body.telegramUserId);
  return { ok: true, balanceCredits: after.balance_credits };
});

fastify.listen({ port: env.PORT, host: '127.0.0.1' });


path: assets/template/src/standalone-telegram.cjs
content: require('dotenv/config');

const { Bot } = require('grammy');
const { z } = require('zod');

const envSchema = z.object({
  TELEGRAM_BOT_TOKEN: z.string().min(40),
  BILLING_URL: z.string().url().default('http://127.0.0.1:3033'),
  BILLING_TOKEN: z.string().min(16),
  LAMPORTS_PER_CREDIT: z.coerce.number().int().positive().default(100000),
});

const env = envSchema.parse(process.env);

async function billing(path, body) {
  const res = await fetch(`${env.BILLING_URL}${path}`, {
    method: 'POST',
    headers: {
      'content-type': 'application/json',
      'x-api-token': env.BILLING_TOKEN,
    },
    body: JSON.stringify(body),
  });
  if (!res.ok) {
    const text = await res.text().catch(() => '');
    throw new Error(`billing ${path} failed: ${res.status} ${text}`);
  }
  return res.json();
}

function formatLamports(lamports) {
  return `${lamports} lamports (~${(lamports / 1e9).toFixed(9)} SOL)`;
}

function pricingLine() {
  return `Pricing: 100 credits = 0.01 SOL (1 credit = ${env.LAMPORTS_PER_CREDIT} lamports).`;
}

const bot = new Bot(env.TELEGRAM_BOT_TOKEN);

bot.command(['start', 'help'], async (ctx) => {
  await ctx.reply(
    `This agent is pay-to-use.\n\n` +
    `Commands:\n` +
    `/deposit - get your personal funding address\n` +
    `/confirm <lamports> - after you send SOL, confirm amount to credit\n` +
    `/balance - show credits\n\n` +
    pricingLine()
  );
});

bot.command('deposit', async (ctx) => {
  const uid = String(ctx.from.id);
  const out = await billing('/deposit-wallet', { telegramUserId: uid });
  await ctx.reply(
    `Send SOL to your personal funding address:\n` +
    `${out.depositAddress}\n\n` +
    `Then run: /confirm <lamports>\n` +
    `Example for 0.01 SOL: /confirm 10000000\n\n` +
    pricingLine()
  );
});

bot.command('balance', async (ctx) => {
  const uid = String(ctx.from.id);
  const out = await billing('/balance', { telegramUserId: uid });
  await ctx.reply(`Balance: ${out.balanceCredits} credits`);
});

bot.command('confirm', async (ctx) => {
  const uid = String(ctx.from.id);
  const parts = (ctx.message.text || '').trim().split(/\s+/);
  const lamports = Number(parts[1]);
  if (!Number.isFinite(lamports) || lamports <= 0) {
    await ctx.reply(`Usage: /confirm <lamports>  (example: /confirm 10000000)`);
    return;
  }

  await ctx.reply(`Waiting for deposit of at least ${formatLamports(lamports)}... (up to ~2 minutes)`);
  const out = await billing('/fund-and-credit', { telegramUserId: uid, depositLamports: lamports });

  if (out.status === 'timeout') {
    await ctx.reply(`No deposit detected yet. Address:\n${out.depositAddress}\nTry /confirm ${lamports} again after you send.`);
    return;
  }

  if (out.status === 'invoice_not_verified_yet') {
    await ctx.reply(
      `Deposit detected. I paid the Pump invoice tx.\n` +
      `Signature: ${out.signature}\n` +
      `Memo: ${out.memo}\n\n` +
      `Not verified yet—run /confirm ${lamports} again in ~10s.`
    );
    return;
  }

  if (out.status === 'credited') {
    await ctx.reply(
      `Credited.\n` +
      `Added: ${out.creditsAdded} credits\n` +
      `Balance: ${out.balanceCredits} credits\n` +
      `Pump invoice signature: ${out.signature}`
    );
    return;
  }

  await ctx.reply(`Unexpected response: ${JSON.stringify(out)}`);
});

bot.on('message:text', async (ctx) => {
  const text = (ctx.message.text || '').trim();
  if (text.startsWith('/')) return; // commands handled above

  const uid = String(ctx.from.id);
  const bal = await billing('/balance', { telegramUserId: uid }).catch(() => ({ balanceCredits: 0 }));
  if (!bal.balanceCredits || bal.balanceCredits <= 0) {
    await ctx.reply(
      `You need credits to use this agent.\n\n` +
      `1) /deposit\n` +
      `2) Send SOL\n` +
      `3) /confirm <lamports>\n\n` +
      pricingLine()
    );
    return;
  }

  // Demo spend 1 credit per message
  await billing('/spend', { telegramUserId: uid, credits: 1 });
  const after = await billing('/balance', { telegramUserId: uid }).catch(() => ({ balanceCredits: '?' }));
  await ctx.reply(`(demo) Spent 1 credit. Balance now: ${after.balanceCredits}. Next: wire this to real tasks.`);
});

(async () => {
  await bot.api.setMyCommands([
    { command: 'deposit', description: 'Get your funding address' },
    { command: 'confirm', description: 'Confirm deposit + credit' },
    { command: 'balance', description: 'Show credits' },
    { command: 'help', description: 'Help' },
  ]);

  await bot.start({ drop_pending_updates: true });
})();


path: assets/template/src/telegram-bot.cjs
content: require('dotenv/config');

const { z } = require('zod');

const envSchema = z.object({
  BILLING_URL: z.string().url().default('http://127.0.0.1:3033'),
  BILLING_TOKEN: z.string().min(16),
  LAMPORTS_PER_CREDIT: z.coerce.number().int().positive().default(100000),
});

const env = envSchema.parse(process.env);

async function billing(path, body) {
  const res = await fetch(`${env.BILLING_URL}${path}`, {
    method: 'POST',
    headers: {
      'content-type': 'application/json',
      'x-api-token': env.BILLING_TOKEN,
    },
    body: JSON.stringify(body),
  });
  if (!res.ok) {
    const text = await res.text().catch(() => '');
    throw new Error(`billing ${path} failed: ${res.status} ${text}`);
  }
  return res.json();
}

function formatLamports(lamports) {
  return `${lamports} lamports (~${(lamports / 1e9).toFixed(9)} SOL)`;
}

module.exports = {
  id: 'telegram-demo-billing',

  // OpenClaw plugin entrypoint style: expose onMessage hook.
  // If your OpenClaw telegram plugin expects a different shape, tell me and I’ll adapt.
  async onMessage(ctx) {
    // ctx is expected to include:
    // - ctx.text
    // - ctx.sender?.id (telegram user id)
    // - ctx.reply(text)

    const text = (ctx.text || '').trim();
    const senderId = String(ctx.sender?.id || ctx.senderId || '');
    if (!senderId) return;

    // Default intercept: require funding
    if (!text.startsWith('/')) {
      const bal = await billing('/balance', { telegramUserId: senderId }).catch(() => ({ balanceCredits: 0 }));
      if (!bal.balanceCredits || bal.balanceCredits <= 0) {
        await ctx.reply(
          `This agent is pay-to-use.\n\n` +
          `To add credits:\n` +
          `1) /deposit (get your personal funding address)\n` +
          `2) Send SOL to that address\n` +
          `3) /confirm <lamports> (I’ll convert it into credits)\n\n` +
          `Pricing: 100 credits = 0.01 SOL (1 credit = 100,000 lamports).\n` +
          `Check balance: /balance`
        );
        return;
      }

      // Demo: spend 1 credit per message (you can change this)
      await billing('/spend', { telegramUserId: senderId, credits: 1 });
      await ctx.reply(`(demo) Spent 1 credit. Your message was received. Now wire this to real tasks.`);
      return;
    }

    const [cmdRaw, ...args] = text.split(/\s+/);
    const cmd = cmdRaw.toLowerCase();

    if (cmd === '/start' || cmd === '/help') {
      await ctx.reply(
        `Commands:\n` +
        `/deposit - get your personal funding address\n` +
        `/confirm <lamports> - after you send SOL, confirm amount to credit\n` +
        `/balance - show credits\n\n` +
        `Pricing: 100 credits = 0.01 SOL (1 credit = 100,000 lamports).`
      );
      return;
    }

    if (cmd === '/deposit') {
      const out = await billing('/deposit-wallet', { telegramUserId: senderId });
      await ctx.reply(
        `Send SOL to your personal funding address:\n` +
        `${out.depositAddress}\n\n` +
        `Then run: /confirm <lamports>\n` +
        `Example for 0.01 SOL: /confirm 10000000`
      );
      return;
    }

    if (cmd === '/confirm') {
      const lamports = Number(args[0]);
      if (!Number.isFinite(lamports) || lamports <= 0) {
        await ctx.reply(`Usage: /confirm <lamports>  (example: /confirm 10000000)`);
        return;
      }
      await ctx.reply(`Waiting for deposit of at least ${formatLamports(lamports)}... (up to ~2 minutes)`);
      const out = await billing('/fund-and-credit', { telegramUserId: senderId, depositLamports: lamports });

      if (out.status === 'timeout') {
        await ctx.reply(`No deposit detected yet. Address:\n${out.depositAddress}\nTry /confirm ${lamports} again after you send.`);
        return;
      }

      if (out.status === 'invoice_not_verified_yet') {
        await ctx.reply(
          `Deposit detected. I paid the Pump invoice tx.\n` +
          `Signature: ${out.signature}\n` +
          `Memo: ${out.memo}\n\n` +
          `Not verified yet—try again in ~10s with: /confirm ${lamports}`
        );
        return;
      }

      if (out.status === 'credited') {
        await ctx.reply(
          `Credited.\n` +
          `Added: ${out.creditsAdded} credits\n` +
          `Balance: ${out.balanceCredits} credits\n` +
          `Pump invoice signature: ${out.signature}`
        );
        return;
      }

      await ctx.reply(`Unexpected response: ${JSON.stringify(out)}`);
      return;
    }

    if (cmd === '/balance') {
      const out = await billing('/balance', { telegramUserId: senderId });
      await ctx.reply(`Balance: ${out.balanceCredits} credits`);
      return;
    }

    await ctx.reply(`Unknown command. Use /help`);
  },
};


path: references/PUMP_TOKENIZED_AGENTS.md
content: # Pump Tokenized Agents (agent-payments-sdk) — Integration Notes

This skill templates a Telegram (polling) + web server project and highlights how to integrate Pump Tokenized Agent payments using `@pump-fun/agent-payments-sdk`.

Core ideas:

- Build accept-payment instructions via `buildAcceptPaymentInstructions`.
- User signs client-side; server verifies payment server-side via `validateInvoicePayment`.
- Never handle or log private keys.

Primary reference skill:
- https://raw.githubusercontent.com/pump-fun/pump-fun-skills/refs/heads/main/tokenized-agents/SKILL.md

Env vars commonly required:
- `SOLANA_RPC_URL`
- `AGENT_TOKEN_MINT_ADDRESS`
- `CURRENCY_MINT`

CURRENCY_MINT defaults:
- USDC: [REDACTED_SECRET]
- wSOL: [REDACTED_SECRET]


path: scripts/stamp_template.sh
content: #!/usr/bin/env bash
set -euo pipefail

# Stamp the template into a new project folder.
# Usage:
#   ./scripts/stamp_template.sh <project-slug> [dest-dir]
# Example:
#   ./scripts/stamp_template.sh acme-bot /tmp

SLUG=${1:-}
DEST_DIR=${2:-.}

if [[ -z "$SLUG" ]]; then
  echo "Usage: $0 <project-slug> [dest-dir]" >&2
  exit 1
fi

SKILL_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
TEMPLATE_DIR="$SKILL_DIR/assets/template"
OUT_DIR="$DEST_DIR/$SLUG"

if [[ ! -d "$TEMPLATE_DIR" ]]; then
  echo "Template not found: $TEMPLATE_DIR" >&2
  exit 1
fi

if [[ -e "$OUT_DIR" ]]; then
  echo "Destination already exists: $OUT_DIR" >&2
  exit 1
fi

mkdir -p "$OUT_DIR"

# tar copy keeps permissions and avoids needing rsync
( cd "$TEMPLATE_DIR" && tar -cf - . ) | ( cd "$OUT_DIR" && tar -xf - )

# Remove common local state if it slipped in
rm -f "$OUT_DIR"/*.log "$OUT_DIR"/*.pid "$OUT_DIR"/demo.db "$OUT_DIR"/.env "$OUT_DIR"/.env.local 2>/dev/null || true

echo "Stamped template to: $OUT_DIR"
echo "Next: cd '$OUT_DIR' && npm install"


Security scan verdicts — ClawScan: suspicious | static analysis: suspicious | VirusTotal: clean | SkillSpector: suspicious (CRITICAL)