Contractless/src/bin/create_nft_tx.rs

158 lines
4.9 KiB
Rust
Raw Normal View History

2026-05-24 17:56:57 +00:00
use blockchain::blocks::nft::{CreateNftTransaction, UnsignedCreateNftTransaction};
use blockchain::common::cli_prompts::{prompt_hidden_nonempty, prompt_visible};
use blockchain::common::types::CREATE_NFT_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() {
// get user input series
let series_data = prompt_visible("Are you creating a 1/1 or a collection? ").await;
let series = if series_data.trim() == "collection" {
1
} else {
0
};
// get user input ticker
let nft_ticker_name = prompt_visible("Please enter the name for your NFT. This can be 3 to 15 characters and must be 100% unique. First come first serve: ").await;
let nft_name = pad_to_width(nft_ticker_name.trim(), 15);
// get the padded CID string
let ipfs_hash = prompt_visible("Enter your IPFS CID for your NFT. This will be stored in a fixed 100 character field, so shorter CIDs are padded with spaces: ").await;
let item_ipfs = pad_to_width(ipfs_hash.trim(), 100);
// how many items in the collection or 1 for 1/1s
let count_string =
prompt_visible("Please enter the number of items in your collection, enter 1 for 1/1s: ")
.await;
let count: u32 = count_string
.trim()
.parse()
.expect("Please enter a valid number");
// get the nft desc
let nft_desc = prompt_visible("Enter your nft description, A max of 100 characters: ").await;
let desc = pad_to_width(nft_desc.trim(), 100);
// get user input txfee
let txfee_prompt = format!(
"Please enter the amount for the fee: (eg. 0.005, minimum fee {:.8})",
display_fee(CREATE_NFT_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 timestampe
let txtype = 4;
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_create_nft = UnsignedCreateNftTransaction::new(
txtype,
timestamp,
address.trim_matches('"'),
series,
&nft_name,
&item_ipfs,
count,
&desc,
txfee,
)
.await;
let create_nft = match CreateNftTransaction::new(unsigned_create_nft, private_key).await {
Ok(tx) => tx,
Err(err) => {
eprintln!("Failed to sign NFT transaction: {err}");
return;
}
};
let hashed_data = create_nft.unsigned_create_nft.hash().await;
let signature = create_nft.signature.clone();
//add the signature and hash
let output = json!({
"txtype": txtype,
"timestamp": timestamp,
"creator": address.trim_matches('"'),
"series": series,
"nft_name": nft_name,
"item_ipfs": item_ipfs,
"count": count,
"desc": desc,
"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}");
}