compile error fixed

This commit is contained in:
jonesmarvin8 2026-05-15 09:07:35 -04:00
parent d2b6597119
commit dd4ee70797
9 changed files with 151 additions and 95 deletions

View File

@ -64,14 +64,13 @@ unset KEYCARD_PIN
### Keycard ### Keycard
| Command | Description | | Command | Description |
|-----------------------------------|--------------------------------------------------------------------------| |-----------------------------|------------------------------------------------------------|
| `wallet keycard available` | Checks whether a Keycard reader and card are accessible | | `wallet keycard available` | Checks whether a Keycard reader and card are accessible |
| `wallet keycard init` | Initializes a blank Keycard with a PIN and a generated PUK | | `wallet keycard init` | Initializes a blank Keycard with a PIN and a generated PUK |
| `wallet keycard connect` | Establishes and saves a pairing with the Keycard | | `wallet keycard connect` | Establishes and saves a pairing with the Keycard |
| `wallet keycard disconnect` | Unpairs the Keycard and clears the saved pairing | | `wallet keycard disconnect` | Unpairs the Keycard and clears the saved pairing |
| `wallet keycard load` | Loads a mnemonic phrase onto the Keycard | | `wallet keycard load` | Loads a mnemonic phrase onto the Keycard |
| `wallet keycard get-private-keys` | Retrieves private account keys (nsk, vsk) for a given BIP32 path |
1. Check keycard availability 1. Check keycard availability
```bash ```bash
@ -114,17 +113,7 @@ Keycard PIN:
✅ Mnemonic phrase loaded successfully. ✅ Mnemonic phrase loaded successfully.
``` ```
5. Get private keys for a path 5. Disconnect (unpair and clear saved pairing)
```bash
wallet keycard get-private-keys --key-path "m/44'/60'/0'/0/0"
# Output:
Keycard PIN:
nsk: 55e505bf925e536c843a12ebc08c41ca5f4761eeeb7fa33725f0b44e6f1ac2e4
vsk: 30f798893977a7b7263d1f77abf58e11e014428c92030d6a02fe363cceb41ffa
```
6. Disconnect (unpair and clear saved pairing)
```bash ```bash
wallet keycard disconnect wallet keycard disconnect
@ -172,7 +161,7 @@ Transaction hash is 2c8a4f1e903d5b76e80214c5b82e1d46a105e28930ad71bcce48f2d07b49
| `wallet auth-transfer init` | Registers an account with the auth-transfer program | | `wallet auth-transfer init` | Registers an account with the auth-transfer program |
| `wallet auth-transfer send` | Sends native tokens between accounts | | `wallet auth-transfer send` | Sends native tokens between accounts |
`--account` (for `init`) and `--from`/`--to` (for `send`) each accept any of: `--account-id` (for `init`) and `--from`/`--to` (for `send`) each accept any of:
- A BIP32 key path — uses Keycard (e.g. `m/44'/60'/0'/0/0`) - A BIP32 key path — uses Keycard (e.g. `m/44'/60'/0'/0/0`)
- An account ID with privacy prefix (e.g. `Public/9bKm...`) - An account ID with privacy prefix (e.g. `Public/9bKm...`)
- An account label (e.g. `my-account`) - An account label (e.g. `my-account`)
@ -181,7 +170,7 @@ For `send`, foreign recipient accounts (not in the local wallet and not a Keycar
1. Initialize a Keycard public account 1. Initialize a Keycard public account
```bash ```bash
wallet auth-transfer init --account "m/44'/60'/0'/0/0" wallet auth-transfer init --account-id "m/44'/60'/0'/0/0"
# Output: # Output:
Keycard PIN: Keycard PIN:

View File

@ -16,8 +16,8 @@ export KEYCARD_MNEMONIC="fashion degree mountain wool question damp current pond
wallet keycard load wallet keycard load
unset KEYCARD_MNEMONIC unset KEYCARD_MNEMONIC
echo "Test: wallet auth-transfer init --account \"m/44'/60'/0'/0/0\"" echo "Test: wallet auth-transfer init --account-id \"m/44'/60'/0'/0/0\""
wallet auth-transfer init --account "m/44'/60'/0'/0/0" wallet auth-transfer init --account-id "m/44'/60'/0'/0/0"
echo "Test: wallet account get --account-id \"m/44'/60'/0'/0/0\"" echo "Test: wallet account get --account-id \"m/44'/60'/0'/0/0\""
wallet account get --account-id "m/44'/60'/0'/0/0" wallet account get --account-id "m/44'/60'/0'/0/0"
@ -29,7 +29,7 @@ echo "Test: wallet account get --account-id \"m/44'/60'/0'/0/0\""
wallet account get --account-id "m/44'/60'/0'/0/0" wallet account get --account-id "m/44'/60'/0'/0/0"
echo "Test: wallet auth-transfer init and send between two keycard accounts" echo "Test: wallet auth-transfer init and send between two keycard accounts"
wallet auth-transfer init --account "m/44'/60'/0'/0/1" wallet auth-transfer init --account-id "m/44'/60'/0'/0/1"
wallet auth-transfer send --amount 40 --from "m/44'/60'/0'/0/0" --to "m/44'/60'/0'/0/1" wallet auth-transfer send --amount 40 --from "m/44'/60'/0'/0/0" --to "m/44'/60'/0'/0/1"
echo "Test: wallet account get --account-id \"m/44'/60'/0'/0/0\"" echo "Test: wallet account get --account-id \"m/44'/60'/0'/0/0\""
@ -38,9 +38,44 @@ wallet account get --account-id "m/44'/60'/0'/0/0"
echo "Test: wallet account get --account-id \"m/44'/60'/0'/0/1\"" echo "Test: wallet account get --account-id \"m/44'/60'/0'/0/1\""
wallet account get --account-id "m/44'/60'/0'/0/1" wallet account get --account-id "m/44'/60'/0'/0/1"
# Send from keycard account to a local wallet account
echo "Test: create local wallet account"
LOCAL_ACCOUNT_ID=$(wallet account new public 2>&1 | grep -oP '(?<=Public/)\S+')
echo "Created local account: Public/${LOCAL_ACCOUNT_ID}"
echo "Test: wallet auth-transfer init local account"
wallet auth-transfer init --account-id "Public/${LOCAL_ACCOUNT_ID}"
echo "Test: wallet auth-transfer send from keycard to local account"
wallet auth-transfer send --amount 10 --from "m/44'/60'/0'/0/0" --to "Public/${LOCAL_ACCOUNT_ID}"
echo "Test: wallet account get --account-id \"m/44'/60'/0'/0/0\""
wallet account get --account-id "m/44'/60'/0'/0/0"
echo "Test: wallet account get --account-id \"Public/${LOCAL_ACCOUNT_ID}\""
wallet account get --account-id "Public/${LOCAL_ACCOUNT_ID}"
# Create a local wallet account, fund it, and send to keycard account (co-signed: local key + keycard)
echo "Test: wallet auth-transfer send from local account to keycard account"
wallet auth-transfer send --amount 10 --from "Public/${LOCAL_ACCOUNT_ID}" --to "m/44'/60'/0'/0/1"
echo "Test: wallet account get --account-id \"Public/${LOCAL_ACCOUNT_ID}\""
wallet account get --account-id "Public/${LOCAL_ACCOUNT_ID}"
echo "Test: wallet account get --account-id \"m/44'/60'/0'/0/1\""
wallet account get --account-id "m/44'/60'/0'/0/1"
# Send from keycard account to a local wallet account (foreign recipient — no signature needed) # Send from keycard account to a local wallet account (foreign recipient — no signature needed)
echo "Test: wallet account get --account-id \"m/44'/60'/0'/0/0\""
wallet account get --account-id "Public/7wHg9sbJwc6h3NP1S9bekfAzB8CHifEcxKswCKUt3YQo"
echo "Test: wallet auth-transfer send from keycard to local account" echo "Test: wallet auth-transfer send from keycard to local account"
wallet auth-transfer send --amount 10 --from "m/44'/60'/0'/0/0" --to "Public/7wHg9sbJwc6h3NP1S9bekfAzB8CHifEcxKswCKUt3YQo" wallet auth-transfer send --amount 10 --from "m/44'/60'/0'/0/0" --to "Public/7wHg9sbJwc6h3NP1S9bekfAzB8CHifEcxKswCKUt3YQo"
echo "Test: wallet account get --account-id \"m/44'/60'/0'/0/0\"" echo "Test: wallet account get --account-id \"m/44'/60'/0'/0/0\""
wallet account get --account-id "m/44'/60'/0'/0/0" wallet account get --account-id "m/44'/60'/0'/0/0"
echo "Test: wallet account get --account-id \"m/44'/60'/0'/0/0\""
wallet account get --account-id "Public/7wHg9sbJwc6h3NP1S9bekfAzB8CHifEcxKswCKUt3YQo"

View File

@ -67,7 +67,10 @@ impl KeycardWallet {
) -> PyResult<bool> { ) -> PyResult<bool> {
self.instance self.instance
.bind(py) .bind(py)
.call_method1("setup_communication_with_pairing", (pin, index, key.to_vec()))? .call_method1(
"setup_communication_with_pairing",
(pin, index, key.to_vec()),
)?
.extract() .extract()
} }
@ -197,7 +200,11 @@ impl KeycardWallet {
fn pairing_file_path() -> Option<PathBuf> { fn pairing_file_path() -> Option<PathBuf> {
let home = std::env::var("NSSA_WALLET_HOME_DIR") let home = std::env::var("NSSA_WALLET_HOME_DIR")
.map(PathBuf::from) .map(PathBuf::from)
.or_else(|_| std::env::home_dir().map(|h| h.join(".nssa").join("wallet")).ok_or(())) .or_else(|_| {
std::env::home_dir()
.map(|h| h.join(".nssa").join("wallet"))
.ok_or(())
})
.ok()?; .ok()?;
Some(home.join("keycard_pairing.json")) Some(home.join("keycard_pairing.json"))
} }

View File

@ -4,8 +4,7 @@ use std::{ffi::CString, ptr};
use nssa::AccountId; use nssa::AccountId;
use wallet::{ use wallet::{
account::AccountIdWithPrivacy, account::AccountIdWithPrivacy, cli::CliAccountMention,
cli::CliAccountMention,
program_facades::native_token_transfer::NativeTokenTransfer, program_facades::native_token_transfer::NativeTokenTransfer,
}; };
@ -79,7 +78,13 @@ pub unsafe extern "C" fn wallet_ffi_transfer_public(
let from_mention = CliAccountMention::Id(AccountIdWithPrivacy::Public(from_id)); let from_mention = CliAccountMention::Id(AccountIdWithPrivacy::Public(from_id));
let to_mention = CliAccountMention::Id(AccountIdWithPrivacy::Public(to_id)); let to_mention = CliAccountMention::Id(AccountIdWithPrivacy::Public(to_id));
match block_on(transfer.send_public_transfer(from_id, to_id, amount, &from_mention, &to_mention)) { match block_on(transfer.send_public_transfer(
from_id,
to_id,
amount,
&from_mention,
&to_mention,
)) {
Ok(tx_hash) => { Ok(tx_hash) => {
let tx_hash = CString::new(tx_hash.to_string()) let tx_hash = CString::new(tx_hash.to_string())
.map_or(ptr::null_mut(), std::ffi::CString::into_raw); .map_or(ptr::null_mut(), std::ffi::CString::into_raw);

View File

@ -52,7 +52,8 @@ impl WalletSubcommand for KeycardSubcommand {
let wallet = KeycardWallet::new(py) let wallet = KeycardWallet::new(py)
.expect("`wallet::keycard::connect`: invalid keycard wallet provided"); .expect("`wallet::keycard::connect`: invalid keycard wallet provided");
wallet.connect(py, &pin) wallet
.connect(py, &pin)
.expect("`wallet::keycard::connect`: failed to connect to keycard"); .expect("`wallet::keycard::connect`: failed to connect to keycard");
println!("\u{2705} Keycard paired and ready."); println!("\u{2705} Keycard paired and ready.");
@ -70,10 +71,12 @@ impl WalletSubcommand for KeycardSubcommand {
let wallet = KeycardWallet::new(py) let wallet = KeycardWallet::new(py)
.expect("`wallet::keycard::disconnect`: invalid keycard wallet provided"); .expect("`wallet::keycard::disconnect`: invalid keycard wallet provided");
wallet.connect(py, &pin) wallet
.connect(py, &pin)
.expect("`wallet::keycard::disconnect`: failed to open session"); .expect("`wallet::keycard::disconnect`: failed to open session");
wallet.disconnect(py) wallet
.disconnect(py)
.expect("`wallet::keycard::disconnect`: failed to unpair keycard"); .expect("`wallet::keycard::disconnect`: failed to unpair keycard");
clear_pairing(); clear_pairing();
@ -91,7 +94,8 @@ impl WalletSubcommand for KeycardSubcommand {
let wallet = KeycardWallet::new(py) let wallet = KeycardWallet::new(py)
.expect("`wallet::keycard::init`: invalid keycard wallet provided"); .expect("`wallet::keycard::init`: invalid keycard wallet provided");
let initialized = wallet.initialize(py, &pin) let initialized = wallet
.initialize(py, &pin)
.expect("`wallet::keycard::init`: failed to initialize keycard"); .expect("`wallet::keycard::init`: failed to initialize keycard");
if initialized { if initialized {
@ -112,7 +116,8 @@ impl WalletSubcommand for KeycardSubcommand {
let wallet = KeycardWallet::new(py) let wallet = KeycardWallet::new(py)
.expect("`wallet::keycard::load`: invalid keycard wallet provided"); .expect("`wallet::keycard::load`: invalid keycard wallet provided");
wallet.connect(py, &pin) wallet
.connect(py, &pin)
.expect("`wallet::keycard::load`: failed to connect to keycard"); .expect("`wallet::keycard::load`: failed to connect to keycard");
println!("\u{2705} Keycard is now connected to wallet."); println!("\u{2705} Keycard is now connected to wallet.");

View File

@ -9,6 +9,7 @@ use futures::TryFutureExt as _;
use nssa::{ProgramDeploymentTransaction, program::Program}; use nssa::{ProgramDeploymentTransaction, program::Program};
use sequencer_service_rpc::RpcClient as _; use sequencer_service_rpc::RpcClient as _;
pub use crate::helperfunctions::{read_mnemonic, read_pin};
use crate::{ use crate::{
WalletCore, WalletCore,
account::{AccountIdWithPrivacy, Label}, account::{AccountIdWithPrivacy, Label},
@ -27,8 +28,6 @@ use crate::{
storage::Storage, storage::Storage,
}; };
pub use crate::helperfunctions::{read_mnemonic, read_pin};
pub mod account; pub mod account;
pub mod chain; pub mod chain;
pub mod config; pub mod config;
@ -138,8 +137,9 @@ impl CliAccountMention {
.ok_or_else(|| anyhow::anyhow!("No account found for label `{label}`")), .ok_or_else(|| anyhow::anyhow!("No account found for label `{label}`")),
Self::KeyPath(path) => { Self::KeyPath(path) => {
let pin = read_pin()?; let pin = read_pin()?;
let id_str = keycard_wallet::KeycardWallet::get_account_id_for_path_with_connect(&pin, path) let id_str =
.map_err(anyhow::Error::from)?; keycard_wallet::KeycardWallet::get_account_id_for_path_with_connect(&pin, path)
.map_err(anyhow::Error::from)?;
AccountIdWithPrivacy::from_str(&id_str) AccountIdWithPrivacy::from_str(&id_str)
.map_err(|e| anyhow::anyhow!("Invalid account id from keycard: {e}")) .map_err(|e| anyhow::anyhow!("Invalid account id from keycard: {e}"))
} }
@ -175,18 +175,25 @@ impl CliAccountMention {
/// Resolve to an [`AccountSigner`] for a recipient — returns `Foreign` when the account /// Resolve to an [`AccountSigner`] for a recipient — returns `Foreign` when the account
/// has no local key and no keycard path, meaning no signature or nonce is required. /// has no local key and no keycard path, meaning no signature or nonce is required.
pub fn to_recipient_signer(&self, wallet_core: &WalletCore) -> Result<crate::signing::AccountSigner> { pub fn to_recipient_signer(
&self,
wallet_core: &WalletCore,
) -> Result<crate::signing::AccountSigner> {
if let Self::KeyPath(path) = self { if let Self::KeyPath(path) = self {
return Ok(crate::signing::AccountSigner::Keycard(path.clone())); return Ok(crate::signing::AccountSigner::Keycard(path.clone()));
} }
let account = self.resolve(wallet_core.storage())?; let account = self.resolve(wallet_core.storage())?;
match account { match account {
AccountIdWithPrivacy::Public(id) => { AccountIdWithPrivacy::Public(id) => Ok(
Ok(match wallet_core.storage().key_chain().pub_account_signing_key(id) { match wallet_core
.storage()
.key_chain()
.pub_account_signing_key(id)
{
Some(_) => crate::signing::AccountSigner::Local(id), Some(_) => crate::signing::AccountSigner::Local(id),
None => crate::signing::AccountSigner::Foreign, None => crate::signing::AccountSigner::Foreign,
}) },
} ),
AccountIdWithPrivacy::Private(_) => { AccountIdWithPrivacy::Private(_) => {
anyhow::bail!("Private accounts not supported as recipients here") anyhow::bail!("Private accounts not supported as recipients here")
} }

View File

@ -58,9 +58,9 @@ impl WalletSubcommand for AuthTransferSubcommand {
Self::Init { account_id } => { Self::Init { account_id } => {
let resolved = account_id.resolve(wallet_core.storage())?; let resolved = account_id.resolve(wallet_core.storage())?;
match resolved { match resolved {
AccountIdWithPrivacy::Public(account_id) => { AccountIdWithPrivacy::Public(pub_account_id) => {
let tx_hash = NativeTokenTransfer(wallet_core) let tx_hash = NativeTokenTransfer(wallet_core)
.register_account(account_id, &account) .register_account(pub_account_id, &account_id)
.await?; .await?;
println!("Transaction hash is {tx_hash}"); println!("Transaction hash is {tx_hash}");
@ -124,7 +124,13 @@ impl WalletSubcommand for AuthTransferSubcommand {
} }
(Some(to), None, None) => match (from, to) { (Some(to), None, None) => match (from, to) {
(AccountIdWithPrivacy::Public(from), AccountIdWithPrivacy::Public(to)) => { (AccountIdWithPrivacy::Public(from), AccountIdWithPrivacy::Public(to)) => {
NativeTokenTransferProgramSubcommand::Public { from, to, amount } NativeTokenTransferProgramSubcommand::Public {
from,
to,
amount,
from_mention: from_account,
to_mention: to_account.expect("matched Some branch"),
}
} }
( (
AccountIdWithPrivacy::Private(from), AccountIdWithPrivacy::Private(from),
@ -481,7 +487,13 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommand {
Ok(SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash }) Ok(SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash })
} }
Self::Public { from, to, amount, from_mention, to_mention } => { Self::Public {
from,
to,
amount,
from_mention,
to_mention,
} => {
let tx_hash = NativeTokenTransfer(wallet_core) let tx_hash = NativeTokenTransfer(wallet_core)
.send_public_transfer(from, to, amount, &from_mention, &to_mention) .send_public_transfer(from, to, amount, &from_mention, &to_mention)
.await?; .await?;

View File

@ -10,9 +10,7 @@ use sequencer_service_rpc::RpcClient as _;
use super::NativeTokenTransfer; use super::NativeTokenTransfer;
use crate::{ use crate::{
ExecutionFailureKind, ExecutionFailureKind, cli::CliAccountMention, helperfunctions::read_pin,
cli::CliAccountMention,
helperfunctions::read_pin,
signing::KeycardSessionContext, signing::KeycardSessionContext,
}; };
@ -25,13 +23,12 @@ impl NativeTokenTransfer<'_> {
from_mention: &CliAccountMention, from_mention: &CliAccountMention,
to_mention: &CliAccountMention, to_mention: &CliAccountMention,
) -> Result<HashType, ExecutionFailureKind> { ) -> Result<HashType, ExecutionFailureKind> {
let from_signer = from_mention.to_signer(self.0).map_err(|e| {
let from_signer = from_mention ExecutionFailureKind::KeycardError(pyo3::PyErr::new::<PyRuntimeError, _>(e.to_string()))
.to_signer(self.0) })?;
.map_err(|e| ExecutionFailureKind::KeycardError(pyo3::PyErr::new::<PyRuntimeError, _>(e.to_string())))?; let to_signer = to_mention.to_recipient_signer(self.0).map_err(|e| {
let to_signer = to_mention ExecutionFailureKind::KeycardError(pyo3::PyErr::new::<PyRuntimeError, _>(e.to_string()))
.to_recipient_signer(self.0) })?;
.map_err(|e| ExecutionFailureKind::KeycardError(pyo3::PyErr::new::<PyRuntimeError, _>(e.to_string())))?;
let account_ids = vec![from, to]; let account_ids = vec![from, to];
let signing_ids: Vec<AccountId> = if to_signer.needs_signature() { let signing_ids: Vec<AccountId> = if to_signer.needs_signature() {
@ -51,13 +48,19 @@ impl NativeTokenTransfer<'_> {
program_id, program_id,
account_ids, account_ids,
nonces, nonces,
AuthTransferInstruction::Transfer { amount: balance_to_move }, AuthTransferInstruction::Transfer {
amount: balance_to_move,
},
) )
.map_err(ExecutionFailureKind::TransactionBuildError)?; .map_err(ExecutionFailureKind::TransactionBuildError)?;
let pin = if from_mention.is_keycard() || to_mention.is_keycard() { let pin = if from_mention.is_keycard() || to_mention.is_keycard() {
read_pin() read_pin()
.map_err(|e| ExecutionFailureKind::KeycardError(pyo3::PyErr::new::<PyRuntimeError, _>(e.to_string())))? .map_err(|e| {
ExecutionFailureKind::KeycardError(pyo3::PyErr::new::<PyRuntimeError, _>(
e.to_string(),
))
})?
.as_str() .as_str()
.to_owned() .to_owned()
} else { } else {
@ -93,34 +96,6 @@ impl NativeTokenTransfer<'_> {
.sequencer_client .sequencer_client
.send_transaction(NSSATransaction::Public(tx)) .send_transaction(NSSATransaction::Public(tx))
.await?) .await?)
} else {
println!(
"Receiver's account ({to}) private key not found in wallet. Proceeding with only sender's key."
);
}
let message = Message::try_new(
program_id,
account_ids,
nonces,
AuthTransferInstruction::Transfer {
amount: balance_to_move,
},
)
.unwrap();
let witness_set = WitnessSet::for_message(&message, &private_keys);
let tx = PublicTransaction::new(message, witness_set);
Ok(self
.0
.sequencer_client
.send_transaction(NSSATransaction::Public(tx))
.await?)
} else {
Err(ExecutionFailureKind::InsufficientFundsError)
}
} }
pub async fn register_account( pub async fn register_account(
@ -144,13 +119,17 @@ impl NativeTokenTransfer<'_> {
) )
.map_err(ExecutionFailureKind::TransactionBuildError)?; .map_err(ExecutionFailureKind::TransactionBuildError)?;
let signer = account_mention let signer = account_mention.to_signer(self.0).map_err(|e| {
.to_signer(self.0) ExecutionFailureKind::KeycardError(pyo3::PyErr::new::<PyRuntimeError, _>(e.to_string()))
.map_err(|e| ExecutionFailureKind::KeycardError(pyo3::PyErr::new::<PyRuntimeError, _>(e.to_string())))?; })?;
let pin = if account_mention.is_keycard() { let pin = if account_mention.is_keycard() {
read_pin() read_pin()
.map_err(|e| ExecutionFailureKind::KeycardError(pyo3::PyErr::new::<PyRuntimeError, _>(e.to_string())))? .map_err(|e| {
ExecutionFailureKind::KeycardError(pyo3::PyErr::new::<PyRuntimeError, _>(
e.to_string(),
))
})?
.as_str() .as_str()
.to_owned() .to_owned()
} else { } else {

View File

@ -34,8 +34,19 @@ impl AccountSigner {
) -> Option<Result<(Signature, PublicKey)>> { ) -> Option<Result<(Signature, PublicKey)>> {
match self { match self {
Self::Local(id) => { Self::Local(id) => {
let key = wallet_core.storage().key_chain().pub_account_signing_key(*id)?; let key = wallet_core
Some(Ok((Signature::new(key, hash), PublicKey::new_from_private_key(key)))) .storage()
.key_chain()
.pub_account_signing_key(*id);
Some(key.map_or_else(
|| Err(anyhow::anyhow!("signing key not found for account {id}")),
|key| {
Ok((
Signature::new(key, hash),
PublicKey::new_from_private_key(key),
))
},
))
} }
Self::Keycard(path) => Some( Self::Keycard(path) => Some(
ctx.get_or_connect(py) ctx.get_or_connect(py)
@ -55,10 +66,16 @@ pub struct KeycardSessionContext {
impl KeycardSessionContext { impl KeycardSessionContext {
pub fn new(pin: impl Into<String>) -> Self { pub fn new(pin: impl Into<String>) -> Self {
Self { pin: pin.into(), wallet: None } Self {
pin: pin.into(),
wallet: None,
}
} }
pub fn get_or_connect<'py>(&'py mut self, py: Python<'py>) -> pyo3::PyResult<&'py KeycardWallet> { pub fn get_or_connect<'py>(
&'py mut self,
py: Python<'py>,
) -> pyo3::PyResult<&'py KeycardWallet> {
if self.wallet.is_none() { if self.wallet.is_none() {
python_path::add_python_path(py)?; python_path::add_python_path(py)?;
let wallet = KeycardWallet::new(py)?; let wallet = KeycardWallet::new(py)?;