diff --git a/rust/tw_tests/tests/chains/bitcoin/bitcoin_sign/psbt.rs b/rust/tw_tests/tests/chains/bitcoin/bitcoin_sign/psbt.rs index 141089020cf..ae660fd50c7 100644 --- a/rust/tw_tests/tests/chains/bitcoin/bitcoin_sign/psbt.rs +++ b/rust/tw_tests/tests/chains/bitcoin/bitcoin_sign/psbt.rs @@ -21,14 +21,16 @@ fn test_bitcoin_sign_psbt_thorchain_swap_witness() { }; // Successfully broadcasted: https://mempool.space/tx/634a416e82ac710166725f6a4090ac7b5db69687e86b2d2e38dcb3d91c956c32 - BitcoinPsbtSignHelper::new(&input).coin(CoinType::Bitcoin).sign_psbt(Expected { - psbt: "70736274ff0100bc0200000001147010db5fbcf619067c1090fec65c131443fbc80fb4aaeebe940e44206098c60000000000ffffffff0360ea000000000000160014f22a703617035ef7f490743d50f26ae08c30d0a70000000000000000426a403d3a474149412e41544f4d3a636f736d6f7331737377797a666d743675396a373437773537753438746778646575393573757a666c6d7175753a303a743a35303e12000000000000160014b139199ec796f36fc42e637f42da8e3e6720aa9d000000000001011f6603010000000000160014b139199ec796f36fc42e637f42da8e3e6720aa9d01086c02483045022100b1229a008f20691639767bf925d6b8956ea957ccc633ad6b5de3618733a55e6b02205774d3320489b8a57a6f8de07f561de3e660ff8e587f6ac5422c49020cd4dc9101210306d8c664ea8fd2683eebea1d3114d90e0a5429e5783ba49b80ddabce04ff28f300000000", - encoded: "02000000000101147010db5fbcf619067c1090fec65c131443fbc80fb4aaeebe940e44206098c60000000000ffffffff0360ea000000000000160014f22a703617035ef7f490743d50f26ae08c30d0a70000000000000000426a403d3a474149412e41544f4d3a636f736d6f7331737377797a666d743675396a373437773537753438746778646575393573757a666c6d7175753a303a743a35303e12000000000000160014b139199ec796f36fc42e637f42da8e3e6720aa9d02483045022100b1229a008f20691639767bf925d6b8956ea957ccc633ad6b5de3618733a55e6b02205774d3320489b8a57a6f8de07f561de3e660ff8e587f6ac5422c49020cd4dc9101210306d8c664ea8fd2683eebea1d3114d90e0a5429e5783ba49b80ddabce04ff28f300000000", - txid: "634a416e82ac710166725f6a4090ac7b5db69687e86b2d2e38dcb3d91c956c32", - vsize: 216, - weight: 862, - fee: 1736, - }); + BitcoinPsbtSignHelper::new(&input) + .coin(CoinType::Bitcoin) + .sign_psbt(Expected { + psbt: "70736274ff0100bc0200000001147010db5fbcf619067c1090fec65c131443fbc80fb4aaeebe940e44206098c60000000000ffffffff0360ea000000000000160014f22a703617035ef7f490743d50f26ae08c30d0a70000000000000000426a403d3a474149412e41544f4d3a636f736d6f7331737377797a666d743675396a373437773537753438746778646575393573757a666c6d7175753a303a743a35303e12000000000000160014b139199ec796f36fc42e637f42da8e3e6720aa9d000000000001011f6603010000000000160014b139199ec796f36fc42e637f42da8e3e6720aa9d01086c02483045022100b1229a008f20691639767bf925d6b8956ea957ccc633ad6b5de3618733a55e6b02205774d3320489b8a57a6f8de07f561de3e660ff8e587f6ac5422c49020cd4dc9101210306d8c664ea8fd2683eebea1d3114d90e0a5429e5783ba49b80ddabce04ff28f300000000", + encoded: "02000000000101147010db5fbcf619067c1090fec65c131443fbc80fb4aaeebe940e44206098c60000000000ffffffff0360ea000000000000160014f22a703617035ef7f490743d50f26ae08c30d0a70000000000000000426a403d3a474149412e41544f4d3a636f736d6f7331737377797a666d743675396a373437773537753438746778646575393573757a666c6d7175753a303a743a35303e12000000000000160014b139199ec796f36fc42e637f42da8e3e6720aa9d02483045022100b1229a008f20691639767bf925d6b8956ea957ccc633ad6b5de3618733a55e6b02205774d3320489b8a57a6f8de07f561de3e660ff8e587f6ac5422c49020cd4dc9101210306d8c664ea8fd2683eebea1d3114d90e0a5429e5783ba49b80ddabce04ff28f300000000", + txid: "634a416e82ac710166725f6a4090ac7b5db69687e86b2d2e38dcb3d91c956c32", + vsize: 216, + weight: 862, + fee: 1736, + }); } #[test] @@ -46,12 +48,14 @@ fn test_bitcoin_sign_psbt_thorchain_swap_non_witness() { }; // Successfully broadcasted: https://mempool.space/tx/710e9270b57720f567ada156c6ac72177aa00a36789e2c6526fd80040fae3ce4 - BitcoinPsbtSignHelper::new(&input).coin(CoinType::Bitcoin).sign_psbt(Expected { - psbt: "70736274ff01008202000000015c37bcf049b7e62dd5bfd707e0998ce86163b786e3cd45db2336cb794a8d8aa10000000000ffffffff03f82a000000000000160014bf5a13a26791a5db6406304a46952e264c2b28910000000000000000056a032b3a6291950000000000001976a9147c2c0ac72afbde13ecf52fca54368e7883b538b188ac000000000001007e0200000002714916920be4dbc87cbb8697ca9b1420d6b1e47e7d732e2d2e0e7a935087788d0000000000ffffffff326c951cd9b3dc382e2d6be88796b65d7bac90406a5f72660171ac826e414a630200000000ffffffff01efca0000000000001976a9147c2c0ac72afbde13ecf52fca54368e7883b538b188ac0000000001076a473044022057ce7a6147fd9e139df797adcec440bad60770f40cbd609363e3075b64d3eccd02200ae7dce5f7d1fa18c5e907a16c1b078fa90f537d36101447e53fbd058d2d950a0121036c3b7dfd678da989d91593e49918a6c9d8a1d37c7e9c0abeae2118c312e69b3100000000", - encoded: "02000000015c37bcf049b7e62dd5bfd707e0998ce86163b786e3cd45db2336cb794a8d8aa1000000006a473044022057ce7a6147fd9e139df797adcec440bad60770f40cbd609363e3075b64d3eccd02200ae7dce5f7d1fa18c5e907a16c1b078fa90f537d36101447e53fbd058d2d950a0121036c3b7dfd678da989d91593e49918a6c9d8a1d37c7e9c0abeae2118c312e69b31ffffffff03f82a000000000000160014bf5a13a26791a5db6406304a46952e264c2b28910000000000000000056a032b3a6291950000000000001976a9147c2c0ac72afbde13ecf52fca54368e7883b538b188ac00000000", - txid: "710e9270b57720f567ada156c6ac72177aa00a36789e2c6526fd80040fae3ce4", - vsize: 236, - weight: 944, - fee: 2662, - }); + BitcoinPsbtSignHelper::new(&input) + .coin(CoinType::Bitcoin) + .sign_psbt(Expected { + psbt: "70736274ff01008202000000015c37bcf049b7e62dd5bfd707e0998ce86163b786e3cd45db2336cb794a8d8aa10000000000ffffffff03f82a000000000000160014bf5a13a26791a5db6406304a46952e264c2b28910000000000000000056a032b3a6291950000000000001976a9147c2c0ac72afbde13ecf52fca54368e7883b538b188ac000000000001007e0200000002714916920be4dbc87cbb8697ca9b1420d6b1e47e7d732e2d2e0e7a935087788d0000000000ffffffff326c951cd9b3dc382e2d6be88796b65d7bac90406a5f72660171ac826e414a630200000000ffffffff01efca0000000000001976a9147c2c0ac72afbde13ecf52fca54368e7883b538b188ac0000000001076a473044022057ce7a6147fd9e139df797adcec440bad60770f40cbd609363e3075b64d3eccd02200ae7dce5f7d1fa18c5e907a16c1b078fa90f537d36101447e53fbd058d2d950a0121036c3b7dfd678da989d91593e49918a6c9d8a1d37c7e9c0abeae2118c312e69b3100000000", + encoded: "02000000015c37bcf049b7e62dd5bfd707e0998ce86163b786e3cd45db2336cb794a8d8aa1000000006a473044022057ce7a6147fd9e139df797adcec440bad60770f40cbd609363e3075b64d3eccd02200ae7dce5f7d1fa18c5e907a16c1b078fa90f537d36101447e53fbd058d2d950a0121036c3b7dfd678da989d91593e49918a6c9d8a1d37c7e9c0abeae2118c312e69b31ffffffff03f82a000000000000160014bf5a13a26791a5db6406304a46952e264c2b28910000000000000000056a032b3a6291950000000000001976a9147c2c0ac72afbde13ecf52fca54368e7883b538b188ac00000000", + txid: "710e9270b57720f567ada156c6ac72177aa00a36789e2c6526fd80040fae3ce4", + vsize: 236, + weight: 944, + fee: 2662, + }); } diff --git a/rust/tw_tests/tests/chains/common/bitcoin/psbt_plan.rs b/rust/tw_tests/tests/chains/common/bitcoin/psbt_plan.rs index f86f50041c8..3a8054c3dbd 100644 --- a/rust/tw_tests/tests/chains/common/bitcoin/psbt_plan.rs +++ b/rust/tw_tests/tests/chains/common/bitcoin/psbt_plan.rs @@ -3,9 +3,10 @@ // Copyright © 2017 Trust Wallet. use tw_coin_registry::coin_type::CoinType; -use tw_coin_registry::dispatcher::{coin_dispatcher, utxo_dispatcher}; +use tw_memory::test_utils::tw_data_helper::TWDataHelper; use tw_proto::BitcoinV2::Proto; use tw_proto::{deserialize, serialize}; +use wallet_core_rs::ffi::bitcoin::psbt::tw_bitcoin_plan_psbt; pub struct BitcoinPsbtPlanHelper<'a> { input: &'a Proto::PsbtSigningInput<'a>, @@ -32,13 +33,11 @@ impl<'a> BitcoinPsbtPlanHelper<'a> { .expect("'BitcoinSignHelper::coin_type' is not set"); let input = serialize(self.input).unwrap(); + let input = TWDataHelper::create(input); - // TODO call `tw_bitcoin_plan_psbt` when all tests are moved to another crate. - let (ctx, _entry) = coin_dispatcher(coin_type).expect("Unknown CoinType"); - let output_bytes = utxo_dispatcher(coin_type) - .expect("CoinType is not UTXO, i.e `utxo_dispatcher` failed") - .plan_psbt(&ctx, &input) - .unwrap(); + let output = + TWDataHelper::wrap(unsafe { tw_bitcoin_plan_psbt(coin_type as u32, input.ptr()) }); + let output_bytes = output.to_vec().unwrap(); let output: Proto::TransactionPlan = deserialize(&output_bytes).unwrap(); diff --git a/rust/tw_tests/tests/chains/common/bitcoin/psbt_sign.rs b/rust/tw_tests/tests/chains/common/bitcoin/psbt_sign.rs index aef22cd8f21..24af4b2f78f 100644 --- a/rust/tw_tests/tests/chains/common/bitcoin/psbt_sign.rs +++ b/rust/tw_tests/tests/chains/common/bitcoin/psbt_sign.rs @@ -3,11 +3,12 @@ // Copyright © 2017 Trust Wallet. use tw_coin_registry::coin_type::CoinType; -use tw_coin_registry::dispatcher::{coin_dispatcher, utxo_dispatcher}; use tw_encoding::hex::ToHex; +use tw_memory::test_utils::tw_data_helper::TWDataHelper; use tw_proto::BitcoinV2::Proto; use tw_proto::Common::Proto::SigningError; use tw_proto::{deserialize, serialize}; +use wallet_core_rs::ffi::bitcoin::psbt::tw_bitcoin_sign_psbt; pub struct Expected { /// Hex encoded PSBT. @@ -44,13 +45,11 @@ impl<'a> BitcoinPsbtSignHelper<'a> { .expect("'BitcoinSignHelper::coin_type' is not set"); let input = serialize(self.input).unwrap(); + let input = TWDataHelper::create(input); - // TODO call `tw_bitcoin_sign_psbt` when all tests are moved to another crate. - let (ctx, _entry) = coin_dispatcher(coin_type).expect("Unknown CoinType"); - let output_bytes = utxo_dispatcher(coin_type) - .expect("CoinType is not UTXO, i.e `utxo_dispatcher` failed") - .sign_psbt(&ctx, &input) - .unwrap(); + let output = + TWDataHelper::wrap(unsafe { tw_bitcoin_sign_psbt(coin_type as u32, input.ptr()) }); + let output_bytes = output.to_vec().unwrap(); let output: Proto::PsbtSigningOutput = deserialize(&output_bytes).unwrap(); diff --git a/rust/wallet_core_rs/src/ffi/bitcoin/mod.rs b/rust/wallet_core_rs/src/ffi/bitcoin/mod.rs index 7632dd9561b..dd6df1c9eda 100644 --- a/rust/wallet_core_rs/src/ffi/bitcoin/mod.rs +++ b/rust/wallet_core_rs/src/ffi/bitcoin/mod.rs @@ -1,3 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 // // Copyright © 2017 Trust Wallet. + +pub mod psbt; diff --git a/rust/wallet_core_rs/src/ffi/bitcoin/psbt.rs b/rust/wallet_core_rs/src/ffi/bitcoin/psbt.rs new file mode 100644 index 00000000000..eac05194ecc --- /dev/null +++ b/rust/wallet_core_rs/src/ffi/bitcoin/psbt.rs @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +#![allow(clippy::missing_safety_doc)] + +use tw_coin_registry::coin_type::CoinType; +use tw_coin_registry::dispatcher::{coin_dispatcher, utxo_dispatcher}; +use tw_memory::ffi::tw_data::TWData; +use tw_memory::ffi::RawPtrTrait; +use tw_misc::try_or_else; + +/// Signs a PSBT (Partially Signed Bitcoin Transaction) specified by the signing input and coin type. +/// +/// \param input The serialized data of a `Proto.PsbtSigningInput` protobuf message. +/// \param coin The given coin type to sign the PSBT for. +/// \return The serialized data of a `Proto.PsbtSigningOutput` protobuf message. +#[no_mangle] +pub unsafe extern "C" fn tw_bitcoin_sign_psbt(coin: u32, input: *const TWData) -> *mut TWData { + let coin = try_or_else!(CoinType::try_from(coin), std::ptr::null_mut); + let input_data = try_or_else!(TWData::from_ptr_as_ref(input), std::ptr::null_mut); + let utxo_dispatcher = try_or_else!(utxo_dispatcher(coin), std::ptr::null_mut); + let (coin_context, _) = try_or_else!(coin_dispatcher(coin), std::ptr::null_mut); + + utxo_dispatcher + .sign_psbt(&coin_context, input_data.as_slice()) + .map(|data| TWData::from(data).into_ptr()) + .unwrap_or_else(|_| std::ptr::null_mut()) +} + +/// Plans a PSBT (Partially Signed Bitcoin Transaction). +/// Can be used to get the transaction detailed decoded from PSBT. +/// +/// \param input The serialized data of a `Proto.PsbtSigningInput` protobuf message. +/// \param coin The given coin type to sign the PSBT for. +/// \return The serialized data of a `Proto.TransactionPlan` protobuf message. +#[no_mangle] +pub unsafe extern "C" fn tw_bitcoin_plan_psbt(coin: u32, input: *const TWData) -> *mut TWData { + let coin = try_or_else!(CoinType::try_from(coin), std::ptr::null_mut); + let input_data = try_or_else!(TWData::from_ptr_as_ref(input), std::ptr::null_mut); + let utxo_dispatcher = try_or_else!(utxo_dispatcher(coin), std::ptr::null_mut); + let (coin_context, _) = try_or_else!(coin_dispatcher(coin), std::ptr::null_mut); + + utxo_dispatcher + .plan_psbt(&coin_context, input_data.as_slice()) + .map(|data| TWData::from(data).into_ptr()) + .unwrap_or_else(|_| std::ptr::null_mut()) +}