71 lines
2.8 KiB
Rust
Raw Permalink Normal View History

2025-07-17 10:10:39 -03:00
use core::{
2025-07-16 15:37:49 -03:00
account::Account,
bytes_to_words,
2025-07-19 19:12:56 -03:00
types::{Address, AuthenticationPath},
visibility::AccountVisibility,
};
2025-07-17 11:07:18 -03:00
use nssa::program::TransferMultipleProgram;
2025-07-17 12:46:57 -03:00
use sparse_merkle_tree::SparseMerkleTree;
2025-07-18 17:10:33 -03:00
/// A private execution of the TransferMultiple function.
2025-07-11 19:35:54 -03:00
/// This actually "burns" a sender private account and "mints" two new private accounts:
2025-07-11 19:44:43 -03:00
/// one for the recipient with the transferred balance, and another owned by the sender with the remaining balance.
2025-07-16 17:25:03 -03:00
fn main() {
2025-07-18 17:10:33 -03:00
// Setup commitment tree, simulating a current chain state that has a private account already
// committed to the commitment tree.
2025-07-15 09:26:34 -03:00
let sender_private_key = [1, 2, 3, 4, 4, 3, 2, 1];
2025-07-11 19:44:43 -03:00
let sender = {
2025-07-18 17:10:33 -03:00
// Creating this here but it is supposed to be already in the private possesion of the user
2025-07-18 15:56:41 -03:00
let mut account = Account::new_from_private_key(sender_private_key);
2025-07-11 19:44:43 -03:00
account.balance = 150;
account
};
2025-07-15 13:08:13 -03:00
let commitment_tree = SparseMerkleTree::new([sender.commitment()].into_iter().collect());
2025-07-18 17:10:33 -03:00
// Get the root of the commitment tree and the authentication path of the commitment of the private account.
2025-07-15 13:54:59 -03:00
let root = bytes_to_words(&commitment_tree.root());
let auth_path: Vec<[u32; 8]> = commitment_tree
.get_authentication_path_for_value(sender.commitment())
.iter()
.map(bytes_to_words)
.collect();
let auth_path: AuthenticationPath = auth_path.try_into().unwrap();
2025-07-18 17:10:33 -03:00
// These are the new private account being minted by this private execution.
// (the `receiver_address` would be <Npk> in UTXO's terminology)
2025-07-17 11:07:18 -03:00
let receiver_address_1 = [99; 8];
2025-07-18 17:10:33 -03:00
let receiver_1 = new_default_account(receiver_address_1);
2025-07-17 11:07:18 -03:00
let receiver_address_2 = [100; 8];
2025-07-18 17:10:33 -03:00
let receiver_2 = new_default_account(receiver_address_2);
2025-07-11 19:35:54 -03:00
// Setup input account visibilites. All accounts are private for this execution.
let visibilities = vec![
AccountVisibility::Private(Some((sender_private_key, auth_path))),
AccountVisibility::Private(None),
AccountVisibility::Private(None),
];
2025-07-17 09:43:44 -03:00
2025-07-18 17:10:33 -03:00
// Set the balances to be sent to the two receiver addresses.
// This means, the execution will remove 70 tokens from the sender
// and send 30 to the first receiver and 40 to the second.
let balance_to_move = vec![30, 40];
// Execute and prove the outer program for the TransferMultipleProgram.
2025-07-18 20:34:07 -03:00
// This is executed off-chain by the sender.
let (receipt, _) = nssa::execute_offchain::<TransferMultipleProgram>(
2025-07-17 11:07:18 -03:00
&[sender, receiver_1, receiver_2],
2025-07-18 17:10:33 -03:00
balance_to_move,
&visibilities,
root,
)
.unwrap();
2025-07-11 19:21:06 -03:00
2025-07-18 17:10:33 -03:00
// Verify the proof
2025-07-19 18:08:57 -03:00
assert!(nssa::verify_privacy_execution(receipt).is_ok());
2025-07-18 17:10:33 -03:00
println!("OK!");
}
2025-07-17 09:20:03 -03:00
2025-07-18 17:10:33 -03:00
fn new_default_account(address: Address) -> Account {
Account::new(address, 0)
2025-07-11 19:21:06 -03:00
}