$line) { $trimmed = trim($line); if ($trimmed === '' || str_starts_with($trimmed, '#')) { continue; } if (!str_contains($line, '=')) { throw new RuntimeException( 'Invalid faucet configuration at line ' . ($lineNumber + 1) ); } [$name, $value] = explode('=', $line, 2); $name = trim($name); $value = trim($value); if (preg_match('/^[A-Z][A-Z0-9_]*$/', $name) !== 1) { throw new RuntimeException( 'Invalid faucet variable name at line ' . ($lineNumber + 1) ); } if (strlen($value) >= 2) { $first = $value[0]; $last = $value[strlen($value) - 1]; if (($first === '"' && $last === '"') || ($first === "'" && $last === "'")) { $value = substr($value, 1, -1); } } // Real process variables override values from faucet.env. if (getenv($name) !== false) { continue; } putenv("$name=$value"); $_ENV[$name] = $value; } } // Every configured filesystem path should be absolute in production. return [ 'faucet_address' => getenv('FAUCET_ADDRESS') ?: '', 'wallet_path' => getenv('CONTRACTLESS_WALLET_PATH') ?: '', 'wallet_key' => getenv('CONTRACTLESS_WALLET_KEY') ?: '', 'rpc_host' => getenv('CONTRACTLESS_RPC_HOST') ?: '127.0.0.1', 'rpc_port' => (int) (getenv('CONTRACTLESS_RPC_PORT') ?: 50050), 'rpc_timeout_seconds' => (float) (getenv('CONTRACTLESS_RPC_TIMEOUT') ?: 10), 'composer_autoload' => getenv('FAUCET_COMPOSER_AUTOLOAD') ?: '', 'claims_file' => getenv('FAUCET_CLAIMS_FILE') ?: __DIR__ . '/storage/claims.json', 'lock_file' => getenv('FAUCET_LOCK_FILE') ?: __DIR__ . '/storage/claims.lock', 'claim_amount_atomic' => 2_500_000_000, 'transfer_fee_atomic' => 25_000_000, 'cooldown_seconds' => 86_400, 'minimum_request_interval_ms' => 250, ];