6.6 KiB
Contractless Faucet
This faucet uses PHP and JSON storage. It connects directly to a Contractless node through the authenticated RPC protocol, creates and signs transfers locally, and submits them without invoking Contractless CLI programs.
Requirements
- 64-bit PHP 8.1 or newer
- Composer
- The Contractless PHP Skein and Falcon modules
contractless/contractless-php-rpc- Access to a compatible Contractless RPC node
- A dedicated, registered faucet wallet
- Read access to that wallet file
- A writable private directory for the JSON claim ledger
Install the native modules first:
https://contractless.dev/contractless/Contractless-PHP-Modules
Install the RPC package in the Composer project containing the faucet:
composer require contractless/contractless-php-rpc:^0.2.0 -W
The web-server account needs permission to read Composer's vendor directory
and faucet wallet, and write the configured claim-ledger directory. It does
not need access to a node runtime, balance sheet, or Contractless CLI binary.
The faucet configuration, wallet file, wallet decryption key, and claim ledger must never be downloadable through the web server.
Configuration
For an installation at:
/var/www/project/public/faucet
copy the included template to the private project root:
cp /var/www/project/public/faucet/.env.example /var/www/project/faucet.env
sudo chown root:www-data /var/www/project/faucet.env
sudo chmod 640 /var/www/project/faucet.env
Then edit /var/www/project/faucet.env and replace every example value with
the correct faucet settings.
The faucet automatically loads faucet.env from the project root two
directories above the faucet:
/var/www/project/faucet.env
No Apache configuration, PHP-FPM pool changes, shell exports, or service restarts are required. Reloading the faucet page uses the saved values.
The optional FAUCET_ENV_FILE process variable can point to a different file,
but normal installations do not need it.
FAUCET_ADDRESS determines the active network:
- An address ending in
.cltcconfigures testnet and displaysCLTC. - An address ending in
.clcconfigures mainnet and displaysCLC.
The faucet address itself must be the registered canonical 40-character short address. Faucet recipients may enter either a canonical short address or a registered vanity address. Vanity inputs are resolved through RPC, and the canonical owner address is used for the transfer and 24-hour claim ledger.
Point the faucet at its dedicated wallet and provide that wallet's decryption key:
CONTRACTLESS_WALLET_PATH=/var/www/project/faucet.wallet
CONTRACTLESS_WALLET_KEY=wallet-decryption-key
The RPC library reads the public key from the wallet, extracts the encrypted private key from its image, verifies the image payload HMAC, decrypts the private key, proves that the Falcon keypair matches, and verifies that the wallet's short address is derived from that public key.
FAUCET_ADDRESS must match the canonical short_address saved in this wallet.
Keep the wallet file and decryption key outside the public document root, but
inside a path PHP is permitted to read. For the example layout, the public
document root is /var/www/project/public, so /var/www/project/faucet.wallet
is private from HTTP while remaining available to PHP. Never expose the wallet
or key through HTML, JavaScript, logs, error responses, or source control.
Before enabling the faucet, verify the wallet through the installed RPC package:
cd /path/to/Contractless-PHP-RPC
php examples/load_wallet.php /private/path/to/faucet.wallet 'wallet decryption key'
Configure the node used for RPC:
CONTRACTLESS_RPC_HOST=127.0.0.1
CONTRACTLESS_RPC_PORT=50050
CONTRACTLESS_RPC_TIMEOUT=10
Use port 50050 for the default testnet RPC or 50055 for the default mainnet
RPC unless the selected node uses a different configured port.
The faucet searches for Composer's autoloader in its own directory, its parent
directory, and the web-project root two directories above it. Set
FAUCET_COMPOSER_AUTOLOAD to the absolute vendor/autoload.php path only when
Composer is installed elsewhere.
For production, set FAUCET_CLAIMS_FILE and FAUCET_LOCK_FILE to paths
outside the public web root. The included storage directory is suitable for
local setup and includes an Apache access-denial rule, but server-level private
storage is preferable.
Claim Rules
Each successful request sends 25 base testnet or mainnet coins and pays a 0.25-coin transfer fee from the faucet wallet.
Before reserving or broadcasting a claim, the faucet:
- Retrieves its confirmed base-coin balance through RPC
- Refuses the request when the faucet cannot cover the claim and fee
- Confirms that the receiving canonical wallet address is registered
- Creates and signs the transfer locally
- Submits the exact signed transaction through RPC
The faucet records a successful claim only after the node returns
successful_broadcast: true.
A claim is rejected when either the canonical wallet address or normalized
client IP has claimed during the preceding 24 hours. IPv4-mapped IPv6 addresses
are treated as IPv4. Native IPv6 clients are grouped by /64.
Claims are reserved under an exclusive file lock before broadcasting. This prevents simultaneous requests from passing the same address or IP check. Failed broadcasts release their reservation so the user may try again.
The faucet trusts REMOTE_ADDR and intentionally ignores forwarded-IP headers.
When deploying behind a reverse proxy, configure the proxy or web server to
replace REMOTE_ADDR only from explicitly trusted proxy addresses.
JSON Ledger
The claim ledger is keyed directly by canonical wallet address and normalized IP:
{
"version": 1,
"last_request_timestamp_ms": 0,
"total_claimed_atomic": 2500000000,
"total_claims": 1,
"addresses": {
"abcd000000000000000000000000000000001234.cltc": {
"claimed_timestamp": 1785000000,
"status": "completed",
"address": "abcd000000000000000000000000000000001234.cltc",
"ip": "203.0.113.10",
"txid": "transaction hash"
}
},
"ips": {
"203.0.113.10": {
"claimed_timestamp": 1785000000,
"status": "completed",
"address": "abcd000000000000000000000000000000001234.cltc",
"ip": "203.0.113.10",
"txid": "transaction hash"
}
}
}
Security
Run the faucet under a dedicated operating-system account with access only to
its private configuration and claim ledger. Do not run PHP or the faucet as
root. Serve the site over HTTPS, keep directory listing disabled, and keep
faucet.env outside the public web root.