Skip to content
Merged
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
85 changes: 85 additions & 0 deletions docs/components.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
Forest Explorer Components Diagram

```mermaid
flowchart TD
%% Forest Explorer Components
subgraph Main
direction TB
App[App]
Ctrl[Faucet Controller]
Model[Faucet Model]
Server[SSR Logic]
RateLimiter[Rate Limiter]
Constants[Network Constants]
end

%% UI
subgraph UI
direction TB
Views[Views]
Home[Home]
Faucets[Faucets]
Components[UI Components]
end

%% Sub-sections of UI
subgraph Faucets
direction TB
Mainnet[Mainnet]
Calibnet[Calibnet]
end
subgraph Components
direction TB
Layout[Layout]
Balance[Balance]
Transaction[Transaction]
Icon[Icon]
Alert[Alert]
Nav[Navigation]
end

%% Utilities
subgraph Utils
direction TB
Addr[Address]
Key
Fmt[Format]
Err[Errors]
Msg[Message]
RpcCtx[RPC Context]
LotusJson[Lotus JSON]
end

%% Main relations
App --> Ctrl
App --> Server
Ctrl --> Model
Ctrl --> RateLimiter
Ctrl --> Constants
Ctrl --> Utils
Ctrl --> Views
Server --> Utils

%% UI relations
Views --> Faucets
Views --> Components

%% UI sub-relations
Faucets --> Mainnet
Faucets --> Calibnet
Components --> Layout
Components --> Balance
Components --> Transaction
Components --> Icon
Components --> Alert
Components --> Nav

%% Utilities relations
Utils --> LotusJson
Utils --> Addr
Utils --> Key
Utils --> Fmt
Utils --> Err
Utils --> Msg
Utils --> RpcCtx
```
7 changes: 4 additions & 3 deletions e2e/script.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,20 +103,21 @@ async function checkFooter(page, path) {
const PAGES = [
{
path: "",
buttons: ["To faucet list"],
buttons: ["Faucet List"],
links: ["Filecoin Slack", "documentation"],
},
{
path: "/faucet",
buttons: ["Home"],
links: ["Calibration Network Faucet", "Mainnet Network Faucet"],
},
{
path: "/faucet/calibnet",
buttons: ["Back to faucet list", "Transaction History", "Send"],
buttons: ["Faucet List", "Transaction History", "Send"],
},
{
path: "/faucet/mainnet",
buttons: ["Back to faucet list", "Transaction History", "Send"],
buttons: ["Faucet List", "Transaction History", "Send"],
},
];

Expand Down
193 changes: 9 additions & 184 deletions src/app.rs
Original file line number Diff line number Diff line change
@@ -1,187 +1,12 @@
use crate::icons::{CheckIcon, LightningIcon};
use crate::rpc_context::{Provider, RpcContext};
use fvm_shared::address::Network;
use crate::faucet::views::faucets::{calibnet::Faucet_Calibnet, mainnet::Faucet_Mainnet, Faucets};
use crate::faucet::views::{components::layout::Footer, home::Explorer};
use crate::utils::rpc_context::RpcContext;
use leptos::prelude::*;
use leptos::{component, leptos_dom::helpers::event_target_value, view, IntoView};
use leptos::{component, view, IntoView};
use leptos_meta::*;
use leptos_router::components::*;
use leptos_router::path;

#[allow(dead_code)]
pub fn shell(options: LeptosOptions) -> impl IntoView {
view! {
<!DOCTYPE html>
<html lang="en">
<head>
<title>Filecoin Forest Explorer Faucet - Get Free tFIL and FIL</title>
<meta charset="utf-8" />
<meta name="robots" content="index, follow" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta
name="description"
content="Get free tFIL and FIL on the Filecoin Forest Explorer Faucet by ChainSafe. Quickly connect your wallet, request tokens, and start building or experimenting on the Filecoin testnet or mainnet with ease."
/>

<AutoReload options=options.clone() />
<HydrationScripts options />
<MetaTags />
</head>
</html>
}
}

#[component]
pub fn Loader(loading: impl Fn() -> bool + 'static + Send) -> impl IntoView {
view! { <span class:loader=loading /> }
}

#[component]
pub fn BlockchainExplorer() -> impl IntoView {
let rpc_context = RpcContext::use_context();
let network_name = LocalResource::new(move || {
let provider = rpc_context.get();
async move { provider.network_name().await.ok() }
});

let network_version = LocalResource::new(move || {
let provider = rpc_context.get();
async move { provider.network_version().await.ok() }
});

view! {
<main class="min-h-screen flex flex-col flex-grow space-y-8">
<div class="space-y-6 flex flex-col items-center">
<h1 class="text-4xl font-extrabold leading-none tracking-tight text-gray-900 md:text-5xl lg:text-6xl">
Filecoin Forest Explorer Faucet
</h1>
<p class="max-w-2xl text-center">
The Filecoin Forest Explorer Faucet provides developers and users with free calibnet(tFil) and mainnet(FIL) to support their exploration, testing and development on the Filecoin network.
</p>
</div>

<div class="grid grid-cols-1 md:grid-cols-2 gap-6 max-w-4xl w-full m-auto">
<div class="bg-white p-6 rounded-lg border border-gray-100">
<h2 class="text-lg font-semibold text-gray-900 mb-4">What does the faucet offer?</h2>
<ul class="space-y-3">
<li class="flex items-start">
<CheckIcon />
<span class="text-gray-600">Free calibnet tFIL for experimentation and development.</span>
</li>
<li class="flex items-start">
<CheckIcon />
<span class="text-gray-600">
Real mainnet FIL for contributors engaging with the Filecoin ecosystem.
</span>
</li>
<li class="flex items-start">
<CheckIcon />
<span class="text-gray-600">
A Quick and Easy way to request free tFIL and FIL - Just enter your wallet address.
</span>
</li>
</ul>
</div>

<div class="bg-white p-6 rounded-lg border border-gray-100">
<h2 class="text-lg font-semibold text-gray-900 mb-4">Why use this faucet?</h2>
<ul class="space-y-3">
<li class="flex items-start">
<LightningIcon class="text-blue-500".to_string() />
<span class="text-gray-600">
Supports both calibnet and mainnet, unlike typical faucets.
</span>
</li>
<li class="flex items-start">
<LightningIcon class="text-blue-500".to_string() />
<span class="text-gray-600">
Enables testing of smart contracts, storage deals, and blockchain interactions without financial risk.
</span>
</li>
<li class="flex items-start">
<LightningIcon class="text-blue-500".to_string() />
<span class="text-gray-600">
Easy access to FIL for developers and users building on Filecoin.
</span>
</li>
<li class="flex items-start">
<LightningIcon class="text-blue-500".to_string() />
<span class="text-gray-600">
Need help? Visit the
<a class="text-blue-500" href="https://filecoin.io/slack" target="_blank">
{" "}
Filecoin Slack
</a>{" "}or <a class="text-blue-500" href="https://docs.filecoin.io" target="_blank">
{" "}
documentation
</a>.
</span>
</li>
</ul>
</div>
</div>

<div class="space-y-6 flex flex-col items-center">
<div class="relative w-64">
<select
on:change=move |ev| { rpc_context.set(event_target_value(&ev)) }
class="w-full px-4 py-2 text-sm text-gray-700 bg-white border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 hover:border-gray-400 transition-colors cursor-pointer appearance-none"
>
<option value=Provider::get_network_url(Network::Testnet)>Glif.io Calibnet</option>
<option value=Provider::get_network_url(Network::Mainnet)>Glif.io Mainnet</option>
</select>
<div class="pointer-events-none absolute inset-y-0 right-0 flex items-center px-2 text-gray-700">
<svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
</svg>
</div>
</div>
<div class="flex items-center w-[300px] justify-between">
<p>Network:</p>
<Transition fallback=move || view! { <p>Loading network name...</p> }>
<p>
<span>{move || network_name.get().flatten()}</span>
<Loader loading=move || network_name.get().is_none() />
</p>
</Transition>
</div>
<div class="flex items-center w-[300px] justify-between">
<p>Version:</p>
<Transition fallback=move || view! { <p>Loading network version...</p> }>
<p>
<span>{move || network_version.get().flatten()}</span>
<Loader loading=move || network_version.get().is_none() />
</p>
</Transition>
</div>
<button class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-6 rounded-lg">
<a href="/faucet">To faucet list</a>
</button>
</div>

</main>
}
}

#[component]
fn Footer() -> impl IntoView {
view! {
<footer class="py-4 text-center">
<a
class="text-green-600"
target="_blank"
rel="noopener noreferrer"
href="https://github.com/ChainSafe/forest-explorer"
>
Forest Explorer
</a>
", built with ❤️ by "
<a class="text-blue-600" target="_blank" rel="noopener noreferrer" href="https://chainsafe.io">
ChainSafe Systems
</a>
</footer>
}
}

#[component]
pub fn App() -> impl IntoView {
provide_meta_context();
Expand All @@ -191,12 +16,12 @@ pub fn App() -> impl IntoView {
<Stylesheet href="/style.css" />
<Link rel="icon" type_="image/x-icon" href="/favicon.ico" />
<Router>
<div class="flex flex-col min-h-screen space-y-8 py-10 px-6 min-h-screen">
<div class="app-container">
<Routes fallback=|| "Not found.">
<Route path=path!("/") view=BlockchainExplorer />
<Route path=path!("/faucet") view=crate::faucet::views::Faucets />
<Route path=path!("/faucet/calibnet") view=crate::faucet::views::Faucet_Calibnet />
<Route path=path!("/faucet/mainnet") view=crate::faucet::views::Faucet_Mainnet />
<Route path=path!("/") view=Explorer />
<Route path=path!("/faucet") view=Faucets />
<Route path=path!("/faucet/calibnet") view=Faucet_Calibnet />
<Route path=path!("/faucet/mainnet") view=Faucet_Mainnet />
</Routes>
<Footer />
</div>
Expand Down
18 changes: 9 additions & 9 deletions src/constants.rs → src/faucet/constants.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
use std::sync::LazyLock;

use fvm_shared::econ::TokenAmount;
use std::sync::LazyLock;

/// The rate limit imposed by the CloudFlare's rate limiter, and also reflected in the user
/// interface.
// Calibnet constants
pub const CALIBNET_RATE_LIMIT_SECONDS: i64 = 60;
pub static FIL_CALIBNET_UNIT: &str = "tFIL";
/// The amount of mainnet FIL to be dripped to the user. This corresponds to 1 tFIL.
pub static CALIBNET_DRIP_AMOUNT: LazyLock<TokenAmount> =
LazyLock::new(|| TokenAmount::from_whole(1));

// Mainnet constants
pub const MAINNET_RATE_LIMIT_SECONDS: i64 = 600;
pub static FIL_MAINNET_UNIT: &str = "FIL";
/// The amount of mainnet FIL to be dripped to the user. This corresponds to 0.01 FIL.
pub static MAINNET_DRIP_AMOUNT: LazyLock<TokenAmount> =
LazyLock::new(|| TokenAmount::from_nano(10_000_000));
/// The amount of calibnet tFIL to be dripped to the user.
pub static CALIBNET_DRIP_AMOUNT: LazyLock<TokenAmount> =
LazyLock::new(|| TokenAmount::from_whole(1));
pub static FIL_MAINNET_UNIT: &str = "FIL";
pub static FIL_CALIBNET_UNIT: &str = "tFIL";
Loading
Loading