diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..f14b6ad
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,13 @@
+[package]
+name = "grin-finalize"
+version = "0.1.0"
+edition = "2024"
+
+[dependencies]
+warp = { version = "0.3", features = ["tls"] }
+tokio = { version = "1", features = ["full"] }
+tokio-rustls = "0.22"
+serde = { version = "1.0", features = ["derive"] }
+chrono = "0.4"
+simplelog = "0.11"
+log = "0.4"
\ No newline at end of file
diff --git a/finalize.py b/finalize.py
new file mode 100644
index 0000000..0a9788a
--- /dev/null
+++ b/finalize.py
@@ -0,0 +1,44 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+
+"""
+Script Name: finalize.py
+Author: transatoshi
+Date Created: 2025-05-11
+Description: This script takes care of finalizing a Grin transaction via slatepack
+"""
+
+
+import pexpect
+import time
+
+def run_grin_wallet():
+ # Start the grin-wallet finalize command
+ command = "
/grin-wallet finalize"
+ child = pexpect.spawn(command)
+
+ # Expect the password prompt and send the password
+ child.expect("Password:")
+ child.sendline("")
+
+ # Expect the slatepack message prompt
+ child.expect("Please paste your encoded slatepack message:")
+
+ # Read the contents of the slatepack file
+ with open("/home/grin/grin-finalize/slatepack.tmp", "r") as file:
+ slatepack_content = file.read()
+
+ # Send the contents of the slatepack file
+ child.sendline(slatepack_content)
+
+ # Finalize by hitting return
+ child.sendline()
+
+ # Wait for the command to complete
+ child.expect(pexpect.EOF)
+
+ # Print the output
+ print(child.before.decode('utf-8'))
+
+if __name__ == "__main__":
+ run_grin_wallet()
diff --git a/src/main.rs b/src/main.rs
new file mode 100644
index 0000000..45b9396
--- /dev/null
+++ b/src/main.rs
@@ -0,0 +1,95 @@
+use std::fs::File;
+use std::io::Write;
+use std::process::Command;
+use log::{info, error};
+use serde::{Deserialize, Serialize};
+use simplelog::{Config, LevelFilter, ColorChoice, TermLogger, WriteLogger, CombinedLogger, TerminalMode};
+use warp::Filter;
+
+#[derive(Deserialize)]
+struct SendRequest {
+ slatepack: String,
+}
+
+#[derive(Serialize)]
+struct Response {
+ message: String,
+}
+
+#[tokio::main]
+async fn main() {
+ // Initialize logging
+ let log_file = File::create("app.log").unwrap();
+ CombinedLogger::init(vec![
+ TermLogger::new(LevelFilter::Info, Config::default(), TerminalMode::Mixed, ColorChoice::Auto),
+ WriteLogger::new(LevelFilter::Info, Config::default(), log_file),
+ ]).unwrap();
+
+ // Define the POST route
+ let send_finalize = warp::post()
+ .and(warp::path("finalize"))
+ .and(warp::body::json())
+ .map(|request: SendRequest| {
+ // Extract the slatepack message from the request
+ let slatepack = request.slatepack;
+
+ // Write slatepack to a file
+ let file_path = "/home/grin/grin-finalize/slatepack.tmp";
+ if let Err(e) = write_to_file(file_path, &slatepack) {
+ error!("Failed to write slatepack to file: {:?}", e);
+ return warp::reply::json(&Response {
+ message: "Failed to write slatepack to file".to_string(),
+ });
+ }
+
+ // Execute the command
+ let output = Command::new("bash")
+ .arg("-c")
+ .arg(format!(
+ "python /finalize.py"
+ ))
+ .output()
+ .expect("Failed to execute command");
+
+ // Process the command output
+ let stdout = String::from_utf8_lossy(&output.stdout);
+ let stderr = String::from_utf8_lossy(&output.stderr);
+
+ if stderr.is_empty() {
+ info!("Transaction finalized: {}", stdout);
+ return warp::reply::json(&Response {
+ message: "Grin transaction successfully finalized ツ".to_string(),
+ });
+ } else {
+ error!("Failed to finalize transaction: {}", stderr);
+ return warp::reply::json(&Response {
+ message: format!("Error: {}", stderr),
+ });
+ }
+ });
+
+ // Load SSL keys and certs
+ let cert_path = "/cert.pem";
+ let key_path = "/cert.key";
+
+ // Enable CORS
+ let cors = warp::cors()
+ .allow_origin("")
+ .allow_methods(vec!["POST"])
+ .allow_headers(vec!["Content-Type"]);
+
+ // Start the Warp server with CORS and TLS
+ warp::serve(send_finalize.with(cors))
+ .tls()
+ .cert_path(cert_path)
+ .key_path(key_path)
+ .run(([0, 0, 0, 0], 3032)) // Listen on all interfaces
+ .await;
+}
+
+// Function to write slatepack to a file
+fn write_to_file(file_path: &str, content: &str) -> std::io::Result<()> {
+ let mut file = File::create(file_path)?;
+ file.write_all(content.as_bytes())?;
+ Ok(())
+}
\ No newline at end of file