diff --git a/Cargo.lock b/Cargo.lock index 54fc0cb..54f2b25 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -879,16 +879,6 @@ dependencies = [ "syn_derive", ] -[[package]] -name = "bs58" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" -dependencies = [ - "sha2", - "tinyvec", -] - [[package]] name = "bumpalo" version = "3.16.0" @@ -5029,7 +5019,6 @@ dependencies = [ "bitcoin", "blake3", "borsh", - "bs58", "byteorder", "bytes", "ed25519-dalek", diff --git a/app/app.rs b/app/app.rs index 4b1eb3a..8824e85 100644 --- a/app/app.rs +++ b/app/app.rs @@ -5,7 +5,6 @@ use futures::{StreamExt, TryFutureExt, TryStreamExt as _}; use parking_lot::RwLock; use rustreexo::accumulator::proof::Proof; use thunder::{ - format_deposit_address, miner::{self, Miner}, node::{self, Node}, types::{ @@ -14,7 +13,7 @@ use thunder::{ self, generated::{validator_service_server, wallet_service_server}, }, - OutPoint, Output, Transaction, THIS_SIDECHAIN, + Address, OutPoint, Output, Transaction, }, wallet::{self, Wallet}, }; @@ -354,24 +353,22 @@ impl App { } pub fn deposit( - &mut self, + &self, + address: Address, amount: bitcoin::Amount, fee: bitcoin::Amount, - ) -> Result<(), Error> { + ) -> Result { let Some(miner) = self.miner.as_ref() else { return Err(Error::NoCusfMainchainWalletClient); }; self.runtime.block_on(async { - let address = self.wallet.get_new_address()?; - let address = - format_deposit_address(THIS_SIDECHAIN, &format!("{address}")); let mut miner_write = miner.write().await; - let _txid = miner_write + let txid = miner_write .cusf_mainchain_wallet .create_deposit_tx(address, amount.to_sat(), fee.to_sat()) .await?; drop(miner_write); - Ok(()) + Ok(txid) }) } } diff --git a/app/gui/parent_chain/transfer.rs b/app/gui/parent_chain/transfer.rs index 9f0386c..e7eb4c1 100644 --- a/app/gui/parent_chain/transfer.rs +++ b/app/gui/parent_chain/transfer.rs @@ -47,6 +47,7 @@ impl Deposit { .clicked() { if let Err(err) = app.deposit( + app.wallet.get_new_address().expect("should not happen"), amount.expect("should not happen"), fee.expect("should not happen"), ) { diff --git a/app/rpc_server.rs b/app/rpc_server.rs index 042a889..54ffa12 100644 --- a/app/rpc_server.rs +++ b/app/rpc_server.rs @@ -7,7 +7,7 @@ use jsonrpsee::{ }; use thunder::{ node, - types::{Address, PointedOutput, Txid, THIS_SIDECHAIN}, + types::{Address, PointedOutput, Txid}, wallet, }; use thunder_app_rpc_api::RpcServer; @@ -50,6 +50,21 @@ impl RpcServer for RpcServerImpl { self.app.wallet.get_balance().map_err(convert_wallet_err) } + async fn create_deposit( + &self, + address: Address, + value_sats: u64, + fee_sats: u64, + ) -> RpcResult { + self.app + .deposit( + address, + bitcoin::Amount::from_sat(value_sats), + bitcoin::Amount::from_sat(fee_sats), + ) + .map_err(convert_app_err) + } + async fn connect_peer(&self, addr: SocketAddr) -> RpcResult<()> { self.app.node.connect_peer(addr).map_err(convert_node_err) } @@ -58,10 +73,7 @@ impl RpcServer for RpcServerImpl { &self, address: Address, ) -> RpcResult { - let deposit_address = thunder::format_deposit_address( - THIS_SIDECHAIN, - &address.to_string(), - ); + let deposit_address = thunder::format_deposit_address(address); Ok(deposit_address) } diff --git a/cli/lib.rs b/cli/lib.rs index bdd1ced..93ae1b6 100644 --- a/cli/lib.rs +++ b/cli/lib.rs @@ -12,6 +12,14 @@ pub enum Command { Balance, /// Connect to a peer ConnectPeer { addr: SocketAddr }, + /// Deposit to address + CreateDeposit { + address: Address, + #[arg(long)] + value_sats: u64, + #[arg(long)] + fee_sats: u64, + }, /// Format a deposit address FormatDepositAddress { address: Address }, /// Generate a mnemonic seed phrase @@ -91,6 +99,16 @@ impl Cli { let () = rpc_client.connect_peer(addr).await?; String::default() } + Command::CreateDeposit { + address, + value_sats, + fee_sats, + } => { + let txid = rpc_client + .create_deposit(address, value_sats, fee_sats) + .await?; + format!("{txid}") + } Command::FormatDepositAddress { address } => { rpc_client.format_deposit_address(address).await? } diff --git a/lib/Cargo.toml b/lib/Cargo.toml index cd57e6b..24a8dd8 100644 --- a/lib/Cargo.toml +++ b/lib/Cargo.toml @@ -16,7 +16,6 @@ bincode = "1.3.3" bitcoin = { version = "0.32.2", features = ["serde"] } blake3 = "1.4.1" borsh = { version = "1.3.1", features = ["derive"] } -bs58 = { version = "0.5.0", features = ["check"] } byteorder = "1.4.3" bytes = "1.4.0" ed25519-dalek = { version = "2.1.1", features = ["batch", "serde"] } diff --git a/lib/lib.rs b/lib/lib.rs index 06816b2..cc22245 100644 --- a/lib/lib.rs +++ b/lib/lib.rs @@ -15,13 +15,10 @@ pub mod wallet; pub use heed; -/// Format `str_dest` with the proper `s{sidechain_number}_` prefix and a +/// Format `b58_dest` with the proper `s{sidechain_number}_` prefix and a /// checksum postfix for calling createsidechaindeposit on mainchain. -pub fn format_deposit_address(this_sidechain: u8, str_dest: &str) -> String { - let deposit_address: String = format!("s{}_{}_", this_sidechain, str_dest); - let hash = sha256::digest(deposit_address.as_bytes()).to_string(); - let hash: String = hash[..6].into(); - format!("{}{}", deposit_address, hash) +pub fn format_deposit_address(dest: types::Address) -> String { + format!("s{}_{}", types::THIS_SIDECHAIN, dest.to_base58ck()) } // TODO: Add error log. diff --git a/lib/types/address.rs b/lib/types/address.rs index df9e341..bad6d8c 100644 --- a/lib/types/address.rs +++ b/lib/types/address.rs @@ -5,7 +5,7 @@ use serde_with::{DeserializeAs, DisplayFromStr}; #[derive(Debug, thiserror::Error)] pub enum AddressParseError { #[error("bs58 error")] - Bs58(#[from] bs58::decode::Error), + Bs58(#[from] bitcoin::base58::InvalidCharacterError), #[error("wrong address length {0} != 20")] WrongLength(usize), } @@ -17,10 +17,11 @@ pub struct Address(pub [u8; 20]); impl Address { pub fn to_base58(self) -> String { - bs58::encode(self.0) - .with_alphabet(bs58::Alphabet::BITCOIN) - .with_check() - .into_string() + bitcoin::base58::encode(&self.0) + } + + pub fn to_base58ck(self) -> String { + bitcoin::base58::encode_check(&self.0) } } @@ -45,10 +46,7 @@ impl From<[u8; 20]> for Address { impl std::str::FromStr for Address { type Err = AddressParseError; fn from_str(s: &str) -> Result { - let address = bs58::decode(s) - .with_alphabet(bs58::Alphabet::BITCOIN) - .with_check(None) - .into_vec()?; + let address = bitcoin::base58::decode(s)?; Ok(Address(address.try_into().map_err( |address: Vec| AddressParseError::WrongLength(address.len()), )?)) diff --git a/lib/types/proto.rs b/lib/types/proto.rs index 8236dce..5d4ed3d 100644 --- a/lib/types/proto.rs +++ b/lib/types/proto.rs @@ -921,15 +921,17 @@ pub mod mainchain { pub async fn create_deposit_tx( &mut self, - address: String, + address: crate::types::Address, value_sats: u64, fee_sats: u64, ) -> Result { let request = generated::CreateDepositTransactionRequest { - sidechain_id: THIS_SIDECHAIN as u32, - address, - value_sats, - fee_sats, + sidechain_id: Some(THIS_SIDECHAIN as u32), + address: Some(ConsensusHex::consensus_encode( + &address.0.to_vec(), + )), + value_sats: Some(value_sats), + fee_sats: Some(fee_sats), }; let generated::CreateDepositTransactionResponse { txid } = self .0 @@ -971,6 +973,7 @@ pub mod mainchain { ) -> Result<(), super::Error> { let request = generated::GenerateBlocksRequest { blocks: Some(blocks), + ack_all_proposals: true, }; let generated::GenerateBlocksResponse {} = self.0.generate_blocks(request).await?.into_inner(); diff --git a/proto b/proto index a5c78ea..1182ca0 160000 --- a/proto +++ b/proto @@ -1 +1 @@ -Subproject commit a5c78ea665ee7aae65fe4fd6441f8cb68d65a5c6 +Subproject commit 1182ca0f6990ab9b309a0f0d2dc27dc6e81b6c76 diff --git a/rpc-api/lib.rs b/rpc-api/lib.rs index 9ed5fe5..4b2d89d 100644 --- a/rpc-api/lib.rs +++ b/rpc-api/lib.rs @@ -51,6 +51,21 @@ impl ToSchema<'static> for BitcoinOutPointSchema { } } +struct BitcoinTxidSchema; + +impl PartialSchema for BitcoinTxidSchema { + fn schema() -> RefOr { + let obj = utoipa::openapi::Object::with_type(SchemaType::String); + RefOr::T(Schema::Object(obj)) + } +} + +impl ToSchema<'static> for BitcoinTxidSchema { + fn schema() -> (&'static str, RefOr) { + ("bitcoin.Txid", ::schema()) + } +} + struct OpenApiSchema; impl PartialSchema for OpenApiSchema { @@ -70,8 +85,8 @@ impl PartialSchema for SocketAddrSchema { } #[open_api(ref_schemas[ - Address, BitcoinAddrSchema, BitcoinOutPointSchema, MerkleRoot, OutPoint, Output, - OutputContent, Txid + Address, BitcoinAddrSchema, BitcoinOutPointSchema, BitcoinTxidSchema, + MerkleRoot, OutPoint, Output, OutputContent, Txid ])] #[rpc(client, server)] pub trait Rpc { @@ -88,6 +103,16 @@ pub trait Rpc { addr: SocketAddr, ) -> RpcResult<()>; + /// Deposit to address + #[open_api_method(output_schema(PartialSchema = "BitcoinTxidSchema"))] + #[method(name = "create_deposit")] + async fn create_deposit( + &self, + address: Address, + value_sats: u64, + fee_sats: u64, + ) -> RpcResult; + /// Format a deposit address #[method(name = "format_deposit_address")] async fn format_deposit_address(