+
+pub struct TestWalletSource {
+ secret_key: SecretKey,
+ utxos: RefCell<Vec<Utxo>>,
+ secp: Secp256k1<bitcoin::secp256k1::All>,
+}
+
+impl TestWalletSource {
+ pub fn new(secret_key: SecretKey) -> Self {
+ Self {
+ secret_key,
+ utxos: RefCell::new(Vec::new()),
+ secp: Secp256k1::new(),
+ }
+ }
+
+ pub fn add_utxo(&self, outpoint: bitcoin::OutPoint, value: u64) -> TxOut {
+ let public_key = bitcoin::PublicKey::new(self.secret_key.public_key(&self.secp));
+ let utxo = Utxo::new_p2pkh(outpoint, value, &public_key.pubkey_hash());
+ self.utxos.borrow_mut().push(utxo.clone());
+ utxo.output
+ }
+
+ pub fn add_custom_utxo(&self, utxo: Utxo) -> TxOut {
+ let output = utxo.output.clone();
+ self.utxos.borrow_mut().push(utxo);
+ output
+ }
+
+ pub fn remove_utxo(&self, outpoint: bitcoin::OutPoint) {
+ self.utxos.borrow_mut().retain(|utxo| utxo.outpoint != outpoint);
+ }
+}
+
+impl WalletSource for TestWalletSource {
+ fn list_confirmed_utxos(&self) -> Result<Vec<Utxo>, ()> {
+ Ok(self.utxos.borrow().clone())
+ }
+
+ fn get_change_script(&self) -> Result<Script, ()> {
+ let public_key = bitcoin::PublicKey::new(self.secret_key.public_key(&self.secp));
+ Ok(Script::new_p2pkh(&public_key.pubkey_hash()))
+ }
+
+ fn sign_tx(&self, tx: &mut Transaction) -> Result<(), ()> {
+ let utxos = self.utxos.borrow();
+ for i in 0..tx.input.len() {
+ if let Some(utxo) = utxos.iter().find(|utxo| utxo.outpoint == tx.input[i].previous_output) {
+ let sighash = SighashCache::new(&*tx)
+ .legacy_signature_hash(i, &utxo.output.script_pubkey, EcdsaSighashType::All as u32)
+ .map_err(|_| ())?;
+ let sig = self.secp.sign_ecdsa(&sighash.as_hash().into(), &self.secret_key);
+ let bitcoin_sig = bitcoin::EcdsaSig { sig, hash_ty: EcdsaSighashType::All }.to_vec();
+ tx.input[i].script_sig = Builder::new()
+ .push_slice(&bitcoin_sig)
+ .push_slice(&self.secret_key.public_key(&self.secp).serialize())
+ .into_script();
+ }
+ }
+ Ok(())
+ }
+}