Contractless/src/bin/create_marketing_tx.rs

180 lines
5.6 KiB
Rust
Raw Normal View History

2026-05-24 17:56:57 +00:00
use blockchain::blocks::marketing::{MarketingTransaction, UnsignedMarketingTransaction};
use blockchain::common::cli_prompts::{prompt_hidden_nonempty, prompt_visible};
use blockchain::common::types::MARKETING_FEE;
use blockchain::json;
use blockchain::wallets::structures::Wallet;
use blockchain::File;
use blockchain::Utc;
use blockchain::{create_dir_all, AsyncWriteExt};
// pad the coin to ensure 15 characters
fn pad_to_width(input: &str, width: usize) -> String {
let mut result = String::with_capacity(width); // Pre-allocate string with capacity
let _ = std::fmt::write(
&mut result,
format_args!("{input:<width$}"),
);
result
}
fn display_fee(value: u64) -> f64 {
value as f64 / 100_000_000.0
}
#[tokio::main]
async fn main() {
let campaign_data = prompt_visible("What is the id number of your campaign? ").await;
let campaign: u64 = campaign_data
.trim()
.parse()
.expect("Please enter a valid number");
let ad_type_input =
prompt_visible("What type of campaign is this? banner, social, or text: ").await;
let ad_type = pad_to_width(ad_type_input.trim(), 6);
let keyword_input = prompt_visible("Enter a keyword, can be up to 40 characters: ").await;
let keyword = pad_to_width(keyword_input.trim(), 40);
let displayed_input =
prompt_visible("Enter the location the ad was displayed, can be up to 100 characters: ")
.await;
let displayed = pad_to_width(displayed_input.trim(), 100);
let impression_input = prompt_visible("How many times was the ad viewed? (0 to 255): ").await;
let impression: u8 = impression_input
.trim()
.parse()
.expect("Please enter a valid number");
let click_input = prompt_visible("How many times was the ad clicked? (0 to 255): ").await;
let click: u8 = click_input
.trim()
.parse()
.expect("Please enter a valid number");
let impression_value_data =
prompt_visible("What is the value of each impression? (1.25): ").await;
let impression_value: f32 = impression_value_data
.trim()
.parse()
.expect("Please enter a valid number");
let impression_value = (impression_value * 100.0) as u16;
let click_value_data = prompt_visible("What is the value of each click? (1.25): ").await;
let click_value: f32 = click_value_data
.trim()
.parse()
.expect("Please enter a valid number");
let click_value = (click_value * 100.0) as u16;
let txfee_prompt = format!(
"Please enter the amount for the fee: (e.g., 0.001, minimum fee {:.8})",
display_fee(MARKETING_FEE)
);
let txfee_string = prompt_visible(&format!("{txfee_prompt}: ")).await;
let txfee_f32: f32 = txfee_string
.trim()
.parse()
.expect("Please enter a valid value.");
let txfee = ((txfee_f32 as f64) * (100000000_f64)).round() as u64;
let decryption_key = prompt_hidden_nonempty(
"What is your wallet decryption key? ",
"Wallet key cannot be empty. Please try again.",
)
.await;
let wallet = match Wallet::try_obtain_wallet(decryption_key, None).await {
Ok(wallet) => wallet,
Err(err) => {
eprintln!("Wallet decryption failed: {err}");
return;
}
};
let private_key = &wallet.saved.private_key;
let address = &wallet.saved.short_address;
// Set type and timestamp
let txtype = 5;
let timestamp = Utc::now().timestamp() as u32;
// Validate wallets
if !Wallet::short_address_validation(address.trim_matches('"')) {
println!("creator wallet invalid: {}", &address);
return;
}
let unsigned_marketing = UnsignedMarketingTransaction::new(
txtype,
timestamp,
campaign,
&ad_type,
&keyword,
&displayed,
impression,
click,
impression_value,
click_value,
address.trim_matches('"'),
txfee,
)
.await;
let marketing = match MarketingTransaction::new(unsigned_marketing, private_key).await {
Ok(tx) => tx,
Err(err) => {
eprintln!("Failed to sign marketing transaction: {err}");
return;
}
};
let hashed_data = marketing.unsigned_marketing.hash().await;
let signature = marketing.signature.clone();
// Add the signature and hash
let output = json!({
"txtype": txtype,
"timestamp": timestamp,
"campaign": campaign,
"ad_type": ad_type,
"keyword": keyword,
"displayed": displayed,
"impression": impression,
"click": click,
"impression_value": impression_value,
"click_value": click_value,
"advertiser": address.trim_matches('"'),
"txfee": txfee,
"hash": hashed_data,
"signature": signature
});
let output_str = serde_json::to_string_pretty(&output).expect("Failed to serialize JSON");
// Define the directory path
let dir_path = "./transactions";
// Create the directory if it doesn't exist
if let Err(e) = create_dir_all(&dir_path).await {
eprintln!("Failed to create directory: {e}");
return;
}
// Define the file path
let file_path = format!("{dir_path}/{hashed_data}.json");
// Open the file for writing asynchronously
let mut file = File::create(&file_path)
.await
.expect("Failed to create file");
// Write the JSON string to the file asynchronously
if let Err(e) = file.write_all(output_str.as_bytes()).await {
eprintln!("Failed to write file: {e}");
return;
}
println!("transaction: {output_str}");
}