Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/vendor/
composer.lock
.DS_Store
*.log
.idea/
.vscode/
70 changes: 69 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,70 @@
# whmcs-chainstack
WHMCS provisioning module for Chainstack — provision and manage RPC/WSS node endpoints from WHMCS.

A WHMCS provisioning module for [Chainstack](https://chainstack.com). It provisions and manages
Chainstack RPC/WSS node endpoints directly from WHMCS: ordering a service creates a node, the
endpoints show up in the client area, and suspend/terminate tear the resources down.

**One WHMCS service = one Chainstack node**, deployed into a per-service project inside a single
operator-owned Chainstack organization, authenticated with one admin API key.

## Requirements

- WHMCS 8.x, PHP 8.1+ (tested on 8.3). PHP extensions: `curl`, `json`, `openssl`.
- A Chainstack organization on a plan that permits the Platform API and node creation.
- A Chainstack admin **API key** (Console → Settings → API keys).

## Install

Copy the module into your WHMCS installation:

```bash
cp -r modules/servers/chainstack <whmcs>/modules/servers/
```

Then in WHMCS admin:

1. **Setup → Products/Services → Servers → Add New Server**
- Hostname `api.chainstack.com`, Type **Chainstack**, **Password** = your API key. Test Connection.
2. **Create a product**, Module = **Chainstack**, and either:
- set **Default network** to a network slug (one product per network), or
- attach a **Network** Configurable Option dropdown (one product, customer picks the network).

Full configuration, lifecycle behavior, and the network-dropdown helper are documented in
[`modules/servers/chainstack/README.md`](modules/servers/chainstack/README.md).

## Networks

The deployable network is resolved **live** against `GET /v2/deployment-options/` at provision
time, and the cloud is derived automatically — so every network Chainstack offers is supported
without code changes. List the available slugs:

```bash
CHAINSTACK_API_KEY=xxx php modules/servers/chainstack/scripts/list_networks.php
```

## Lifecycle

| Action | Effect |
|---|---|
| Create | Creates a project + node; endpoints appear in the client area (global nodes deploy synchronously). |
| Suspend | Deletes the node + project (stops usage/cost). |
| Unsuspend | Re-provisions — note the endpoint **URL changes** (new auth key). |
| Terminate | Deletes the node + project. |

## Tests

```bash
composer install
vendor/bin/phpunit
```

A manual end-to-end harness (creates and deletes one real node + project) is at
[`tests/e2e_harness.php`](tests/e2e_harness.php).

## Repository layout

```
modules/servers/chainstack/ the module (install this into WHMCS)
scripts/ operator helpers (list networks, sync dropdown)
tests/ PHPUnit suite + manual e2e harness
```
11 changes: 11 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"name": "chainstack/whmcs-provisioning",
"description": "Chainstack WHMCS provisioning module (tests)",
"license": "proprietary",
"require": {
"php": ">=8.1"
},
"require-dev": {
"phpunit/phpunit": "^10.5 || ^11.0"
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}
127 changes: 127 additions & 0 deletions modules/servers/chainstack/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
# Chainstack WHMCS Provisioning Module

Provisions Chainstack RPC/WSS endpoints (nodes) for WHMCS customers. **One WHMCS service = one
Chainstack node**, deployed into a per-service project inside a single operator-owned Chainstack
organization. Authenticates with one admin API key.

## Requirements

- WHMCS 8.x (tested with PHP 8.3). PHP extensions: `curl`, `json`, `openssl`.
- A Chainstack organization on a plan that permits the Platform API and node creation.
- An admin **API key** (Chainstack console → Settings → API keys).

## Install

1. Copy this directory to `<whmcs>/modules/servers/chainstack/`.
2. Ensure files are owned by the web user and readable (dirs 755, files 644).

## Configure

### 1. Add the server
Setup → Products/Services → **Servers** → Add New Server:
- **Name:** Chainstack
- **Hostname:** `api.chainstack.com`
- **Type:** Chainstack
- **Password:** *your Chainstack admin API key* (stored encrypted by WHMCS)
- Save → **Test Connection** (calls `GET /v1/organization/`).

### 2. Create one product per network
Each product maps to a fixed network. For each chain you want to sell:
- Create a product (e.g. "Ethereum Mainnet Node").
- Module Settings → Module Name = **Chainstack**.
- **Default network** = the network slug (e.g. `ethereum-mainnet`).
Run `scripts/list_networks.php` for the full list of valid slugs:
```
CHAINSTACK_API_KEY=xxx php scripts/list_networks.php
```

### 3. (Alternative) One product, customer picks the network from a dropdown
The same module also supports a single "Chainstack Node" product where the customer selects the
network at order time. Resolution precedence: **Configurable Option `Network` › product `Default
network`**, so both styles coexist.

Run the sync helper to create/refresh the `Network` Configurable Option group (dropdown of all
network slugs, priced free) directly from the live API. **Run it as your WHMCS web/PHP user**
(not root) so WHMCS bootstrap doesn't create root-owned cache files:

```bash
# from the WHMCS root, using the PHP binary your WHMCS runs on:
php modules/servers/chainstack/scripts/setup_network_option.php
```
- API key is auto-detected from the configured Chainstack server (or pass `CHAINSTACK_API_KEY`).
- Pass `PRODUCT_ID=<id>` to auto-link the group to a product, or attach it manually via
Products/Services → edit → Configurable Options.
- Idempotent: re-run anytime to pick up new networks (existing values and any prices you set are
left untouched). Networks removed upstream are reported, not deleted.

The Configurable Option **must be named `Network`** (the module reads `configoptions['Network']`).
Each value is written as `slug|Friendly Name` (e.g. `ethereum-sepolia-testnet|Ethereum Sepolia
Testnet`) — WHMCS shows the friendly name to customers and passes the **slug** to the module. The
helper generates the friendly names automatically (with nicer casing for BNB Smart Chain, PoS,
zkEVM, opBNB, etc.).

## Lifecycle behavior

| WHMCS action | Effect |
|---|---|
| **Create** | Creates a project + one node; stores their IDs on the service. Endpoints appear in the client area (global nodes deploy synchronously). |
| **Suspend** | **Deletes the node + project** (stops all usage/cost). |
| **Unsuspend** | **Re-provisions** a fresh project + node. ⚠️ The endpoint **URL changes** (new auth key) — the previous URL does not return. |
| **Terminate** | Deletes the node + project. |
| **Client buttons** | `Refresh Status`. |
| **Admin buttons** | `Create Endpoint` (recovery), `Refresh Status`. |

**Important:** because suspend tears down and unsuspend recreates, a suspend/unsuspend cycle gives
the customer a **new endpoint URL**. Communicate this to customers if you rely on automatic
suspension (e.g. overdue invoices).

## Errors

API errors are surfaced with friendly text where mapped — e.g. hitting the org's node limit shows
*"Your Chainstack account has reached its node limit. Please contact your administrator…"*. All
calls are logged via WHMCS Module Log (Utilities → Logs → Module Log); the API key is redacted.

## Blockchain icons

Per-protocol icons come from Chainstack's CDN (`https://static.chainstack.dev/<protocol>.svg`,
the same source the console uses). They appear:
- next to each endpoint inside the service's client-area panel, and
- as the product-details **header icon** (swapped in via a `ClientAreaFooterOutput` hook — no theme
files are modified). Unknown protocols fall back to a small inline generic SVG.

The header swap reads the protocol stored at provision time, so it shows only for services
provisioned by the current module version.

## Reliability & pricing

- **Re-run safe.** Module commands are idempotent: WHMCS re-running a failed `Create` will not
create duplicate projects/nodes, and a node-create failure rolls back a project created in the
same call. (No custom HTTP retry — WHMCS's command re-run is the retry mechanism.)
- **Synchronous deploys.** Scope is global/elastic nodes, which return `status=running` with
endpoints immediately; the client area fetches status live. There is no background sync cron.
- **Pricing.** The sync helper creates network options priced **free (0.00)**. The operator
(WHMCS account owner) sets whatever prices they want per product / configurable option.

## Files

```
chainstack.php WHMCS module functions (incl. AdminServicesTabFields)
hooks.php ClientAreaFooterOutput: product-details blockchain icon swap
lib/ChainstackClient.php HTTP client (Bearer auth, typed errors)
lib/Provisioner.php lifecycle orchestration + live network resolution
lib/Helpers.php server config, per-service state, naming, friendly errors
templates/clientarea.tpl endpoint display
scripts/list_networks.php list deployable network slugs (run with CHAINSTACK_API_KEY)
scripts/setup_network_option.php create/sync the "Network" Configurable Option dropdown
```

State is stored on the service via `serviceProperties`: `chainstack_project_id`,
`chainstack_node_ids`, `chainstack_status`, `chainstack_protocol`.

## Tests

PHPUnit suite under `tests/` (run from the package root):
```
composer install
vendor/bin/phpunit
```
Loading