/ cli / src / commands / developer / transfer_private.rs
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  }