1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
//! # Signer Module
//!
//! This module provides transaction signing capabilities for Elements/Liquid transactions
//! using various signing backends. The primary implementation uses Blockstream's Liquid
//! Wallet Kit (LWK) for software-based signing with mnemonic phrases.
//!
//! ## ⚠️ SECURITY WARNING ⚠️
//!
//! **TESTNET/REGTEST ONLY**: This implementation is designed exclusively for testnet
//! and regtest environments. It stores mnemonic phrases in plain text JSON files
//! and should NEVER be used in production or mainnet environments.
//!
//! For production use cases, consider:
//! - Hardware wallets (Ledger, Trezor)
//! - Encrypted key storage solutions
//! - Remote signing services with proper security
//! - Hardware Security Modules (HSMs)
//!
//! ## JSON File Format
//!
//! The signer uses `mnemonic.local.json` for persistent storage with the following structure:
//!
//! ```json
//! {
//! "mnemonic": [
//! "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about",
//! "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo wrong",
//! "additional mnemonics as needed for test isolation..."
//! ]
//! }
//! ```
//!
//! ### File Structure Details:
//! - **Location**: `mnemonic.local.json` in the current working directory
//! - **Format**: JSON with a single `mnemonic` array field
//! - **Content**: Array of BIP39 mnemonic phrases (12, 15, 18, 21, or 24 words)
//! - **Indexing**: Zero-based array indexing for consistent test identification
//! - **Persistence**: Automatically created and updated when new mnemonics are generated
//!
//! ## Usage Examples
//!
//! ### Basic Signer Creation
//!
//! ```rust,no_run
//! use amp_rs::signer::{Signer, LwkSoftwareSigner, SignerError};
//!
//! #[tokio::main]
//! async fn main() -> Result<(), SignerError> {
//! // Create signer from existing mnemonic
//! let mnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about";
//! let signer = LwkSoftwareSigner::new(mnemonic)?;
//!
//! // Sign a transaction
//! let unsigned_tx = "020000000001..."; // Your unsigned transaction hex
//! let signed_tx = signer.sign_transaction(unsigned_tx).await?;
//! println!("Signed transaction: {}", signed_tx);
//!
//! Ok(())
//! }
//! ```
//!
//! ### Automatic Mnemonic Generation
//!
//! ```rust,no_run
//! use amp_rs::signer::{LwkSoftwareSigner, SignerError};
//!
//! #[tokio::main]
//! async fn main() -> Result<(), SignerError> {
//! // Generate new signer (loads first mnemonic from file or creates new)
//! let (mnemonic, signer) = LwkSoftwareSigner::generate_new()?;
//! println!("Using mnemonic: {}", mnemonic);
//!
//! // Signer is ready to use
//! assert!(signer.is_testnet());
//!
//! Ok(())
//! }
//! ```
//!
//! ### Indexed Mnemonic Access for Testing
//!
//! ```rust,no_run
//! use amp_rs::signer::{LwkSoftwareSigner, SignerError};
//!
//! #[tokio::main]
//! async fn main() -> Result<(), SignerError> {
//! // Get specific mnemonic by index (generates new ones if needed)
//! let (mnemonic_0, signer_0) = LwkSoftwareSigner::generate_new_indexed(0)?;
//! let (mnemonic_2, signer_2) = LwkSoftwareSigner::generate_new_indexed(2)?;
//!
//! // Each signer uses a different mnemonic for test isolation
//! assert_ne!(mnemonic_0, mnemonic_2);
//!
//! Ok(())
//! }
//! ```
//!
//! ### Error Handling
//!
//! ```rust,no_run
//! use amp_rs::signer::{Signer, LwkSoftwareSigner, SignerError};
//!
//! async fn sign_with_error_handling(unsigned_tx: &str) -> Result<String, SignerError> {
//! let (_, signer) = LwkSoftwareSigner::generate_new()?;
//!
//! match signer.sign_transaction(unsigned_tx).await {
//! Ok(signed_tx) => {
//! println!("Transaction signed successfully");
//! Ok(signed_tx)
//! },
//! Err(SignerError::HexParse(e)) => {
//! eprintln!("Invalid hex format: {}", e);
//! Err(SignerError::HexParse(e))
//! },
//! Err(SignerError::InvalidTransaction(msg)) => {
//! eprintln!("Invalid transaction: {}", msg);
//! Err(SignerError::InvalidTransaction(msg))
//! },
//! Err(SignerError::Lwk(msg)) => {
//! eprintln!("LWK signing failed: {}", msg);
//! Err(SignerError::Lwk(msg))
//! },
//! Err(e) => {
//! eprintln!("Unexpected error: {}", e);
//! Err(e)
//! }
//! }
//! }
//! ```
pub use SignerError;
pub use LwkSoftwareSigner;
use async_trait;
/// Trait for transaction signing implementations
///
/// This trait provides a unified interface for signing Elements/Liquid transactions
/// using various signing backends (software signers, hardware wallets, etc.).
///
/// # Usage
///
/// Implementations of this trait should handle the complete signing pipeline:
/// 1. Parse the unsigned transaction hex string
/// 2. Sign the transaction using the appropriate private key(s)
/// 3. Return the signed transaction as a hex string
///
/// # Thread Safety
///
/// All implementations must be thread-safe (Send + Sync) to support concurrent
/// signing operations in async environments.
///
/// # Example
///
/// ```rust,no_run
/// use amp_rs::signer::{Signer, LwkSoftwareSigner};
///
/// async fn sign_example() -> Result<(), Box<dyn std::error::Error>> {
/// let signer = LwkSoftwareSigner::new("abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about")?;
/// let unsigned_tx = "020000000001..."; // Unsigned transaction hex
/// let signed_tx = signer.sign_transaction(unsigned_tx).await?;
/// println!("Signed transaction: {}", signed_tx);
/// Ok(())
/// }
/// ```