pub mod box_selector;
pub mod derivation_path;
pub mod ext_pub_key;
pub mod ext_secret_key;
pub mod miner_fee;
pub mod mnemonic;
#[cfg(feature = "mnemonic_gen")]
pub mod mnemonic_generator;
pub mod multi_sig;
pub mod secret_key;
pub mod signing;
pub mod tx_builder;
pub mod tx_context;
use ergotree_interpreter::sigma_protocol::private_input::PrivateInput;
use ergotree_interpreter::sigma_protocol::prover::Prover;
use ergotree_interpreter::sigma_protocol::prover::ProverError;
use ergotree_interpreter::sigma_protocol::prover::TestProver;
use secret_key::SecretKey;
use signing::{sign_transaction, TxSigningError};
use thiserror::Error;
use crate::chain::ergo_state_context::ErgoStateContext;
use crate::chain::transaction::reduced::ReducedTransaction;
use crate::chain::transaction::unsigned::UnsignedTransaction;
use crate::chain::transaction::Input;
use crate::chain::transaction::Transaction;
use crate::ergotree_ir::sigma_protocol::sigma_boolean::SigmaBoolean;
use crate::wallet::mnemonic::Mnemonic;
use crate::wallet::multi_sig::{
generate_commitments, generate_commitments_for, TransactionHintsBag,
};
use self::ext_secret_key::ExtSecretKey;
use self::ext_secret_key::ExtSecretKeyError;
use self::signing::sign_message;
use self::signing::sign_reduced_transaction;
use self::signing::sign_tx_input;
use self::signing::TransactionContext;
pub struct Wallet {
prover: Box<dyn Prover>,
}
#[allow(missing_docs)]
#[derive(Error, Debug)]
pub enum WalletError {
#[error("Transaction signing error: {0}")]
TxSigningError(#[from] TxSigningError),
#[error("Prover error: {0}")]
ProverError(#[from] ProverError),
#[error("ExtSecretKeyError: {0}")]
ExtSecretKeyError(#[from] ExtSecretKeyError),
#[error("error parsing SecretKey from ExtSecretKey.bytes")]
SecretKeyParsingError,
}
impl Wallet {
pub fn from_mnemonic(
mnemonic_phrase: &str,
mnemonic_pass: &str,
) -> Result<Wallet, WalletError> {
let seed = Mnemonic::to_seed(mnemonic_phrase, mnemonic_pass);
let ext_sk = ExtSecretKey::derive_master(seed)?;
Ok(Wallet::from_secrets(vec![ext_sk.secret_key()]))
}
pub fn from_secrets(secrets: Vec<SecretKey>) -> Wallet {
let prover = TestProver {
secrets: secrets.into_iter().map(PrivateInput::from).collect(),
};
Wallet {
prover: Box::new(prover),
}
}
pub fn add_secret(&mut self, secret: SecretKey) {
self.prover.append_secret(secret.into())
}
pub fn sign_transaction(
&self,
tx_context: TransactionContext<UnsignedTransaction>,
state_context: &ErgoStateContext,
tx_hints: Option<&TransactionHintsBag>,
) -> Result<Transaction, WalletError> {
sign_transaction(self.prover.as_ref(), tx_context, state_context, tx_hints)
.map_err(WalletError::from)
}
pub fn sign_reduced_transaction(
&self,
reduced_tx: ReducedTransaction,
tx_hints: Option<&TransactionHintsBag>,
) -> Result<Transaction, WalletError> {
sign_reduced_transaction(self.prover.as_ref(), reduced_tx, tx_hints)
.map_err(WalletError::from)
}
pub fn generate_commitments(
&self,
tx_context: TransactionContext<UnsignedTransaction>,
state_context: &ErgoStateContext,
) -> Result<TransactionHintsBag, TxSigningError> {
let public_keys: Vec<SigmaBoolean> = self
.prover
.secrets()
.iter()
.map(|secret| secret.public_image())
.collect();
generate_commitments(tx_context, state_context, public_keys.as_slice())
}
pub fn generate_commitments_for_reduced_transaction(
&self,
reduced_tx: ReducedTransaction,
) -> Result<TransactionHintsBag, TxSigningError> {
let mut tx_hints = TransactionHintsBag::empty();
let public_keys: Vec<SigmaBoolean> = self
.prover
.secrets()
.iter()
.map(|secret| secret.public_image())
.collect();
for (index, input) in reduced_tx.reduced_inputs().iter().enumerate() {
let sigma_prop = input.clone().sigma_prop;
let hints = generate_commitments_for(&sigma_prop, &public_keys);
tx_hints.add_hints_for_input(index, hints);
}
Ok(tx_hints)
}
pub fn sign_message(
&self,
sigma_tree: SigmaBoolean,
msg: &[u8],
) -> Result<Vec<u8>, WalletError> {
sign_message(self.prover.as_ref(), sigma_tree, msg).map_err(WalletError::from)
}
pub fn sign_tx_input(
&self,
input_idx: usize,
tx_context: TransactionContext<UnsignedTransaction>,
state_context: &ErgoStateContext,
tx_hints: Option<&TransactionHintsBag>,
) -> Result<Input, WalletError> {
let tx = tx_context.spending_tx.clone();
let message_to_sign = tx.bytes_to_sign().map_err(TxSigningError::from)?;
Ok(sign_tx_input(
self.prover.as_ref(),
&tx_context,
state_context,
tx_hints,
input_idx,
message_to_sign.as_slice(),
)?)
}
}