Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(utxo): refactor utxo output script creation #1960

Merged
merged 34 commits into from
Feb 6, 2024
Merged
Show file tree
Hide file tree
Changes from 32 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
d5f055a
remove unused TransactionOutputs (which prevented parametrised addres…
dimxy Sep 5, 2023
19cab7a
add script_type to Address
dimxy Sep 5, 2023
ca5e9c2
fix format
dimxy Sep 5, 2023
753fb93
fix coin prefix in address tests
dimxy Sep 5, 2023
9cc277f
fix fmt
dimxy Sep 5, 2023
1793290
fix test results because of Address::from_str changed to from_legacya…
dimxy Sep 6, 2023
f953499
add NetworkAddressPrefixes type and replace use of u8 addr prefixes
dimxy Oct 9, 2023
6050621
remove controversial check in withdraw (no segwit case)
dimxy Oct 9, 2023
0b1842d
fix use for coin prefixes in test helpers
dimxy Oct 9, 2023
82a3b2d
add default val for LegacyAddress
dimxy Oct 9, 2023
6924cb0
remove commented code
dimxy Oct 9, 2023
3de99ae
remove unused invalid prefixes error
dimxy Oct 9, 2023
838911d
fix after rebase
dimxy Nov 2, 2023
69bd48b
fix convert_address fn for converting to legacy address
dimxy Nov 2, 2023
e5283c3
fix cargo fmt
dimxy Nov 2, 2023
123e3f8
Merge branch 'dev' into feature-add-script-type-to-address-bak
dimxy Jan 23, 2024
055e2f7
fix test_address_to_scripthash after merge
dimxy Jan 23, 2024
124d758
add comment for addr prefixes
dimxy Jan 23, 2024
845ed0d
change to unchecked ver of address_from_str
dimxy Jan 25, 2024
87c438d
refactor: add AddressBuilder to check creation params; simplify fn ou…
dimxy Jan 25, 2024
b10f38d
add drop_mutability in conf builder
dimxy Jan 25, 2024
a38ed54
fix addr_format for check_if_my_payment_sent fn (must not be segwit)
dimxy Jan 29, 2024
35367d4
rename address builder options to avoid confusion
dimxy Jan 29, 2024
f66529e
break script witness creation fn into p2wpkh and p2wsh to validate wi…
dimxy Jan 29, 2024
9206ca2
add swap events debug logging
dimxy Jan 29, 2024
9bb5f13
fix clippy fmt
dimxy Jan 29, 2024
acf7174
remove my debug in swaps
dimxy Jan 29, 2024
095a804
remove temp ignore for iris tests
dimxy Jan 30, 2024
64dbf87
refactor AddressBuilder according to builder pattern
dimxy Feb 1, 2024
354c970
fixed review notes: propagate output_script() error
dimxy Feb 2, 2024
4603855
remove extra map_err, add returned err logging
dimxy Feb 2, 2024
9260531
remove extra map_to_mm
dimxy Feb 2, 2024
3434e2b
refactor AddressPrefixes - remove extra const type
dimxy Feb 5, 2024
d7f6cdb
refactor: rename AddressPrefixes to singular
dimxy Feb 5, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions mm2src/coins/coin_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@ impl From<Web3RpcError> for ValidatePaymentError {
}
}

impl From<keys::Error> for ValidatePaymentError {
fn from(err: keys::Error) -> Self { Self::InternalError(err.to_string()) }
}

#[derive(Debug, Display)]
pub enum MyAddressError {
UnexpectedDerivationMethod(String),
Expand Down
16 changes: 13 additions & 3 deletions mm2src/coins/lightning/ln_events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ pub enum SignFundingTransactionError {
// Generates the raw funding transaction with one output equal to the channel value.
fn sign_funding_transaction(
uuid: Uuid,
output_script: &Script,
output_script_pubkey: &Script,
platform: Arc<Platform>,
) -> Result<Transaction, SignFundingTransactionError> {
let coin = &platform.coin;
Expand All @@ -207,7 +207,7 @@ fn sign_funding_transaction(
})?
.clone()
};
unsigned.outputs[0].script_pubkey = output_script.to_bytes().into();
unsigned.outputs[0].script_pubkey = output_script_pubkey.to_bytes().into();

let my_address = coin
.as_ref()
Expand Down Expand Up @@ -532,7 +532,17 @@ impl LightningEventHandler {
let keys_manager = self.keys_manager.clone();

let fut = async move {
let change_destination_script = Builder::build_p2witness(&my_address.hash).to_bytes().take().into();
let change_destination_script = match Builder::build_p2wpkh(my_address.hash()) {
Ok(script) => script.to_bytes().take().into(),
Err(err) => {
error!(
"Could not create witness script for change output {}: {}",
my_address.to_string(),
err.to_string()
);
return;
},
};
let feerate_sat_per_1000_weight = platform.get_est_sat_per_1000_weight(ConfirmationTarget::Normal);
let output_descriptors = outputs.iter().collect::<Vec<_>>();
let claiming_tx = match keys_manager.spend_spendable_outputs(
Expand Down
9 changes: 6 additions & 3 deletions mm2src/coins/lp_coins.rs
Original file line number Diff line number Diff line change
Expand Up @@ -657,6 +657,10 @@ impl TransactionErr {
}
}

impl From<keys::Error> for TransactionErr {
fn from(e: keys::Error) -> Self { TransactionErr::Plain(e.to_string()) }
}

#[derive(Debug, PartialEq)]
pub enum FoundSwapTxSpend {
Spent(TransactionEnum),
Expand Down Expand Up @@ -4258,7 +4262,7 @@ struct ConvertUtxoAddressReq {

pub async fn convert_utxo_address(ctx: MmArc, req: Json) -> Result<Response<Vec<u8>>, String> {
let req: ConvertUtxoAddressReq = try_s!(json::from_value(req));
let mut addr: utxo::Address = try_s!(req.address.parse());
let mut addr: utxo::LegacyAddress = try_s!(req.address.parse()); // Only legacy addresses supported as source
let coin = match lp_coinfind(&ctx, &req.to_coin).await {
Ok(Some(c)) => c,
_ => return ERR!("Coin {} is not activated", req.to_coin),
Expand All @@ -4267,8 +4271,7 @@ pub async fn convert_utxo_address(ctx: MmArc, req: Json) -> Result<Response<Vec<
MmCoinEnum::UtxoCoin(utxo) => utxo,
_ => return ERR!("Coin {} is not utxo", req.to_coin),
};
addr.prefix = coin.as_ref().conf.pub_addr_prefix;
addr.t_addr_prefix = coin.as_ref().conf.pub_t_addr_prefix;
addr.prefixes = coin.as_ref().conf.address_prefixes.p2pkh.clone();
addr.checksum_type = coin.as_ref().conf.checksum_type;

let response = try_s!(json::to_vec(&json!({
Expand Down
23 changes: 10 additions & 13 deletions mm2src/coins/qrc20.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ use futures::compat::Future01CompatExt;
use futures::{FutureExt, TryFutureExt};
use futures01::Future;
use keys::bytes::Bytes as ScriptBytes;
use keys::{Address as UtxoAddress, Address, KeyPair, Public};
use keys::{Address as UtxoAddress, KeyPair, Public};
use mm2_core::mm_ctx::MmArc;
use mm2_err_handle::prelude::*;
use mm2_number::{BigDecimal, MmNumber};
Expand Down Expand Up @@ -634,21 +634,21 @@ impl UtxoTxGenerationOps for Qrc20Coin {
impl GetUtxoListOps for Qrc20Coin {
async fn get_unspent_ordered_list(
&self,
address: &Address,
address: &UtxoAddress,
) -> UtxoRpcResult<(Vec<UnspentInfo>, RecentlySpentOutPointsGuard<'_>)> {
utxo_common::get_unspent_ordered_list(self, address).await
}

async fn get_all_unspent_ordered_list(
&self,
address: &Address,
address: &UtxoAddress,
) -> UtxoRpcResult<(Vec<UnspentInfo>, RecentlySpentOutPointsGuard<'_>)> {
utxo_common::get_all_unspent_ordered_list(self, address).await
}

async fn get_mature_unspent_ordered_list(
&self,
address: &Address,
address: &UtxoAddress,
) -> UtxoRpcResult<(MatureUnspentList, RecentlySpentOutPointsGuard<'_>)> {
utxo_common::get_mature_unspent_ordered_list(self, address).await
}
Expand All @@ -675,8 +675,8 @@ impl UtxoCommonOps for Qrc20Coin {
utxo_common::checked_address_from_str(self, address)
}

fn script_for_address(&self, address: &Address) -> MmResult<Script, UnsupportedAddr> {
utxo_common::get_script_for_address(self.as_ref(), address)
fn script_for_address(&self, address: &UtxoAddress) -> MmResult<Script, UnsupportedAddr> {
utxo_common::output_script_checked(self.as_ref(), address)
}

async fn get_current_mtp(&self) -> UtxoRpcResult<u32> {
Expand Down Expand Up @@ -748,12 +748,11 @@ impl UtxoCommonOps for Qrc20Coin {
utxo_common::addr_format_for_standard_scripts(self)
}

fn address_from_pubkey(&self, pubkey: &Public) -> Address {
fn address_from_pubkey(&self, pubkey: &Public) -> UtxoAddress {
let conf = &self.utxo.conf;
utxo_common::address_from_pubkey(
pubkey,
conf.pub_addr_prefix,
conf.pub_t_addr_prefix,
conf.address_prefixes.clone(),
conf.checksum_type,
conf.bech32_hrp.clone(),
self.addr_format().clone(),
Expand Down Expand Up @@ -1537,12 +1536,10 @@ pub struct Qrc20FeeDetails {
}

async fn qrc20_withdraw(coin: Qrc20Coin, req: WithdrawRequest) -> WithdrawResult {
let to_addr = UtxoAddress::from_str(&req.to)
.map_err(|e| e.to_string())
let to_addr = UtxoAddress::from_legacyaddress(&req.to, &coin.as_ref().conf.address_prefixes)
.map_to_mm(WithdrawError::InvalidAddress)?;
let conf = &coin.utxo.conf;
let is_p2pkh = to_addr.prefix == conf.pub_addr_prefix && to_addr.t_addr_prefix == conf.pub_t_addr_prefix;
if !is_p2pkh {
if !to_addr.is_pubkey_hash() {
let error = "QRC20 can be sent to P2PKH addresses only".to_owned();
return MmError::err(WithdrawError::InvalidAddress(error));
}
Expand Down
37 changes: 26 additions & 11 deletions mm2src/coins/qrc20/qrc20_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use chain::OutPoint;
use common::{block_on, wait_until_sec, DEX_FEE_ADDR_RAW_PUBKEY};
use crypto::Secp256k1Secret;
use itertools::Itertools;
use keys::{Address, AddressBuilder};
use mm2_core::mm_ctx::MmCtxBuilder;
use mm2_number::bigdecimal::Zero;
use mocktopus::mocking::{MockResult, Mockable};
Expand Down Expand Up @@ -65,14 +66,16 @@ fn test_withdraw_to_p2sh_address_should_fail() {
];
let (_, coin) = qrc20_coin_for_test(priv_key, None);

let p2sh_address = Address {
prefix: coin.as_ref().conf.p2sh_addr_prefix,
hash: coin.as_ref().derivation_method.unwrap_single_addr().hash.clone(),
t_addr_prefix: coin.as_ref().conf.p2sh_t_addr_prefix,
checksum_type: coin.as_ref().derivation_method.unwrap_single_addr().checksum_type,
hrp: coin.as_ref().conf.bech32_hrp.clone(),
addr_format: UtxoAddressFormat::Standard,
};
let p2sh_address = AddressBuilder::new(
UtxoAddressFormat::Standard,
coin.as_ref().derivation_method.unwrap_single_addr().hash().clone(),
*coin.as_ref().derivation_method.unwrap_single_addr().checksum_type(),
coin.as_ref().conf.address_prefixes.clone(),
coin.as_ref().conf.bech32_hrp.clone(),
)
.as_sh()
.build()
.expect("valid address props");

let req = WithdrawRequest {
amount: 10.into(),
Expand Down Expand Up @@ -150,7 +153,11 @@ fn test_validate_maker_payment() {

assert_eq!(
*coin.utxo.derivation_method.unwrap_single_addr(),
"qUX9FGHubczidVjWPCUWuwCUJWpkAtGCgf".into()
Address::from_legacyaddress(
"qUX9FGHubczidVjWPCUWuwCUJWpkAtGCgf",
&coin.as_ref().conf.address_prefixes
)
.unwrap()
);

// tx_hash: 016a59dd2b181b3906b0f0333d5c7561dacb332dc99ac39679a591e523f2c49a
Expand Down Expand Up @@ -249,7 +256,11 @@ fn test_wait_for_confirmations_excepted() {

assert_eq!(
*coin.utxo.derivation_method.unwrap_single_addr(),
"qUX9FGHubczidVjWPCUWuwCUJWpkAtGCgf".into()
Address::from_legacyaddress(
"qUX9FGHubczidVjWPCUWuwCUJWpkAtGCgf",
&coin.as_ref().conf.address_prefixes
)
.unwrap()
);

// tx_hash: 35e03bc529528a853ee75dde28f27eec8ed7b152b6af7ab6dfa5d55ea46f25ac
Expand Down Expand Up @@ -557,7 +568,11 @@ fn test_generate_token_transfer_script_pubkey() {
gas_price,
};

let to_addr: UtxoAddress = "qHmJ3KA6ZAjR9wGjpFASn4gtUSeFAqdZgs".into();
let to_addr: UtxoAddress = UtxoAddress::from_legacyaddress(
"qHmJ3KA6ZAjR9wGjpFASn4gtUSeFAqdZgs",
&coin.as_ref().conf.address_prefixes,
)
.unwrap();
let to_addr = qtum::contract_addr_from_utxo_addr(to_addr).unwrap();
let amount: U256 = 1000000000.into();
let actual = coin.transfer_output(to_addr, amount, gas_limit, gas_price).unwrap();
Expand Down
10 changes: 9 additions & 1 deletion mm2src/coins/qrc20/script_pubkey.rs
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,10 @@ fn decode_contract_number(source: &[u8]) -> Result<i64, String> {

#[cfg(test)]
mod tests {
use std::convert::TryInto;

use keys::prefixes::QRC20_PREFIXES;

use super::*;

#[test]
Expand Down Expand Up @@ -246,7 +250,11 @@ mod tests {
fn test_extract_contract_call() {
let script: Script = "5403a02526012844a9059cbb0000000000000000000000000240b898276ad2cc0d2fe6f527e8e31104e7fde3000000000000000000000000000000000000000000000000000000003b9aca0014d362e096e873eb7907e205fadc6175c6fec7bc44c2".into();

let to_addr: UtxoAddress = "qHmJ3KA6ZAjR9wGjpFASn4gtUSeFAqdZgs".into();
let to_addr: UtxoAddress = UtxoAddress::from_legacyaddress(
"qHmJ3KA6ZAjR9wGjpFASn4gtUSeFAqdZgs",
&QRC20_PREFIXES.try_into().unwrap(),
)
.unwrap();
let to_addr = qtum::contract_addr_from_utxo_addr(to_addr).unwrap();
let amount: U256 = 1000000000.into();
let function = eth::ERC20_CONTRACT.function("transfer").unwrap();
Expand Down
7 changes: 4 additions & 3 deletions mm2src/coins/rpc_command/init_scan_for_new_addresses.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::coin_balance::HDAddressBalance;
use crate::rpc_command::hd_account_balance_rpc_error::HDAccountBalanceRpcError;
use crate::utxo::utxo_common;
use crate::{lp_coinfind_or_err, CoinsContext, MmCoinEnum};
use async_trait::async_trait;
use common::{SerdeInfallible, SuccessResponse};
Expand Down Expand Up @@ -132,10 +133,8 @@ pub mod common_impl {
use crate::hd_wallet::{HDAccountOps, HDWalletCoinOps, HDWalletOps};
use crate::utxo::UtxoCommonOps;
use crate::CoinWithDerivationMethod;
use keys::Address;
use std::collections::HashSet;
use std::ops::DerefMut;
use std::str::FromStr;

pub async fn scan_for_new_addresses_rpc<Coin>(
coin: &Coin,
Expand Down Expand Up @@ -165,7 +164,9 @@ pub mod common_impl {

let addresses: HashSet<_> = new_addresses
.iter()
.map(|address_balance| Address::from_str(&address_balance.address).expect("Valid address"))
.map(|address_balance| {
utxo_common::address_from_str_unchecked(coin.as_ref(), &address_balance.address).expect("Valid address")
})
.collect();

coin.prepare_addresses_for_balance_stream_if_enabled(addresses.into())
Expand Down
5 changes: 4 additions & 1 deletion mm2src/coins/rpc_command/lightning/open_channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,10 @@ pub async fn open_channel(ctx: MmArc, req: OpenChannelRequest) -> OpenChannelRes

// The actual script_pubkey will replace this before signing the transaction after receiving the required
// output script from the other node when the channel is accepted
let script_pubkey = Builder::build_p2witness(&AddressHashEnum::WitnessScriptHash(Default::default())).to_bytes();
let script_pubkey = match Builder::build_p2wsh(&AddressHashEnum::WitnessScriptHash(Default::default())) {
Ok(script) => script.to_bytes(),
Err(err) => return MmError::err(OpenChannelError::InternalError(err.to_string())),
};
let outputs = vec![TransactionOutput { value, script_pubkey }];

let mut tx_builder = UtxoTxBuilder::new(&platform_coin)
Expand Down
Loading
Loading