Skip to content

Commit

Permalink
Faucet working
Browse files Browse the repository at this point in the history
  • Loading branch information
phklive committed Feb 23, 2024
1 parent 61c5cb7 commit 3eda77c
Show file tree
Hide file tree
Showing 11 changed files with 519 additions and 0 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
[workspace]
members = [
"block-producer",
"faucet",
"node",
"proto",
"rpc",
Expand Down
19 changes: 19 additions & 0 deletions faucet/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
[package]
name = "miden-node-faucet"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
actix-web = "4"
actix-files = "0.6.5"
actix-cors = "0.7.0"
async-mutex = "1.4.0"
clap = { version = "4.5.1", features = ["derive"] }
derive_more = "0.99.17"
miden-client = { git = "https://github.com/0xPolygonMiden/miden-client", branch = "phklive-fix-faucet", features = [ "testing", "concurrent", ] }
miden-lib = { workspace = true }
miden-node-proto = { path = "../proto" }
miden-objects = { workspace = true }
serde = { version = "1.0", features = ["derive"] }
38 changes: 38 additions & 0 deletions faucet/src/cli.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
use std::path::PathBuf;

use clap::{Parser, Subcommand};

#[derive(Parser)]
#[clap(name = "Miden Faucet")]
#[clap(about = "A command line tool for Miden Faucet", long_about = None)]
pub struct Cli {
#[clap(subcommand)]
pub command: Command,
}

#[derive(Subcommand)]
pub enum Command {
/// Initialise a new Miden faucet from arguments
Init {
#[clap(short, long, required = true)]
token_symbol: String,

#[clap(short, long, required = true)]
decimals: u8,

#[clap(short, long, required = true)]
max_supply: u64,

#[clap(short, long)]
asset_amount: u64,
},

/// Imports an existing Miden faucet from specified file
Import {
#[clap(short, long, required = true)]
faucet_path: PathBuf,

#[clap(short, long)]
asset_amount: u64,
},
}
32 changes: 32 additions & 0 deletions faucet/src/errors.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
use actix_web::{
error,
http::{header::ContentType, StatusCode},
HttpResponse,
};
use derive_more::Display;

#[derive(Debug, Display)]
pub enum FaucetError {
BadRequest(String),
InternalServerError(String),
}

impl error::ResponseError for FaucetError {
fn error_response(&self) -> HttpResponse<actix_web::body::BoxBody> {
let message = match self {
FaucetError::BadRequest(msg) => msg,
FaucetError::InternalServerError(msg) => msg,
};

HttpResponse::build(self.status_code())
.insert_header(ContentType::html())
.body(message.to_owned())
}

fn status_code(&self) -> actix_web::http::StatusCode {
match *self {
FaucetError::InternalServerError(_) => StatusCode::INTERNAL_SERVER_ERROR,
FaucetError::BadRequest(_) => StatusCode::BAD_REQUEST,
}
}
}
84 changes: 84 additions & 0 deletions faucet/src/handlers.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
use crate::{errors::FaucetError, FaucetState};
use actix_web::{get, http::header, web, HttpResponse, Result};
use miden_client::client::transactions::TransactionTemplate;
use miden_objects::{
accounts::AccountId, assets::FungibleAsset, notes::NoteId, utils::serde::Serializable,
};
use serde::Deserialize;

#[derive(Deserialize)]
struct User {
account_id: String,
}

#[get("/get_tokens")]
pub async fn get_tokens(
req: web::Query<User>,
state: web::Data<FaucetState>,
) -> Result<HttpResponse> {
println!("Received a request with account_id: {}", req.account_id);

let client = state.client.clone();

// Receive and hex user account id
let target_account_id = AccountId::from_hex(req.account_id.as_str())
.map_err(|err| FaucetError::BadRequest(err.to_string()))?;

// Instantiate asset
let asset =
FungibleAsset::new(state.id, state.asset_amount).expect("Failed to instantiate asset.");

// Instantiate transaction template
let tx_template = TransactionTemplate::MintFungibleAsset {
asset,
target_account_id,
};

// Run transaction executor & execute transaction
let tx_result = client
.lock()
.await
.new_transaction(tx_template)
.map_err(|err| FaucetError::InternalServerError(err.to_string()))?;

// Get note id
let note_id: NoteId = tx_result
.created_notes()
.first()
.ok_or_else(|| {
FaucetError::InternalServerError("Failed to access generated note.".to_string())
})?
.id();

// Run transaction prover & send transaction to node
{
let mut client_guard = client.lock().await;
client_guard
.send_transaction(tx_result)
.await
.map_err(|err| FaucetError::InternalServerError(err.to_string()))?;
}

// Get note from client store
let input_note = state
.client
.clone()
.lock()
.await
.get_input_note(note_id)
.map_err(|err| FaucetError::InternalServerError(err.to_string()))?;

// Serialize note for transport
let bytes = input_note.to_bytes();

// Send generated note to user
Ok(HttpResponse::Ok()
.content_type("application/octet-stream")
.append_header(header::ContentDisposition {
disposition: actix_web::http::header::DispositionType::Attachment,
parameters: vec![actix_web::http::header::DispositionParam::Filename(
"note.mno".to_string(),
)],
})
.body(bytes))
}
110 changes: 110 additions & 0 deletions faucet/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
use actix_cors::Cors;
use actix_files::Files;
use actix_web::{web, App, HttpServer};
use async_mutex::Mutex;
use clap::Parser;
use cli::Cli;
use handlers::get_tokens;
use miden_client::client::rpc::TonicRpcClient;
use miden_client::client::Client;
use miden_client::config::{ClientConfig, RpcConfig, StoreConfig};
use miden_client::store::data_store::SqliteDataStore;
use miden_client::store::Store;
use miden_objects::accounts::AccountId;
use std::io;
use std::sync::Arc;

mod cli;
mod errors;
mod handlers;
mod utils;

#[derive(Clone)]
pub struct FaucetState {
id: AccountId,
asset_amount: u64,
client: Arc<Mutex<Client<TonicRpcClient, SqliteDataStore>>>,
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
let cli = Cli::parse();

// Setup the data_store
let store_config = StoreConfig::default();
let store = Store::new(store_config).expect("Failed to instantiate store.");
let data_store = SqliteDataStore::new(store);

// Setup the tonic rpc client
let rpc_config = RpcConfig::default();
let api = TonicRpcClient::new(&rpc_config.endpoint.to_string());

// Setup the client
let client_config = ClientConfig::default();
let mut client =
Client::new(client_config, api, data_store).expect("Failed to instantiate client.");

let amount: u64;

// Create the faucet account
let faucet_account = match &cli.command {
cli::Command::Init {
token_symbol,
decimals,
max_supply,
asset_amount,
} => {
amount = *asset_amount;
utils::create_fungible_faucet(token_symbol, decimals, max_supply, &mut client)
}
cli::Command::Import {
faucet_path,
asset_amount,
} => {
amount = *asset_amount;
utils::import_fungible_faucet(faucet_path, &mut client)
}
}
.map_err(|_| {
io::Error::new(
io::ErrorKind::InvalidData,
"Failed to create faucet account.",
)
})?;

// Sync client
client
.sync_state()
.await
.map_err(|_| io::Error::new(io::ErrorKind::ConnectionRefused, "Failed to sync state."))?;

println!(
"✅ Faucet setup successful, account id: {}",
faucet_account.id()
);

println!("🚀 Starting server on: http://127.0.0.1:8080");

// Instantiate faucet state
let faucet_state = FaucetState {
id: faucet_account.id(),
asset_amount: amount,
client: Arc::new(Mutex::new(client)),
};

HttpServer::new(move || {
let cors = Cors::default()
.allow_any_origin()
.allowed_methods(vec!["GET"]);
App::new()
.app_data(web::Data::new(faucet_state.clone()))
.wrap(cors)
.service(get_tokens)
.service(Files::new("/", "src/static").index_file("index.html"))
})
.bind(("127.0.0.1", 8080))?
.run()
.await?;

Ok(())
}
Binary file added faucet/src/static/background.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
82 changes: 82 additions & 0 deletions faucet/src/static/index.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
input:focus {
outline: none;
}

*,
*::before,
*::after {
box-sizing: border-box;
}


body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
-webkit-font-smoothing: antialiased;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
background-image: url(./background.png);
background-repeat: repeat;
}

#error-message {
display: none;
color: red;
text-align: center;
margin-bottom: 5px;
}

#navbar {
position: fixed;
top: 0;
left: 0;
background-color: rgb(17, 24, 39);
width: 100%;
padding: 20px;
}

#title {
font-size: x-large;
text-align: center;
font-weight: bold;
color: white;
margin: 0;
}

#center-container {
background-color: rgb(17, 24, 39);
border-radius: 10px;
display: flex;
flex-direction: column;
padding: 30px;
}

#subtitle {
font-size: large;
text-align: center;
font-weight: bold;
color: white;
margin: 0;
margin-bottom: 20px;
}

#account-id {
padding: 10px;
border-radius: 10px;
border: 1px solid #ccc;
margin-bottom: 30px;
width: 300px;
}

#button {
color: white;
border-radius: 10px;
font-weight: bold;
padding: 10px 20px;
background-color: rgb(124, 58, 237);
width: 300px;
}
Loading

0 comments on commit 3eda77c

Please sign in to comment.