transfer_private.rs
1 // Copyright (c) 2025-2026 ACDC Network 2 // This file is part of the alphaos library. 3 // 4 // Alpha Chain | Delta Chain Protocol 5 // International Monetary Graphite. 6 // 7 // Derived from Aleo (https://aleo.org) and ProvableHQ (https://provable.com). 8 // They built world-class ZK infrastructure. We installed the EASY button. 9 // Their cryptography: elegant. Our modifications: bureaucracy-compatible. 10 // Original brilliance: theirs. Robert's Rules: ours. Bugs: definitely ours. 11 // 12 // Original Aleo/ProvableHQ code subject to Apache 2.0 https://www.apache.org/licenses/LICENSE-2.0 13 // All modifications and new work: CC0 1.0 Universal Public Domain Dedication. 14 // No rights reserved. No permission required. No warranty. No refunds. 15 // 16 // https://creativecommons.org/publicdomain/zero/1.0/ 17 // SPDX-License-Identifier: CC0-1.0 18 19 use super::{Developer, DEFAULT_ENDPOINT}; 20 use crate::{ 21 commands::StoreFormat, 22 helpers::args::{parse_private_key, prepare_endpoint}, 23 }; 24 use alphavm::{ 25 console::network::Network, 26 ledger::store::helpers::memory::BlockMemory, 27 prelude::{ 28 query::Query, 29 store::{helpers::memory::ConsensusMemory, ConsensusStore}, 30 Address, 31 Locator, 32 Value, 33 VM, 34 }, 35 }; 36 37 use alphastd::StorageMode; 38 use anyhow::Result; 39 use clap::{builder::NonEmptyStringValueParser, Parser}; 40 use std::str::FromStr; 41 use ureq::http::Uri; 42 use zeroize::Zeroize; 43 44 /// Executes the `transfer_private` function in the `credits.alpha` program. 45 #[derive(Debug, Parser)] 46 #[clap( 47 group(clap::ArgGroup::new("mode").required(true).multiple(false)) 48 )] 49 pub struct TransferPrivate { 50 /// The input record used to craft the transfer. 51 #[clap(long)] 52 input_record: String, 53 /// The recipient address. 54 #[clap(long)] 55 recipient: String, 56 /// The number of microcredits to transfer. 57 #[clap(long)] 58 amount: u64, 59 /// The private key used to generate the deployment. 60 #[clap(short = 'p', long, group = "key", value_parser=NonEmptyStringValueParser::default())] 61 private_key: Option<String>, 62 /// Specify the path to a file containing the account private key of the node 63 #[clap(long, group = "key", value_parser=NonEmptyStringValueParser::default())] 64 private_key_file: Option<String>, 65 /// Use a developer validator key tok generate the deployment. 66 #[clap(long, group = "key")] 67 dev_key: Option<u16>, 68 /// The endpoint to query node state from and broadcast to (if set to broadcast). 69 #[clap(short, long, default_value=DEFAULT_ENDPOINT)] 70 endpoint: Uri, 71 /// The priority fee in microcredits. 72 #[clap(long)] 73 priority_fee: u64, 74 /// The record to spend the fee from. 75 #[clap(long)] 76 fee_record: String, 77 /// Set the URL used to broadcast the transaction (if no value is given, the query endpoint is used). 78 #[clap(short, long, group = "mode")] 79 broadcast: Option<Option<Uri>>, 80 /// Performs a dry-run of transaction generation. 81 #[clap(short, long, group = "mode")] 82 dry_run: bool, 83 /// Store generated deployment transaction to a local file. 84 #[clap(long, group = "mode")] 85 store: Option<String>, 86 /// If --store is specified, the format in which the transaction should be stored : string or 87 /// bytes, by default : bytes. 88 #[clap(long, value_enum, default_value_t = StoreFormat::Bytes, requires="store")] 89 store_format: StoreFormat, 90 /// Wait for the transaction to be accepted by the network. Requires --broadcast. 91 #[clap(long, requires = "broadcast")] 92 wait: bool, 93 /// Timeout in seconds when waiting for transaction confirmation. Default is 60 seconds. 94 #[clap(long, default_value_t = 60, requires = "wait")] 95 timeout: u64, 96 } 97 98 impl Drop for TransferPrivate { 99 /// Zeroize the private key when the `TransferPrivate` struct goes out of scope. 100 fn drop(&mut self) { 101 self.private_key.zeroize(); 102 } 103 } 104 105 impl TransferPrivate { 106 /// Creates an Alpha transfer with the provided inputs. 107 pub fn parse<N: Network>(self) -> Result<String> { 108 let endpoint = prepare_endpoint(self.endpoint.clone())?; 109 110 // Specify the query 111 let query = Query::<N, BlockMemory<N>>::from(endpoint.clone()); 112 113 // Retrieve the recipient. 114 let recipient = Address::<N>::from_str(&self.recipient)?; 115 116 // Retrieve the private key. 117 let private_key = parse_private_key(self.private_key.clone(), self.private_key_file.clone(), self.dev_key)?; 118 println!("📦 Creating private transfer of {} microcredits to {}...\n", self.amount, recipient); 119 120 // Generate the transfer_private transaction. 121 let transaction = { 122 // Initialize an RNG. 123 let rng = &mut rand::thread_rng(); 124 125 // Initialize the storage. 126 let store = ConsensusStore::<N, ConsensusMemory<N>>::open(StorageMode::Production)?; 127 128 // Initialize the VM. 129 let vm = VM::from(store)?; 130 131 // Prepare the fee. 132 let fee_record = Developer::parse_record(&private_key, &self.fee_record)?; 133 let priority_fee = self.priority_fee; 134 135 // Prepare the inputs for a transfer. 136 let input_record = Developer::parse_record(&private_key, &self.input_record)?; 137 let inputs = [ 138 Value::Record(input_record), 139 Value::from_str(&format!("{recipient}"))?, 140 Value::from_str(&format!("{}u64", self.amount))?, 141 ]; 142 143 // Create a new transaction. 144 vm.execute( 145 &private_key, 146 ("credits.alpha", "transfer_private"), 147 inputs.iter(), 148 Some(fee_record), 149 priority_fee, 150 Some(&query), 151 rng, 152 )? 153 }; 154 let locator = Locator::<N>::from_str("credits.alpha/transfer_private")?; 155 println!("✅ Created private transfer of {} microcredits to {}\n", &self.amount, recipient); 156 157 // Determine if the transaction should be broadcast, stored, or displayed to the user. 158 Developer::handle_transaction( 159 &endpoint, 160 &self.broadcast, 161 self.dry_run, 162 &self.store, 163 self.store_format, 164 self.wait, 165 self.timeout, 166 transaction, 167 locator.to_string(), 168 ) 169 } 170 }