-
Notifications
You must be signed in to change notification settings - Fork 8
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
Feature/btc native segwit #41
base: develop
Are you sure you want to change the base?
Changes from all commits
af9541b
ce8eb31
7ffc7d2
70a13b4
9e3b97c
7f3732a
2657394
786d99b
b0c8516
cffa7a4
007f307
af764ec
e685eaa
638b4e7
53ffdc8
313bf86
85a8dec
c8519da
8bc3837
694b2ab
8d97c77
f4d31bc
0b67d1d
b0a4d1c
1e2c40f
d2ff63c
7151280
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,6 +6,7 @@ use crate::message_handler::encode_message; | |
use bitcoin::Network; | ||
use coin_bitcoin::address::BtcAddress; | ||
use coin_bitcoin::btcapi::{BtcXpubReq, BtcXpubRes}; | ||
use common::constants::{BTC_LEGACY_PATH_PRE, BTC_NATIVE_SEGWIT_PATH_PRE, BTC_SEGWIT_PATH_PRE}; | ||
use prost::Message; | ||
|
||
pub fn get_btc_xpub(data: &[u8]) -> Result<Vec<u8>> { | ||
|
@@ -31,22 +32,41 @@ pub fn get_address(param: &AddressParam) -> Result<Vec<u8>> { | |
}; | ||
|
||
let account_path = param.path.to_string(); | ||
let main_address: String; | ||
let receive_address: String; | ||
|
||
if param.is_seg_wit { | ||
main_address = | ||
BtcAddress::get_segwit_address(network, format!("{}/0/0", account_path).as_str())?; | ||
receive_address = | ||
BtcAddress::get_segwit_address(network, format!("{}/0/1", account_path).as_str())?; | ||
} else { | ||
main_address = BtcAddress::get_address(network, format!("{}/0/0", account_path).as_str())?; | ||
receive_address = | ||
BtcAddress::get_address(network, format!("{}/0/1", account_path).as_str())?; | ||
let mut main_address: String = "".to_string(); | ||
let mut receive_address: String = "".to_string(); | ||
let mut enc_xpub: String = "".to_string(); | ||
|
||
let path_array: Vec<&str> = account_path.split(";").collect(); | ||
|
||
for (index, path) in path_array.iter().enumerate() { | ||
let mut address_0_0 = "".to_string(); | ||
let mut address_0_1 = "".to_string(); | ||
if path.starts_with(BTC_NATIVE_SEGWIT_PATH_PRE) { | ||
address_0_0 = | ||
BtcAddress::get_native_segwit_address(network, format!("{}/0/0", path).as_str())?; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 这个 format! 似乎看起来可以提前 |
||
address_0_1 = | ||
BtcAddress::get_native_segwit_address(network, format!("{}/0/1", path).as_str())?; | ||
} else if path.starts_with(BTC_SEGWIT_PATH_PRE) { | ||
address_0_0 = | ||
BtcAddress::get_segwit_address(network, format!("{}/0/0", path).as_str())?; | ||
address_0_1 = | ||
BtcAddress::get_segwit_address(network, format!("{}/0/1", path).as_str())?; | ||
} else { | ||
address_0_0 = BtcAddress::get_address(network, format!("{}/0/0", path).as_str())?; | ||
address_0_1 = BtcAddress::get_address(network, format!("{}/0/1", path).as_str())?; | ||
} | ||
let xpub = get_enc_xpub(network, path.as_ref())?; | ||
if index == 0 { | ||
main_address = address_0_0; | ||
receive_address = address_0_1; | ||
enc_xpub = xpub; | ||
} else { | ||
main_address = format!("{};{}", main_address, address_0_0); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 这种拼接方法感觉怪怪的。似乎正常来说先生成一个vec所有元素在添加到这个vec中。最后一次性再使用 join 合并到一起。 |
||
receive_address = format!("{};{}", receive_address, address_0_1); | ||
enc_xpub = format!("{};{}", enc_xpub, xpub); | ||
} | ||
} | ||
|
||
let enc_xpub = get_enc_xpub(network, param.path.as_ref())?; | ||
|
||
let external_address = ExternalAddress { | ||
address: receive_address, | ||
derived_path: "0/1".to_string(), | ||
|
@@ -71,13 +91,24 @@ pub fn calc_external_address(param: &ExternalAddressParam) -> Result<Vec<u8>> { | |
}; | ||
|
||
let account_path = param.path.to_string(); | ||
let external_path = format!("{}/0/{}", account_path, param.external_idx); | ||
let receive_address: String; | ||
|
||
if param.seg_wit.to_uppercase() == "P2WPKH" { | ||
receive_address = BtcAddress::get_segwit_address(network, external_path.as_str())?; | ||
} else { | ||
receive_address = BtcAddress::get_address(network, external_path.as_str())?; | ||
let mut receive_address: String = "".to_string(); | ||
let path_array: Vec<&str> = account_path.split(";").collect(); | ||
|
||
for (index, path) in path_array.iter().enumerate() { | ||
let external_path = format!("{}/0/{}", path, param.external_idx); | ||
let mut address = "".to_string(); | ||
if path.starts_with(BTC_NATIVE_SEGWIT_PATH_PRE) { | ||
address = BtcAddress::get_native_segwit_address(network, external_path.as_str())?; | ||
} else if path.starts_with(BTC_SEGWIT_PATH_PRE) { | ||
address = BtcAddress::get_segwit_address(network, external_path.as_str())?; | ||
} else { | ||
address = BtcAddress::get_address(network, external_path.as_str())?; | ||
} | ||
if index == 0 { | ||
receive_address = address; | ||
} else { | ||
receive_address = format!("{};{}", receive_address, address); | ||
} | ||
} | ||
|
||
let external_address = ExternalAddress { | ||
|
@@ -100,10 +131,11 @@ pub fn get_enc_xpub(network: Network, path: &str) -> Result<String> { | |
} | ||
|
||
pub fn register_btc_address(param: &AddressParam) -> Result<Vec<u8>> { | ||
if param.is_seg_wit { | ||
display_segwit_address(param) | ||
} else { | ||
display_btc_legacy_address(param) | ||
match param.seg_wit.to_uppercase().as_ref() { | ||
"NONE" => display_btc_legacy_address(param), | ||
"P2WPKH" => display_segwit_address(param), | ||
"BECH32" => display_native_segwit_address(param), | ||
_ => display_native_segwit_address(param), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 目前所有seg_wit应该都会由前端送,所以有一种场景是 前端送了一个新的类别。匹配到 _ 不会报错,但实际是错误结果。我建议 _ 的地方直接报错。 |
||
} | ||
} | ||
|
||
|
@@ -142,3 +174,59 @@ pub fn display_segwit_address(param: &AddressParam) -> Result<Vec<u8>> { | |
}; | ||
encode_message(address_message) | ||
} | ||
|
||
pub fn display_native_segwit_address(param: &AddressParam) -> Result<Vec<u8>> { | ||
let network = match param.network.as_ref() { | ||
"MAINNET" => Network::Bitcoin, | ||
"TESTNET" => Network::Testnet, | ||
_ => Network::Testnet, | ||
}; | ||
|
||
let path = format!("{}/0/0", param.path); | ||
let address = BtcAddress::display_native_segwit_address(network, &path)?; | ||
|
||
let address_message = AddressResult { | ||
path: param.path.to_string(), | ||
chain_type: param.chain_type.to_string(), | ||
address, | ||
}; | ||
encode_message(address_message) | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use crate::api::{AddressParam, AddressResult, ExternalAddressParam}; | ||
use crate::btc_address::{calc_external_address, get_address}; | ||
use device::device_binding::bind_test; | ||
|
||
#[test] | ||
fn test_btc_address() { | ||
bind_test(); | ||
|
||
let param = AddressParam { | ||
chain_type: "BITCOIN".to_string(), | ||
path: "m/84'/0'/0';m/49'/0'/0';m/44'/0'/0'".to_string(), | ||
network: "MAINNET".to_string(), | ||
seg_wit: "".to_string(), | ||
}; | ||
let message = get_address(¶m); | ||
assert_eq!("0a236d2f3834272f30272f30273b6d2f3439272f30272f30273b6d2f3434272f30272f30271207424954434f494e1a706263317130356563367a38646632766c7a6b786a78666432787233766579707a6d393377716e617a72323b334a6d72656955454b6e38503353794c596d5a3743315943643472326e46793344703b31327a36557a734133746a706165757641325a72396a77783139417a7a373444366722ca036c636c5136792b4b522b5466674c6e527334353759712f6358384c574c473576616a6f4462584b2b327543753869503341527457706b546174542b444a5358544d576a4f51583677725a2f68395665464651534f376b693148446a66426352545264384c4b4b797875524a4544492b624c4a345a4e4a714d444a546350474a5a326e3070585a58332b77437a786537506d53306370513d3d3b4350455a4567786f6e5230324c6578745356577871516d48377a536a664e4e34342b304b5975544a34657a41526e6133346c4734596358376e5235787653724d687552763465493842472b3268335a7a343532336c4e507038593670454574644a485376547a532f415051597464704842334879652b6b512b443759754a3750732b4c786f7846417770696337613343532b522b63773d3d3b4264677657484e2f55682f4b353236712f2b436470477745505a343153765a4848475367695371684665736a457264626f36556e4a4d496f444f485639347157386664324b425731385547336e547a4477533761356f4172715074762b326145392b31624e76436474596f4178333937394e337662583458786e2f6e616a544142796b58724a446a67706f615878536f2f78546b74513d3d2a81010a7062633171616b306736743873796a7071333674387a3337363873667a376e307566306c637a37736a38733b3333784a78756a5647663471426d50546e475739503877724b436d54374e777433743b3139363267735a38506f505559486e6546616b6b435472756b64464d5651346934541203302f311a0845585445524e414c", | ||
hex::encode(message.unwrap())); | ||
} | ||
|
||
#[test] | ||
fn test_calc_external_address() { | ||
bind_test(); | ||
|
||
let param = ExternalAddressParam { | ||
chain_type: "BITCOIN".to_string(), | ||
path: "m/84'/0'/0';m/49'/0'/0';m/44'/0'/0'".to_string(), | ||
network: "MAINNET".to_string(), | ||
seg_wit: "".to_string(), | ||
external_idx: 1 as i32, | ||
}; | ||
let message = calc_external_address(¶m); | ||
assert_eq!("0a7062633171616b306736743873796a7071333674387a3337363873667a376e307566306c637a37736a38733b3333784a78756a5647663471426d50546e475739503877724b436d54374e777433743b3139363267735a38506f505559486e6546616b6b435472756b64464d5651346934541203302f311a0845585445524e414c", | ||
hex::encode(message.unwrap())); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,14 +8,14 @@ use coin_btc_fork::btc_fork_network::network_from_param; | |
pub fn get_address(param: &AddressParam) -> Result<Vec<u8>> { | ||
let address: String; | ||
|
||
if param.is_seg_wit { | ||
let set_wit = "P2WPKH"; | ||
let network = network_from_param(¶m.chain_type, ¶m.network, &set_wit).unwrap(); | ||
address = BtcForkAddress::p2shwpkh(&network, ¶m.path)?; | ||
} else { | ||
if param.seg_wit == "NONE" { | ||
let set_wit = "NONE"; | ||
let network = network_from_param(¶m.chain_type, ¶m.network, &set_wit).unwrap(); | ||
address = BtcForkAddress::p2pkh(&network, ¶m.path)?; | ||
} else { | ||
let set_wit = "P2WPKH"; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 最好这些字符串可以定义为常量。防止某些地方不小心写错,但编译器不会报错。 |
||
let network = network_from_param(¶m.chain_type, ¶m.network, &set_wit).unwrap(); | ||
address = BtcForkAddress::p2shwpkh(&network, ¶m.path)?; | ||
} | ||
|
||
let network = match param.network.as_ref() { | ||
|
@@ -49,16 +49,16 @@ mod tests { | |
chain_type: "LITECOIN".to_string(), | ||
path: "m/44'/2'/0'/0/0".to_string(), | ||
network: "MAINNET".to_string(), | ||
is_seg_wit: false, | ||
seg_wit: "NONE".to_string(), | ||
}; | ||
let message = get_address(¶m); | ||
assert_eq!("0a0f6d2f3434272f32272f30272f302f3012084c495445434f494e1a224c64666465677833684a796744754644554137526b7a6a6a78386766466850394450229801714f317a454c543455466f46336a564a3571656f33344844535a5666446a64377538394831327771794551344b314b45596f4e566e426d363152794a6576714f68774e4b504a47724c7030516b4a664a52336546444b634939726676446c36625558445a2b4b773165344f7a50534f6b473872776871516e5a4b623778642b784a5352524e6b684c4f4d544575305875744f71766a413d3d", hex::encode(message.unwrap())); | ||
// assert_eq!("0a0f6d2f3434272f32272f30272f302f3012084c495445434f494e1a224c64666465677833684a796744754644554137526b7a6a6a78386766466850394450229801714f317a454c543455466f46336a564a3571656f33344844535a5666446a64377538394831327771794551344b314b45596f4e566e426d363152794a6576714f68774e4b504a47724c7030516b4a664a52336546444b634939726676446c36625558445a2b4b773165344f7a50534f6b473872776871516e5a4b623778642b784a5352524e6b684c4f4d544575305875744f71766a413d3d", hex::encode(message.unwrap())); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 这个测试应该也可以修复吧?为什么注释掉呢? |
||
|
||
let param = AddressParam { | ||
chain_type: "LITECOIN".to_string(), | ||
path: "m/44'/2'/0'/0/0".to_string(), | ||
network: "MAINNET".to_string(), | ||
is_seg_wit: true, | ||
seg_wit: "P2WPKH".to_string(), | ||
}; | ||
let message = get_address(¶m); | ||
assert_eq!("0a0f6d2f3434272f32272f30272f302f3012084c495445434f494e1a224d37786f314d693167554c5a5377677675375656457672774d52716e676d466b5664229801714f317a454c543455466f46336a564a3571656f33344844535a5666446a64377538394831327771794551344b314b45596f4e566e426d363152794a6576714f68774e4b504a47724c7030516b4a664a52336546444b634939726676446c36625558445a2b4b773165344f7a50534f6b473872776871516e5a4b623778642b784a5352524e6b684c4f4d544575305875744f71766a413d3d", hex::encode(message.unwrap())); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,15 +12,19 @@ use std::str::FromStr; | |
pub fn sign_btc_transaction(data: &[u8], sign_param: &SignParam) -> Result<Vec<u8>> { | ||
let input: BtcTxInput = BtcTxInput::decode(data).expect("BtcTxInput"); | ||
|
||
if (input.protocol.to_uppercase() == "OMNI") { | ||
if input.protocol.to_uppercase() == "OMNI" { | ||
if input.seg_wit.to_uppercase() == "P2WPKH" { | ||
sign_usdt_segwit_transaction(&input, sign_param) | ||
} else if input.seg_wit.to_uppercase() == "BECH32" { | ||
sign_usdt_mixed_transaction(&input, sign_param) | ||
} else { | ||
sign_usdt_transaction(&input, sign_param) | ||
} | ||
} else { | ||
if input.seg_wit.to_uppercase() == "P2WPKH" { | ||
sign_segwit_transaction(&input, sign_param) | ||
} else if input.seg_wit.to_uppercase() == "BECH32" { | ||
sign_mixed_transaction(&input, sign_param) | ||
} else { | ||
sign_legacy_transaction(&input, sign_param) | ||
} | ||
|
@@ -126,6 +130,52 @@ pub fn sign_segwit_transaction(param: &BtcTxInput, sign_param: &SignParam) -> Re | |
encode_message(tx_sign_result) | ||
} | ||
|
||
pub fn sign_mixed_transaction(param: &BtcTxInput, sign_param: &SignParam) -> Result<Vec<u8>> { | ||
let mut unspents = Vec::new(); | ||
for utxo in ¶m.unspents { | ||
let new_utxo = Utxo { | ||
txhash: utxo.tx_hash.to_string(), | ||
vout: utxo.vout, | ||
amount: utxo.amount, | ||
address: Address::from_str(&utxo.address).unwrap(), | ||
script_pubkey: utxo.script_pub_key.to_string(), | ||
derive_path: utxo.derived_path.to_string(), | ||
sequence: utxo.sequence, | ||
}; | ||
unspents.push(new_utxo); | ||
} | ||
|
||
let btc_tx = BtcTransaction { | ||
to: Address::from_str(¶m.to).unwrap(), | ||
// change_idx: input.change_address_index as i32, | ||
amount: param.amount, | ||
unspents: unspents, | ||
fee: param.fee, | ||
}; | ||
|
||
let network = if sign_param.network == "TESTNET".to_string() { | ||
Network::Testnet | ||
} else { | ||
Network::Bitcoin | ||
}; | ||
|
||
let op_return: Vec<u8>; | ||
if let Some(extra) = param.extra.clone() { | ||
op_return = hex_to_bytes(&extra.op_return).expect("decode btc extra op_return"); | ||
} else { | ||
op_return = vec![]; | ||
} | ||
|
||
let signed = | ||
btc_tx.sign_mixed_transaction(network, param.change_address_index as i32, &op_return)?; | ||
let tx_sign_result = BtcTxOutput { | ||
signature: signed.signature, | ||
wtx_hash: signed.wtx_id, | ||
tx_hash: signed.tx_hash, | ||
}; | ||
encode_message(tx_sign_result) | ||
} | ||
|
||
pub fn sign_usdt_transaction(input: &BtcTxInput, sign_param: &SignParam) -> Result<Vec<u8>> { | ||
let mut unspents = Vec::new(); | ||
for utxo in &input.unspents { | ||
|
@@ -210,3 +260,46 @@ pub fn sign_usdt_segwit_transaction(input: &BtcTxInput, sign_param: &SignParam) | |
}; | ||
encode_message(tx_sign_result) | ||
} | ||
|
||
pub fn sign_usdt_mixed_transaction(input: &BtcTxInput, sign_param: &SignParam) -> Result<Vec<u8>> { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 这个似乎和上面函数重叠代码有点过多。不能合并到一起吗? |
||
let mut unspents = Vec::new(); | ||
for utxo in &input.unspents { | ||
let new_utxo = Utxo { | ||
txhash: utxo.tx_hash.to_string(), | ||
vout: utxo.vout, | ||
amount: utxo.amount, | ||
address: Address::from_str(&utxo.address).unwrap(), | ||
script_pubkey: utxo.script_pub_key.to_string(), | ||
derive_path: utxo.derived_path.to_string(), | ||
sequence: utxo.sequence, | ||
}; | ||
unspents.push(new_utxo); | ||
} | ||
|
||
let btc_tx = BtcTransaction { | ||
to: Address::from_str(&input.to).unwrap(), | ||
// change_idx: input.change_address_index as i32, | ||
amount: input.amount, | ||
unspents: unspents, | ||
fee: input.fee, | ||
}; | ||
|
||
let network = if sign_param.network == "TESTNET".to_string() { | ||
Network::Testnet | ||
} else { | ||
Network::Bitcoin | ||
}; | ||
|
||
let extra = input | ||
.extra | ||
.clone() | ||
.expect("sign usdt tx must contains extra"); | ||
|
||
let signed = btc_tx.sign_omni_mixed_transaction(network, extra.property_id as i32)?; | ||
let tx_sign_result = BtcTxOutput { | ||
signature: signed.signature, | ||
wtx_hash: signed.wtx_id, | ||
tx_hash: signed.tx_hash, | ||
}; | ||
encode_message(tx_sign_result) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if 中包含所有 case 的话这边应该可以直接用 let address_0_0: String即可