From 071dd946717bfec2f43a3a66b24f116b9f196f9b Mon Sep 17 00:00:00 2001 From: jonesmarvin8 <83104039+jonesmarvin8@users.noreply.github.com> Date: Wed, 3 Jun 2026 09:32:04 -0400 Subject: [PATCH] Rebase to main --- Cargo.lock | 1 + docs/LEZ testnet v0.1 tutorials/keycard.md | 21 +++-- lez/keycard_wallet/src/python_path.rs | 3 +- lez/keycard_wallet/tests/keycard_test_3.sh | 2 +- lez/keycard_wallet/tests/keycard_tests.sh | 10 ++- lez/keycard_wallet/tests/keycard_tests_2.sh | 4 +- lez/wallet/src/account_manager.rs | 2 +- lez/wallet/src/cli/mod.rs | 2 +- .../native_token_transfer/public.rs | 89 +------------------ lez/wallet/src/signing.rs | 1 - 10 files changed, 30 insertions(+), 105 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d5ce6321..e0c8ea2c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4617,6 +4617,7 @@ dependencies = [ "pyo3", "serde", "serde_json", + "zeroize", ] [[package]] diff --git a/docs/LEZ testnet v0.1 tutorials/keycard.md b/docs/LEZ testnet v0.1 tutorials/keycard.md index ab42a8bd..47573f12 100644 --- a/docs/LEZ testnet v0.1 tutorials/keycard.md +++ b/docs/LEZ testnet v0.1 tutorials/keycard.md @@ -69,7 +69,10 @@ The default password (`KeycardDefaultPairing`) is [recommended](https://docs.key To use a custom pairing password, set it before `init`: ```bash -export KEYCARD_PAIRING_PASSWORD=my-custom-password +# Note: Keep the leading space before this command. +# Leading space prevents this command from being stored in shell history +# (when HISTCONTROL=ignorespace is enabled). + export KEYCARD_PAIRING_PASSWORD=my-custom-password wallet keycard init ``` @@ -152,7 +155,7 @@ Keycard PIN: First install the wallet with the `keycard-debug` feature: ```bash -cargo install --path wallet --force --features keycard-debug +cargo install --path lez/wallet --force --features keycard-debug ``` Then run the command: @@ -168,7 +171,7 @@ VSK: 30f798893977a7b7263d1f77abf58e11e014428c92030d6a02fe363cceb41ffa To restore the standard build without `keycard-debug` afterwards: ```bash -cargo install --path wallet --force +cargo install --path lez/wallet --force ``` ### Pinata (testnet) @@ -496,7 +499,7 @@ Transaction data is ... ## Testing -Tests for Keycard commands are in `keycard_wallet/tests/`. +Tests for Keycard commands are in `lez/keycard_wallet/tests/`. | Test file | Description | |---|---| @@ -508,15 +511,15 @@ Tests for Keycard commands are in `keycard_wallet/tests/`. Run from the repo root with a Keycard connected: ```bash -bash keycard_wallet/tests/keycard_tests.sh -bash keycard_wallet/tests/keycard_tests_2.sh -bash keycard_wallet/tests/keycard_test_3.sh -bash keycard_wallet/tests/keycard_power_recovery_tests.sh +bash lez/keycard_wallet/tests/keycard_tests.sh +bash lez/keycard_wallet/tests/keycard_tests_2.sh +bash lez/keycard_wallet/tests/keycard_test_3.sh +bash lez/keycard_wallet/tests/keycard_power_recovery_tests.sh ``` ## SigningGroup -`SigningGroup` (`wallet/src/signing.rs`) partitions a transaction's signers into two buckets — local accounts and Keycard accounts. This ensures that Python GIL is only used at most once per transaction, regardless of how many Keycard accounts are involved. +`SigningGroup` (`lez/wallet/src/signing.rs`) partitions a transaction's signers into two buckets — local accounts and Keycard accounts. This ensures that Python GIL is only used at most once per transaction, regardless of how many Keycard accounts are involved. Local signers are resolved and signed in pure Rust. Keycard signers store only their BIP32 key path; all of them are signed inside a single Python session (`connect` / `close_session`) when `sign_all` is called. The command calls `needs_pin` to decide whether to prompt for a PIN before signing. diff --git a/lez/keycard_wallet/src/python_path.rs b/lez/keycard_wallet/src/python_path.rs index 5261d7b7..df25db2a 100644 --- a/lez/keycard_wallet/src/python_path.rs +++ b/lez/keycard_wallet/src/python_path.rs @@ -12,8 +12,9 @@ pub fn add_python_path(py: Python<'_>) -> PyResult<()> { .unwrap_or_else(|| current_dir.clone()); let mut paths_to_add: Vec = vec![ - python_base.join("keycard_wallet").join("python"), + python_base.join("lez").join("keycard_wallet").join("python"), python_base + .join("lez") .join("keycard_wallet") .join("python") .join("keycard-py"), diff --git a/lez/keycard_wallet/tests/keycard_test_3.sh b/lez/keycard_wallet/tests/keycard_test_3.sh index 5be1a3dd..d80e2aca 100755 --- a/lez/keycard_wallet/tests/keycard_test_3.sh +++ b/lez/keycard_wallet/tests/keycard_test_3.sh @@ -7,7 +7,7 @@ source venv/bin/activate -cargo install --path wallet --force --features keycard-debug +cargo install --path lez/wallet --force --features keycard-debug export KEYCARD_PIN=111111 diff --git a/lez/keycard_wallet/tests/keycard_tests.sh b/lez/keycard_wallet/tests/keycard_tests.sh index 2344f101..dfa30461 100755 --- a/lez/keycard_wallet/tests/keycard_tests.sh +++ b/lez/keycard_wallet/tests/keycard_tests.sh @@ -87,10 +87,16 @@ wallet account get --account-id "Public/7wHg9sbJwc6h3NP1S9bekfAzB8CHifEcxKswCKUt echo "" echo "=== Test: Shielded auth-transfer to owned private account ===" +SHIELDED_RECV=$(wallet account new private | grep -o 'Private/[^[:space:]]*' | head -1) +echo "Private recipient: $SHIELDED_RECV" +SHIELDED_KEYS=$(wallet account show-keys --account-id "$SHIELDED_RECV") +SHIELDED_NPK=$(echo "$SHIELDED_KEYS" | head -1) +SHIELDED_VPK=$(echo "$SHIELDED_KEYS" | tail -1) + wallet auth-transfer send --amount 2 \ --from "m/44'/60'/0'/0/0" \ - --to-npk "55204e2934045b044f06d8222b454d46b54788f33c7dec4f6733d441703bb0e6" \ - --to-vpk "02a8626b0c0ad9383c5678dad48c3969b4174fb377cdb03a6259648032c774cec8" + --to-npk "$SHIELDED_NPK" \ + --to-vpk "$SHIELDED_VPK" echo "Shielded auth-transfer sent" sleep 15 diff --git a/lez/keycard_wallet/tests/keycard_tests_2.sh b/lez/keycard_wallet/tests/keycard_tests_2.sh index 9a6450f4..cbff19fe 100755 --- a/lez/keycard_wallet/tests/keycard_tests_2.sh +++ b/lez/keycard_wallet/tests/keycard_tests_2.sh @@ -258,7 +258,7 @@ sleep 15 echo "Keycard path 2 (LEZ definition) state (total supply should have increased):" wallet account get --account-id "m/44'/60'/0'/0/2" -echo "Keycard path 6 (LEZ holding) state (balance should be 20500):" +echo "Keycard path 6 (LEZ holding) state (balance should be 20800):" wallet account get --account-id "m/44'/60'/0'/0/6" # ============================================================================= @@ -276,7 +276,7 @@ sleep 15 echo "Keycard path 2 (LEZ definition) state (total supply should reflect burn):" wallet account get --account-id "m/44'/60'/0'/0/2" -echo "Keycard path 6 (LEZ holding) state (balance should be 20000):" +echo "Keycard path 6 (LEZ holding) state (balance should be 20300):" wallet account get --account-id "m/44'/60'/0'/0/6" # ============================================================================= diff --git a/lez/wallet/src/account_manager.rs b/lez/wallet/src/account_manager.rs index 46e9bcaa..ffff57c6 100644 --- a/lez/wallet/src/account_manager.rs +++ b/lez/wallet/src/account_manager.rs @@ -72,7 +72,7 @@ impl AccountIdentity { /// Returns the `AccountId` for public variants. Used by facades that need the raw ID /// for derived-address computation alongside the identity. #[must_use] - pub const fn public_account_id(&self) -> Option { + pub const fn public_account_id(&self) -> Option { match self { Self::Public(id) | Self::PublicNoSign(id) => Some(*id), Self::PublicKeycard { account_id, .. } => Some(*account_id), diff --git a/lez/wallet/src/cli/mod.rs b/lez/wallet/src/cli/mod.rs index c7a70ecd..57c40b95 100644 --- a/lez/wallet/src/cli/mod.rs +++ b/lez/wallet/src/cli/mod.rs @@ -157,7 +157,7 @@ impl CliAccountMention { } #[must_use] - pub fn into_public_identity(self, account_id: nssa::AccountId) -> crate::AccountIdentity { + pub fn into_public_identity(self, account_id: lee::AccountId) -> crate::AccountIdentity { match self { Self::KeyPath(key_path) => crate::AccountIdentity::PublicKeycard { account_id, diff --git a/lez/wallet/src/program_facades/native_token_transfer/public.rs b/lez/wallet/src/program_facades/native_token_transfer/public.rs index f745557a..47cbf2c0 100644 --- a/lez/wallet/src/program_facades/native_token_transfer/public.rs +++ b/lez/wallet/src/program_facades/native_token_transfer/public.rs @@ -1,12 +1,6 @@ use authenticated_transfer_core::Instruction as AuthTransferInstruction; -use common::{HashType, transaction::LeeTransaction}; -use lee::{ - AccountId, PublicTransaction, - program::Program, - public_transaction::{Message, WitnessSet}, -}; -use pyo3::exceptions::PyRuntimeError; -use sequencer_service_rpc::RpcClient as _; +use common::HashType; +use lee::program::Program; use super::NativeTokenTransfer; use crate::{ @@ -31,41 +25,6 @@ impl NativeTokenTransfer<'_> { tx_pre_check, ) .await - .map_err(ExecutionFailureKind::SequencerError)?; - - let message = Message::try_new( - program_id, - vec![from, to], - nonces, - AuthTransferInstruction::Transfer { - amount: balance_to_move, - }, - ) - .map_err(ExecutionFailureKind::TransactionBuildError)?; - - let pin = if groups.needs_pin() { - read_pin() - .map_err(|e| { - ExecutionFailureKind::KeycardError(pyo3::PyErr::new::( - e.to_string(), - )) - })? - .as_str() - .to_owned() - } else { - String::new() - }; - - let sigs = groups.sign_all(&message.hash(), &pin).map_err(|e| { - ExecutionFailureKind::KeycardError(pyo3::PyErr::new::(e.to_string())) - })?; - - let tx = PublicTransaction::new(message, WitnessSet::from_raw_parts(sigs)); - Ok(self - .0 - .sequencer_client - .send_transaction(LeeTransaction::Public(tx)) - .await?) } pub async fn register_account( @@ -78,49 +37,5 @@ impl NativeTokenTransfer<'_> { self.0 .send_pub_tx(vec![account], instruction_data, &program.into()) .await - .map_err(ExecutionFailureKind::SequencerError)?; - - let account_ids = vec![from]; - let program_id = Program::authenticated_transfer_program().id(); - let message = Message::try_new( - program_id, - account_ids, - nonces, - AuthTransferInstruction::Initialize, - ) - .map_err(ExecutionFailureKind::TransactionBuildError)?; - - let mut groups = SigningGroups::new(); - groups - .add_sender(account_mention, from, self.0) - .map_err(|e| { - ExecutionFailureKind::KeycardError(pyo3::PyErr::new::( - e.to_string(), - )) - })?; - - let pin = if groups.needs_pin() { - read_pin() - .map_err(|e| { - ExecutionFailureKind::KeycardError(pyo3::PyErr::new::( - e.to_string(), - )) - })? - .as_str() - .to_owned() - } else { - String::new() - }; - - let sigs = groups.sign_all(&message.hash(), &pin).map_err(|e| { - ExecutionFailureKind::KeycardError(pyo3::PyErr::new::(e.to_string())) - })?; - - let tx = PublicTransaction::new(message, WitnessSet::from_raw_parts(sigs)); - Ok(self - .0 - .sequencer_client - .send_transaction(LeeTransaction::Public(tx)) - .await?) } } diff --git a/lez/wallet/src/signing.rs b/lez/wallet/src/signing.rs index 299a33b7..505dedd9 100644 --- a/lez/wallet/src/signing.rs +++ b/lez/wallet/src/signing.rs @@ -1,5 +1,4 @@ use keycard_wallet::{KeycardWallet, python_path}; -use lee::{AccountId, PrivateKey, PublicKey, Signature}; use pyo3::Python; /// Lazily opens and reuses a single Keycard session for all keycard signers in one transaction.