Skip to content
Merged
Show file tree
Hide file tree
Changes from 28 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
d5f055a
remove unused TransactionOutputs (which prevented parametrised addres…
Sep 5, 2023
19cab7a
add script_type to Address
Sep 5, 2023
ca5e9c2
fix format
Sep 5, 2023
753fb93
fix coin prefix in address tests
Sep 5, 2023
9cc277f
fix fmt
Sep 5, 2023
1793290
fix test results because of Address::from_str changed to from_legacya…
Sep 6, 2023
f953499
add NetworkAddressPrefixes type and replace use of u8 addr prefixes
Oct 9, 2023
6050621
remove controversial check in withdraw (no segwit case)
Oct 9, 2023
0b1842d
fix use for coin prefixes in test helpers
Oct 9, 2023
82a3b2d
add default val for LegacyAddress
Oct 9, 2023
6924cb0
remove commented code
Oct 9, 2023
3de99ae
remove unused invalid prefixes error
Oct 9, 2023
838911d
fix after rebase
Nov 2, 2023
69bd48b
fix convert_address fn for converting to legacy address
Nov 2, 2023
e5283c3
fix cargo fmt
Nov 2, 2023
123e3f8
Merge branch 'dev' into feature-add-script-type-to-address-bak
Jan 23, 2024
055e2f7
fix test_address_to_scripthash after merge
Jan 23, 2024
124d758
add comment for addr prefixes
Jan 23, 2024
845ed0d
change to unchecked ver of address_from_str
Jan 25, 2024
87c438d
refactor: add AddressBuilder to check creation params; simplify fn ou…
Jan 25, 2024
b10f38d
add drop_mutability in conf builder
Jan 25, 2024
a38ed54
fix addr_format for check_if_my_payment_sent fn (must not be segwit)
Jan 29, 2024
35367d4
rename address builder options to avoid confusion
Jan 29, 2024
f66529e
break script witness creation fn into p2wpkh and p2wsh to validate wi…
Jan 29, 2024
9206ca2
add swap events debug logging
Jan 29, 2024
9bb5f13
fix clippy fmt
Jan 29, 2024
acf7174
remove my debug in swaps
Jan 29, 2024
095a804
remove temp ignore for iris tests
Jan 30, 2024
64dbf87
refactor AddressBuilder according to builder pattern
Feb 1, 2024
354c970
fixed review notes: propagate output_script() error
Feb 2, 2024
4603855
remove extra map_err, add returned err logging
Feb 2, 2024
9260531
remove extra map_to_mm
Feb 2, 2024
3434e2b
refactor AddressPrefixes - remove extra const type
Feb 5, 2024
d7f6cdb
refactor: rename AddressPrefixes to singular
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
12 changes: 9 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,13 @@ 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(_) => {
error!("Error building change script");
Comment thread
shamardy marked this conversation as resolved.
Outdated
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
5 changes: 2 additions & 3 deletions mm2src/coins/lp_coins.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4258,7 +4258,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 +4267,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_p2pkh() {
let error = "QRC20 can be sent to P2PKH addresses only".to_owned();
Comment thread
shamardy marked this conversation as resolved.
return MmError::err(WithdrawError::InvalidAddress(error));
}
Expand Down
32 changes: 23 additions & 9 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,15 @@ 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,
let p2sh_address = AddressBuilder {
prefixes: coin.as_ref().conf.address_prefixes.clone(),
hash: coin.as_ref().derivation_method.unwrap_single_addr().hash().clone(),
checksum_type: *coin.as_ref().derivation_method.unwrap_single_addr().checksum_type(),
hrp: coin.as_ref().conf.bech32_hrp.clone(),
addr_format: UtxoAddressFormat::Standard,
};
}
.build_as_sh()
.expect("valid address props");

let req = WithdrawRequest {
amount: 10.into(),
Expand Down Expand Up @@ -150,7 +152,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 +255,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 +567,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
40 changes: 18 additions & 22 deletions mm2src/coins/utxo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,10 @@ use futures::compat::Future01CompatExt;
use futures::lock::{Mutex as AsyncMutex, MutexGuard as AsyncMutexGuard};
use futures01::Future;
use keys::bytes::Bytes;
use keys::NetworkAddressPrefixes;
use keys::Signature;
pub use keys::{Address, AddressFormat as UtxoAddressFormat, AddressHashEnum, KeyPair, Private, Public, Secret,
Type as ScriptType};
pub use keys::{Address, AddressBuilder, AddressFormat as UtxoAddressFormat, AddressHashEnum, AddressPrefixes,
AddressScriptType, KeyPair, LegacyAddress, Private, Public, Secret};
#[cfg(not(target_arch = "wasm32"))]
use lightning_invoice::Currency as LightningCurrency;
use mm2_core::mm_ctx::{MmArc, MmWeak};
Expand Down Expand Up @@ -504,11 +505,8 @@ pub struct UtxoCoinConf {
pub ticker: String,
/// https://en.bitcoin.it/wiki/List_of_address_prefixes
/// https://github.com/jl777/coins/blob/master/coins
pub pub_addr_prefix: u8,
pub p2sh_addr_prefix: u8,
pub wif_prefix: u8,
pub pub_t_addr_prefix: u8,
pub p2sh_t_addr_prefix: u8,
pub address_prefixes: NetworkAddressPrefixes,
pub sign_message_prefix: Option<String>,
// https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#Segwit_address_format
pub bech32_hrp: Option<String>,
Expand Down Expand Up @@ -879,7 +877,7 @@ impl HDAddressBalanceScanner for UtxoAddressScanner {
let is_used = match self {
UtxoAddressScanner::Native { non_empty_addresses } => non_empty_addresses.contains(&address.to_string()),
UtxoAddressScanner::Electrum(electrum_client) => {
let script = output_script(address, ScriptType::P2PKH);
let script = output_script(address);
let script_hash = electrum_script_hash(&script);

let electrum_history = electrum_client
Expand Down Expand Up @@ -1881,12 +1879,12 @@ where
})
.collect();

let signature_version = match &my_address.addr_format {
let signature_version = match my_address.addr_format() {
UtxoAddressFormat::Segwit => SignatureVersion::WitnessV0,
_ => coin.as_ref().conf.signature_version,
};

let prev_script = utxo_common::get_script_for_address(coin.as_ref(), my_address)
let prev_script = utxo_common::output_script_checked(coin.as_ref(), my_address)
.map_err(|e| TransactionErr::Plain(ERRL!("{}", e)))?;
let signed = try_tx_s!(sign_tx(
unsigned,
Expand All @@ -1903,15 +1901,13 @@ where
Ok(signed)
}

pub fn output_script(address: &Address, script_type: ScriptType) -> Script {
match address.addr_format {
UtxoAddressFormat::Segwit => Builder::build_p2witness(&address.hash),
_ => match script_type {
ScriptType::P2PKH => Builder::build_p2pkh(&address.hash),
ScriptType::P2SH => Builder::build_p2sh(&address.hash),
ScriptType::P2WPKH => Builder::build_p2witness(&address.hash),
ScriptType::P2WSH => Builder::build_p2witness(&address.hash),
},
/// Builds transaction output script for an Address struct
pub fn output_script(address: &Address) -> Script {
match address.script_type() {
AddressScriptType::P2PKH => Builder::build_p2pkh(address.hash()),
AddressScriptType::P2SH => Builder::build_p2sh(address.hash()),
AddressScriptType::P2WPKH => Builder::build_p2wpkh(address.hash()).expect("valid p2wpkh"),
AddressScriptType::P2WSH => Builder::build_p2wsh(address.hash()).expect("valid p2wsh"),
Comment thread
shamardy marked this conversation as resolved.
Outdated
}
}

Expand Down Expand Up @@ -1941,14 +1937,14 @@ pub fn address_by_conf_and_pubkey_str(
let pubkey_bytes = try_s!(hex::decode(pubkey));
let hash = dhash160(&pubkey_bytes);

let address = Address {
prefix: utxo_conf.pub_addr_prefix,
t_addr_prefix: utxo_conf.pub_t_addr_prefix,
let address = AddressBuilder {
prefixes: utxo_conf.address_prefixes,
hash: hash.into(),
checksum_type: utxo_conf.checksum_type,
hrp: utxo_conf.bech32_hrp,
addr_format,
};
}
.build_as_pkh()?;
address.display_address()
}

Expand Down
18 changes: 5 additions & 13 deletions mm2src/coins/utxo/bch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,11 +157,7 @@ impl BchCoin {

pub fn slp_address(&self, address: &Address) -> Result<CashAddress, String> {
let conf = &self.as_ref().conf;
address.to_cashaddress(
&self.slp_prefix().to_string(),
conf.pub_addr_prefix,
conf.p2sh_addr_prefix,
)
address.to_cashaddress(&self.slp_prefix().to_string(), &conf.address_prefixes)
}

pub fn bchd_urls(&self) -> &[String] { &self.bchd_urls }
Expand Down Expand Up @@ -348,11 +344,8 @@ impl BchCoin {

pub fn get_my_slp_address(&self) -> Result<CashAddress, String> {
let my_address = try_s!(self.as_ref().derivation_method.single_addr_or_err());
let slp_address = my_address.to_cashaddress(
&self.slp_prefix().to_string(),
self.as_ref().conf.pub_addr_prefix,
self.as_ref().conf.p2sh_addr_prefix,
)?;
let slp_address =
my_address.to_cashaddress(&self.slp_prefix().to_string(), &self.as_ref().conf.address_prefixes)?;
Ok(slp_address)
}

Expand Down Expand Up @@ -760,7 +753,7 @@ impl UtxoCommonOps for BchCoin {
}

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

async fn get_current_mtp(&self) -> UtxoRpcResult<u32> {
Expand Down Expand Up @@ -833,8 +826,7 @@ impl UtxoCommonOps for BchCoin {
let addr_format = self.addr_format().clone();
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(),
addr_format,
Expand Down
Loading