use blstrs::Scalar;
use colored::Colorize;
use pallas_addresses::Address;
use pallas_crypto::key::ed25519::SecretKey;
use pallas_traverse::fees;
use pallas_txbuilder::{BuildConway, BuiltTransaction, Input, Output, StagingTransaction};
use pallas_wallet::PrivateKey;
use rand_core::OsRng;
use seedelf_cli::address;
use seedelf_cli::assets::Assets;
use seedelf_cli::constants::MAXIMUM_TOKENS_PER_UTXO;
use seedelf_cli::convert;
use seedelf_cli::display::preprod_text;
use seedelf_cli::koios::{UtxoResponse, submit_tx};
use seedelf_cli::register::Register;
use seedelf_cli::setup;
use seedelf_cli::transaction::wallet_minimum_lovelace_with_assets;
use seedelf_cli::utxos;
pub async fn run(network_flag: bool, variant: u64) -> Result<(), String> {
preprod_text(network_flag);
println!("\n{}", "Sweeping All dApp UTxOs".bright_blue(),);
let wallet_addr: Address = address::wallet_contract(network_flag, variant);
let mut draft_tx: StagingTransaction = StagingTransaction::new();
let scalar: Scalar = setup::load_wallet();
let vkey = convert::secret_key_to_public_key(scalar);
let addr = address::dapp_address(vkey.clone(), network_flag);
let addr_bech32 = addr.to_bech32().unwrap();
let all_utxos: Vec<UtxoResponse> =
utxos::collect_all_address_utxos(&addr_bech32, network_flag).await;
if all_utxos.is_empty() {
return Err("Not Enough Lovelace/Tokens".to_string());
}
let (total_lovelace, tokens) = utxos::assets_of(all_utxos.clone());
for utxo in all_utxos.clone() {
let this_input: Input = Input::new(
pallas_crypto::hash::Hash::new(
hex::decode(utxo.tx_hash.clone())
.expect("Invalid hex string")
.try_into()
.expect("Failed to convert to 32-byte array"),
),
utxo.tx_index,
);
draft_tx = draft_tx.input(this_input.clone());
}
let tmp_fee: u64 = 200_000;
draft_tx = draft_tx
.fee(tmp_fee)
.disclosed_signer(pallas_crypto::hash::Hash::new(
hex::decode(vkey.clone())
.unwrap()
.try_into()
.expect("Not Correct Length"),
));
let change_token_per_utxo: Vec<Assets> = tokens
.clone()
.split(MAXIMUM_TOKENS_PER_UTXO.try_into().unwrap());
let number_of_change_utxo: usize = change_token_per_utxo.len();
let mut lovelace_amount: u64 = total_lovelace;
for (i, change) in change_token_per_utxo.iter().enumerate() {
let datum_vector: Vec<u8> = Register::create(scalar).rerandomize().to_vec();
let minimum: u64 = wallet_minimum_lovelace_with_assets(change.clone());
let change_lovelace: u64 = if i == number_of_change_utxo - 1 {
lovelace_amount -= tmp_fee;
lovelace_amount
} else {
lovelace_amount -= minimum;
minimum
};
let mut change_output: Output = Output::new(wallet_addr.clone(), change_lovelace)
.set_inline_datum(datum_vector.clone());
for asset in change.items.clone() {
change_output = change_output
.add_asset(asset.policy_id, asset.token_name, asset.amount)
.unwrap();
}
draft_tx = draft_tx.output(change_output);
}
if number_of_change_utxo == 0 {
let datum_vector: Vec<u8> = Register::create(scalar).rerandomize().to_vec();
let change_lovelace: u64 = lovelace_amount - tmp_fee;
let change_output: Output = Output::new(wallet_addr.clone(), change_lovelace)
.set_inline_datum(datum_vector.clone());
draft_tx = draft_tx.output(change_output);
}
let mut raw_tx: StagingTransaction = draft_tx.clone().clear_fee();
for i in 0..number_of_change_utxo + 1 {
raw_tx = raw_tx.remove_output(number_of_change_utxo - i);
}
let intermediate_tx: BuiltTransaction = draft_tx.build_conway_raw().unwrap();
let fake_signer_secret_key: SecretKey = SecretKey::new(OsRng);
let fake_signer_private_key: PrivateKey = PrivateKey::from(fake_signer_secret_key);
let tx_size: u64 = intermediate_tx
.sign(fake_signer_private_key)
.unwrap()
.tx_bytes
.0
.len()
.try_into()
.unwrap();
let tx_fee = fees::compute_linear_fee_policy(tx_size, &(fees::PolicyParams::default()));
println!(
"{} {}",
"\nTx Size Fee:".bright_blue(),
tx_fee.to_string().bright_white()
);
raw_tx = raw_tx.fee(tx_fee);
let change_token_per_utxo: Vec<Assets> = tokens
.clone()
.split(MAXIMUM_TOKENS_PER_UTXO.try_into().unwrap());
let number_of_change_utxo: usize = change_token_per_utxo.len();
let mut lovelace_amount: u64 = total_lovelace;
for (i, change) in change_token_per_utxo.iter().enumerate() {
let datum_vector: Vec<u8> = Register::create(scalar).rerandomize().to_vec();
let minimum: u64 = wallet_minimum_lovelace_with_assets(change.clone());
let change_lovelace: u64 = if i == number_of_change_utxo - 1 {
lovelace_amount -= tx_fee;
lovelace_amount
} else {
lovelace_amount -= minimum;
minimum
};
let mut change_output: Output = Output::new(wallet_addr.clone(), change_lovelace)
.set_inline_datum(datum_vector.clone());
for asset in change.items.clone() {
change_output = change_output
.add_asset(asset.policy_id, asset.token_name, asset.amount)
.unwrap();
}
raw_tx = raw_tx.output(change_output);
}
if number_of_change_utxo == 0 {
let datum_vector: Vec<u8> = Register::create(scalar).rerandomize().to_vec();
let change_lovelace: u64 = lovelace_amount - tx_fee;
let change_output: Output = Output::new(wallet_addr.clone(), change_lovelace)
.set_inline_datum(datum_vector.clone());
raw_tx = raw_tx.output(change_output);
}
let tx: BuiltTransaction = raw_tx.build_conway_raw().unwrap();
let signed_tx_cbor = tx.sign(convert::secret_key_to_private_key(scalar)).unwrap();
println!(
"\nTx Cbor: {}",
hex::encode(signed_tx_cbor.tx_bytes.clone()).white()
);
match submit_tx(hex::encode(signed_tx_cbor.tx_bytes), network_flag).await {
Ok(response) => {
if let Some(_error) = response.get("contents") {
println!("\nError: {}", response);
std::process::exit(1);
}
println!("\nTransaction Successfully Submitted!");
println!(
"\nTx Hash: {}",
response.as_str().unwrap_or("default").bright_cyan()
);
if network_flag {
println!(
"{}",
format!(
"\nhttps://preprod.cardanoscan.io/transaction/{}",
response.as_str().unwrap_or("default")
)
.bright_purple()
);
} else {
println!(
"{}",
format!(
"\nhttps://cardanoscan.io/transaction/{}",
response.as_str().unwrap_or("default")
)
.bright_purple()
);
}
}
Err(err) => {
eprintln!("Failed to submit tx: {}", err);
}
}
Ok(())
}