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
76 changes: 76 additions & 0 deletions pages/faucet.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
<!-- template.html -->
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Faucet</title>
<!-- Tailwind CDN -->
<script src="https://cdn.tailwindcss.com"></script>
</head>

<body class="bg-gray-100 flex items-center justify-center min-h-screen">
<div class="bg-white shadow-lg rounded-2xl p-8 max-w-md w-full">
<h1 class="text-3xl font-bold mb-2 text-center text-blue-600">Faucet</h1>
<p class="text-gray-600 text-center mb-1">Network: <span class="font-semibold">{{ .Network }}</span></p>

<form id="faucet-form" class="space-y-4">
<div>
<label for="address" class="block text-gray-700 font-medium">Wallet Address:</label>
<input type="text" id="address" name="address" required
class="mt-1 w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500">
</div>
<div>
<label for="amount" class="block text-gray-700 font-medium">Amount:</label>
<input type="number" id="amount" name="amount" min="1" required
class="mt-1 w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500">
</div>
<button type="submit"
class="w-full bg-blue-600 hover:bg-blue-700 text-white font-semibold py-2 px-4 rounded-lg transition">
Claim {{.Asset}}
</button>
</form>
<div id="message" class="mt-4 text-center text-sm"></div>
</div>

<script>
document.getElementById("faucet-form").addEventListener("submit", async function (e) {
e.preventDefault();

const address = document.getElementById("address").value;
const amount = document.getElementById("amount").value;
const messageDiv = document.getElementById("message");
try {
const res = await fetch("/faucet", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({address, amount})
});

const data = await res.json();

if (res.ok) {
let txId = data.txId;

messageDiv.textContent = txId
? `{{.Asset}} sent successfully! TxID: ${txId}`
: "{{.Asset}} sent successfully!";
messageDiv.className = "mt-4 text-green-600 text-center break-words";
} else {
messageDiv.textContent = data.error || "❌ Something went wrong.";
messageDiv.className = "mt-4 text-red-600 text-center";
}
} catch (error) {
messageDiv.textContent = "⚠️ Network error. Please try again.";
messageDiv.className = "mt-4 text-red-600 text-center";
}


});
</script>
</body>

</html>
32 changes: 32 additions & 0 deletions router/faucet_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package router

import (
"encoding/json"
"html/template"
"io"
"net/http"
)
Expand Down Expand Up @@ -123,3 +124,34 @@ func parseRequestBody(body io.ReadCloser) map[string]interface{} {

return decodedBody
}

// HandleFaucetPage will return an HTML page that will allow us to interact with the faucet endpoints
func (r *Router) HandleFaucetPage(res http.ResponseWriter, _ *http.Request) {
filepath := "pages/faucet.html"
Copy link

Copilot AI Aug 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The hardcoded file path "pages/faucet.html" makes the code less maintainable and could fail if the file structure changes. Consider making this configurable or using a constant to define template paths.

Suggested change
filepath := "pages/faucet.html"
filepath := faucetPageTemplatePath

Copilot uses AI. Check for mistakes.

tmpl, err := template.ParseFiles(filepath)
if err != nil {
http.Error(res, "Page not found", http.StatusNotFound)
return
}

type PageData struct {
Network string
Asset string
}
Comment on lines +138 to +141
Copy link

Copilot AI Aug 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] The PageData struct is defined inside the function scope. Consider moving it to package level or using an existing struct type to improve code organization and reusability.

Suggested change
type PageData struct {
Network string
Asset string
}

Copilot uses AI. Check for mistakes.
network := r.Config.Chain()
asset := "BTC"
if network == "liquid" {
asset = "L-BTC"
}

data := PageData{
Network: network,
Asset: asset,
}

err = tmpl.Execute(res, data)
if err != nil {
http.Error(res, "Failed to render page", http.StatusInternalServerError)
}
}
1 change: 1 addition & 0 deletions router/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ func NewRouter(config cfg.Config) *Router {
faucet := faucet.NewFaucet(config.RPCServerURL(), rpcClient)
r.Faucet = faucet
r.HandleFunc("/faucet", r.HandleFaucetRequest).Methods(http.MethodPost, http.MethodOptions)
r.HandleFunc("/faucet", r.HandleFaucetPage).Methods(http.MethodGet, http.MethodOptions)
Copy link

Copilot AI Aug 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using the same path /faucet for both GET and POST methods could be confusing. Consider using a more specific path like /faucet/ui for the UI page as mentioned in the PR description, which would make the API more self-documenting and avoid potential routing conflicts.

Suggested change
r.HandleFunc("/faucet", r.HandleFaucetPage).Methods(http.MethodGet, http.MethodOptions)
r.HandleFunc("/faucet/ui", r.HandleFaucetPage).Methods(http.MethodGet, http.MethodOptions)

Copilot uses AI. Check for mistakes.
if config.Chain() == "liquid" {
registry, _ := helpers.NewRegistry(config.RegistryPath())
r.Registry = registry
Expand Down