From c5e42e328fae56116fdd1e15e72590a78c894f65 Mon Sep 17 00:00:00 2001 From: nagarajm22 Date: Thu, 23 May 2024 14:42:18 +0800 Subject: [PATCH 01/17] ocean rawtx api --- lib/ain-ocean/src/api/rawtx.rs | 2 +- lib/ain-ocean/src/model/mod.rs | 1 + lib/ain-ocean/src/model/raw_tx.rs | 9 +++++++++ 3 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 lib/ain-ocean/src/model/raw_tx.rs diff --git a/lib/ain-ocean/src/api/rawtx.rs b/lib/ain-ocean/src/api/rawtx.rs index d412441a68..e9497fbaca 100644 --- a/lib/ain-ocean/src/api/rawtx.rs +++ b/lib/ain-ocean/src/api/rawtx.rs @@ -1,5 +1,5 @@ use std::sync::Arc; - +use crate::model::RawTx; use axum::{ routing::{get, post}, Router, diff --git a/lib/ain-ocean/src/model/mod.rs b/lib/ain-ocean/src/model/mod.rs index 44afffc91c..99d9780f4b 100644 --- a/lib/ain-ocean/src/model/mod.rs +++ b/lib/ain-ocean/src/model/mod.rs @@ -12,6 +12,7 @@ mod poolswap; mod poolswap_aggregated; mod price_ticker; mod raw_block; +mod raw_tx; mod script_activity; mod script_aggregation; mod script_unspent; diff --git a/lib/ain-ocean/src/model/raw_tx.rs b/lib/ain-ocean/src/model/raw_tx.rs new file mode 100644 index 0000000000..94ba831992 --- /dev/null +++ b/lib/ain-ocean/src/model/raw_tx.rs @@ -0,0 +1,9 @@ +use rust_decimal::Decimal; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] +pub struct RawTx { + pub hex: String, + pub max_fee_rate: Option, +} From 180c77dcd045656300c9a1243fa36830821f8567 Mon Sep 17 00:00:00 2001 From: nagarajm22 Date: Thu, 23 May 2024 16:31:11 +0800 Subject: [PATCH 02/17] updated validate --- lib/ain-ocean/src/api/mod.rs | 2 +- lib/ain-ocean/src/api/rawtx.rs | 55 +++++++++++++++++++++++++++------- 2 files changed, 46 insertions(+), 11 deletions(-) diff --git a/lib/ain-ocean/src/api/mod.rs b/lib/ain-ocean/src/api/mod.rs index d3fce25083..2d217f6d9e 100644 --- a/lib/ain-ocean/src/api/mod.rs +++ b/lib/ain-ocean/src/api/mod.rs @@ -11,7 +11,7 @@ mod masternode; mod oracle; mod pool_pair; pub mod prices; -// mod rawtx; +mod rawtx; mod cache; pub mod common; mod path; diff --git a/lib/ain-ocean/src/api/rawtx.rs b/lib/ain-ocean/src/api/rawtx.rs index e9497fbaca..292ae5f48b 100644 --- a/lib/ain-ocean/src/api/rawtx.rs +++ b/lib/ain-ocean/src/api/rawtx.rs @@ -1,22 +1,56 @@ use std::sync::Arc; -use crate::model::RawTx; +use crate::{ + error::{ApiError, Error, NotFoundKind}, + model::RawTx, + repository::RepositoryOps, + storage::SortOrder, + Result, +}; +use super::{ + query::PaginationQuery, + response::{ApiPagedResponse, Response}, + AppContext, +}; use axum::{ - routing::{get, post}, - Router, + extract::{Path, Query}, + routing::{get,post}, + Extension, Router, }; use defichain_rpc::{Client, RpcApi}; -use super::path::Path; -async fn send_rawtx() -> String { - "Sending raw transaction".to_string() +use ain_macros::ocean_endpoint; + +#[ocean_endpoint] +async fn send_rawtx( + Path(tx): Path, + Extension(ctx): Extension>, +) -> Result> { + + Ok(Response::new("Sending raw transaction".to_string())) } -async fn test_rawtx() -> String { - "Testing raw transaction".to_string() +#[ocean_endpoint] +async fn test_rawtx( + Path(tx): Path, + Extension(ctx): Extension>, +) -> Result> { + +Ok(Response::new("Testing raw transaction".to_string())) +} +#[ocean_endpoint] +async fn get_rawtx( + Path(txid): Path, + Extension(ctx): Extension>, +) -> Result> { + format!("Details of raw transaction with txid {}", txid); + Ok(Response::new("Testing raw transaction".to_string())) } -async fn get_rawtx(Path(txid): Path) -> String { - format!("Details of raw transaction with txid {}", txid) +async fn validate(hex:String) { + if !hex.starts_with("040000000001") { + return + } + } pub fn router(ctx: Arc) -> Router { @@ -24,4 +58,5 @@ pub fn router(ctx: Arc) -> Router { .route("/send", post(send_rawtx)) .route("/test", get(test_rawtx)) .route("/:txid", get(get_rawtx)) + .layer(Extension(ctx)) } From 7aeb6cd812239d99ba66a9ce9cfd39d2acb7399e Mon Sep 17 00:00:00 2001 From: nagarajm22 Date: Sat, 1 Jun 2024 01:01:05 +0800 Subject: [PATCH 03/17] updated api for raw_trasaction --- lib/ain-ocean/src/api/mod.rs | 12 ++-- lib/ain-ocean/src/api/pool_pair/mod.rs | 3 +- lib/ain-ocean/src/api/pool_pair/price.rs | 3 +- lib/ain-ocean/src/api/rawtx.rs | 81 ++++++++++++++---------- lib/ain-ocean/src/model/mod.rs | 1 + lib/ain-ocean/src/model/raw_tx.rs | 4 +- 6 files changed, 58 insertions(+), 46 deletions(-) diff --git a/lib/ain-ocean/src/api/mod.rs b/lib/ain-ocean/src/api/mod.rs index 2d217f6d9e..f1707120df 100644 --- a/lib/ain-ocean/src/api/mod.rs +++ b/lib/ain-ocean/src/api/mod.rs @@ -4,18 +4,18 @@ use axum::{extract::Request, http::StatusCode, response::IntoResponse, Json, Rou // mod address; mod block; +mod cache; +pub mod common; mod fee; mod governance; mod loan; mod masternode; mod oracle; +mod path; mod pool_pair; pub mod prices; -mod rawtx; -mod cache; -pub mod common; -mod path; mod query; +mod rawtx; mod response; mod stats; mod tokens; @@ -80,10 +80,8 @@ pub async fn ocean_router( .nest("/masternodes", masternode::router(Arc::clone(&context))) .nest("/oracles", oracle::router(Arc::clone(&context))) .nest("/poolpairs", pool_pair::router(Arc::clone(&context))) - // .nest("/prices", prices::router(Arc::clone(&context))) - // .nest("/poolpairs", poolpairs::router(Arc::clone(&context))) .nest("/prices", prices::router(Arc::clone(&context))) - // .nest("/rawtx", rawtx::router(Arc::clone(&context))) + .nest("/rawtx", rawtx::router(Arc::clone(&context))) .nest("/stats", stats::router(Arc::clone(&context))) .nest("/tokens", tokens::router(Arc::clone(&context))) .nest("/transactions", transactions::router(Arc::clone(&context))) diff --git a/lib/ain-ocean/src/api/pool_pair/mod.rs b/lib/ain-ocean/src/api/pool_pair/mod.rs index ea2927678b..9448073184 100644 --- a/lib/ain-ocean/src/api/pool_pair/mod.rs +++ b/lib/ain-ocean/src/api/pool_pair/mod.rs @@ -20,6 +20,7 @@ use path::{ SwapPathsResponse, }; use petgraph::graphmap::UnGraphMap; +use price::DexPriceResponse; use rust_decimal::Decimal; use rust_decimal_macros::dec; use serde::{Deserialize, Serialize}; @@ -42,8 +43,6 @@ use crate::{ Result, TokenIdentifier, }; -use price::DexPriceResponse; - pub mod path; pub mod price; pub mod service; diff --git a/lib/ain-ocean/src/api/pool_pair/price.rs b/lib/ain-ocean/src/api/pool_pair/price.rs index e4d1bf6f32..1bdb408d16 100644 --- a/lib/ain-ocean/src/api/pool_pair/price.rs +++ b/lib/ain-ocean/src/api/pool_pair/price.rs @@ -1,10 +1,9 @@ -use serde::Serialize; use std::{collections::HashMap, sync::Arc}; use defichain_rpc::json::token::TokenInfo; +use serde::Serialize; use super::{path::get_best_path, AppContext}; - use crate::{ api::{ cache::{get_token_cached, list_token_cached}, diff --git a/lib/ain-ocean/src/api/rawtx.rs b/lib/ain-ocean/src/api/rawtx.rs index 292ae5f48b..4e6d8a0de9 100644 --- a/lib/ain-ocean/src/api/rawtx.rs +++ b/lib/ain-ocean/src/api/rawtx.rs @@ -1,62 +1,77 @@ -use std::sync::Arc; -use crate::{ - error::{ApiError, Error, NotFoundKind}, - model::RawTx, - repository::RepositoryOps, - storage::SortOrder, - Result, -}; -use super::{ - query::PaginationQuery, - response::{ApiPagedResponse, Response}, - AppContext, -}; +use std::{str::FromStr, sync::Arc}; + +use ain_macros::ocean_endpoint; use axum::{ - extract::{Path, Query}, - routing::{get,post}, + extract::Path, + response::Json, + routing::{get, post}, Extension, Router, }; -use defichain_rpc::{Client, RpcApi}; +use bitcoin::{consensus::encode::deserialize, Transaction, Txid}; +use defichain_rpc::{ + json::{GetTransactionResult, TestMempoolAcceptResult}, + RpcApi, +}; +use rust_decimal::Decimal; +use rust_decimal_macros::dec; -use ain_macros::ocean_endpoint; +use super::{response::Response, AppContext}; +use crate::{api::response::ApiPagedResponse, error::ApiError, model::RawTxDto, Result}; +const DEFAULT_MAX_FEE_RATE: Decimal = dec!(0.1); #[ocean_endpoint] async fn send_rawtx( - Path(tx): Path, + Path(tx): Path, Extension(ctx): Extension>, ) -> Result> { - - Ok(Response::new("Sending raw transaction".to_string())) + let mut tx = tx.clone(); + if tx.max_fee_rate.is_none() { + tx.max_fee_rate = Some(DEFAULT_MAX_FEE_RATE); + }; + let trx = defichain_rpc::RawTx::raw_hex(tx.hex); + let tx_hash = ctx.client.send_raw_transaction(trx).await?; + Ok(Response::new(tx_hash.to_string())) } #[ocean_endpoint] async fn test_rawtx( - Path(tx): Path, + Path(tx): Path, Extension(ctx): Extension>, -) -> Result> { - -Ok(Response::new("Testing raw transaction".to_string())) +) -> Result>> { + let mut tx = tx.clone(); + if tx.max_fee_rate.is_none() { + tx.max_fee_rate = Some(DEFAULT_MAX_FEE_RATE); + }; + let trx = defichain_rpc::RawTx::raw_hex(tx.hex); + let mempool_tx = ctx.client.test_mempool_accept(&[trx]).await?; + Ok(Response::new(mempool_tx)) } #[ocean_endpoint] -async fn get_rawtx( +async fn get_raw_tx( Path(txid): Path, Extension(ctx): Extension>, -) -> Result> { - format!("Details of raw transaction with txid {}", txid); - Ok(Response::new("Testing raw transaction".to_string())) +) -> Result> { + format!("Details of raw transaction with txid {}", txid); + let tx_hash = Txid::from_str(&txid)?; + let tx_result = ctx.client.get_transaction(&tx_hash, Some(true)).await?; + Ok(Response::new(tx_result)) } -async fn validate(hex:String) { - if !hex.starts_with("040000000001") { - return +async fn validate(hex: String) { + if !hex.starts_with("040000000001") { + return; + } + let buffer = hex::decode(hex).expect("Decoding failed"); + let transaction: Transaction = deserialize(&buffer).expect("Failed to deserialize transaction"); + if transaction.output.len() != 2 { + return; } - } pub fn router(ctx: Arc) -> Router { Router::new() .route("/send", post(send_rawtx)) .route("/test", get(test_rawtx)) - .route("/:txid", get(get_rawtx)) + // .route("/:txid", get(get_raw_tx)) .layer(Extension(ctx)) } diff --git a/lib/ain-ocean/src/model/mod.rs b/lib/ain-ocean/src/model/mod.rs index 99d9780f4b..9ad04ef098 100644 --- a/lib/ain-ocean/src/model/mod.rs +++ b/lib/ain-ocean/src/model/mod.rs @@ -34,6 +34,7 @@ pub use oracle_token_currency::*; pub use poolswap::*; pub use poolswap_aggregated::*; pub use price_ticker::*; +pub use raw_tx::*; // pub use raw_block::*; // pub use script_activity::*; // pub use script_aggregation::*; diff --git a/lib/ain-ocean/src/model/raw_tx.rs b/lib/ain-ocean/src/model/raw_tx.rs index 94ba831992..a20c4af5b0 100644 --- a/lib/ain-ocean/src/model/raw_tx.rs +++ b/lib/ain-ocean/src/model/raw_tx.rs @@ -1,9 +1,9 @@ use rust_decimal::Decimal; use serde::{Deserialize, Serialize}; -#[derive(Serialize, Deserialize, Debug, Default)] +#[derive(Serialize, Deserialize, Debug, Default, Clone)] #[serde(rename_all = "camelCase")] -pub struct RawTx { +pub struct RawTxDto { pub hex: String, pub max_fee_rate: Option, } From 2c3a5dfbd51d4003e145931397fea2d9cc67cb50 Mon Sep 17 00:00:00 2001 From: nagarajm22 Date: Tue, 4 Jun 2024 19:22:27 +0800 Subject: [PATCH 04/17] fixed get_raw_tx --- lib/ain-ocean/src/api/rawtx.rs | 66 ++++++++++++++++++++++++++++--- lib/ain-ocean/src/model/raw_tx.rs | 43 ++++++++++++++++++++ 2 files changed, 104 insertions(+), 5 deletions(-) diff --git a/lib/ain-ocean/src/api/rawtx.rs b/lib/ain-ocean/src/api/rawtx.rs index 4e6d8a0de9..2a5b73646c 100644 --- a/lib/ain-ocean/src/api/rawtx.rs +++ b/lib/ain-ocean/src/api/rawtx.rs @@ -9,14 +9,19 @@ use axum::{ }; use bitcoin::{consensus::encode::deserialize, Transaction, Txid}; use defichain_rpc::{ - json::{GetTransactionResult, TestMempoolAcceptResult}, + json::{Bip125Replaceable, GetTransactionResult, TestMempoolAcceptResult}, RpcApi, }; use rust_decimal::Decimal; use rust_decimal_macros::dec; use super::{response::Response, AppContext}; -use crate::{api::response::ApiPagedResponse, error::ApiError, model::RawTxDto, Result}; +use crate::{ + api::response::ApiPagedResponse, + error::ApiError, + model::{RawTransaction, RawTxDto, TransctionDetails, WalletTxInfo}, + Result, +}; const DEFAULT_MAX_FEE_RATE: Decimal = dec!(0.1); #[ocean_endpoint] @@ -50,11 +55,62 @@ async fn test_rawtx( async fn get_raw_tx( Path(txid): Path, Extension(ctx): Extension>, -) -> Result> { +) -> Result> { format!("Details of raw transaction with txid {}", txid); let tx_hash = Txid::from_str(&txid)?; let tx_result = ctx.client.get_transaction(&tx_hash, Some(true)).await?; - Ok(Response::new(tx_result)) + + let details: Vec = tx_result + .details + .into_iter() + .map(|detail| { + let address = match detail.address { + Some(addr) => Some(addr), + None => None, + }; + + TransctionDetails { + address: address, + category: detail.category.to_owned(), + amount: detail.amount.to_sat(), + label: detail.label, + vout: detail.vout, + fee: detail.fee.map(|f| f.to_sat()), + abandoned: detail.abandoned, + hex: hex::encode(&tx_result.hex), + blockhash: tx_result.info.blockhash.clone(), + confirmations: tx_result.info.confirmations, + time: tx_result.info.time, + blocktime: tx_result.info.blocktime, + } + }) + .collect(); + + let bip_125 = match tx_result.info.bip125_replaceable { + Bip125Replaceable::Yes => Some("Yes".to_string()), + Bip125Replaceable::No => Some("No".to_string()), + Bip125Replaceable::Unknown => Some("Unknown".to_string()), + }; + + let raw_tx = RawTransaction { + info: WalletTxInfo { + confirmations: tx_result.info.confirmations, + blockhash: tx_result.info.blockhash, + blockindex: tx_result.info.blockindex, + blocktime: tx_result.info.blocktime, + blockheight: tx_result.info.blockheight, + txid: tx_result.info.txid, + time: tx_result.info.time, + timereceived: tx_result.info.timereceived, + bip125_replaceable: bip_125, + wallet_conflicts: tx_result.info.wallet_conflicts, + }, + amount: tx_result.amount.to_sat(), + fee: tx_result.fee.map(|amount| amount.to_sat()), + details: details, + hex: tx_result.hex, + }; + Ok(Response::new(raw_tx)) } async fn validate(hex: String) { @@ -72,6 +128,6 @@ pub fn router(ctx: Arc) -> Router { Router::new() .route("/send", post(send_rawtx)) .route("/test", get(test_rawtx)) - // .route("/:txid", get(get_raw_tx)) + .route("/:txid", get(get_raw_tx)) .layer(Extension(ctx)) } diff --git a/lib/ain-ocean/src/model/raw_tx.rs b/lib/ain-ocean/src/model/raw_tx.rs index a20c4af5b0..e3fbb828dc 100644 --- a/lib/ain-ocean/src/model/raw_tx.rs +++ b/lib/ain-ocean/src/model/raw_tx.rs @@ -1,9 +1,52 @@ +use bitcoin::{address::NetworkUnchecked, Address, BlockHash, Txid}; +use defichain_rpc::json::GetTransactionResultDetailCategory; use rust_decimal::Decimal; use serde::{Deserialize, Serialize}; +use super::{TransactionVin, TransactionVout}; + #[derive(Serialize, Deserialize, Debug, Default, Clone)] #[serde(rename_all = "camelCase")] pub struct RawTxDto { pub hex: String, pub max_fee_rate: Option, } + +#[derive(Serialize, Deserialize, Debug)] +pub struct TransctionDetails { + pub address: Option>, + pub category: GetTransactionResultDetailCategory, + pub amount: i64, + pub label: Option, + pub vout: u32, + pub fee: Option, + pub abandoned: Option, + pub hex: String, + pub blockhash: Option, + pub confirmations: i32, + pub time: u64, + pub blocktime: Option, +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct WalletTxInfo { + pub confirmations: i32, + pub blockhash: Option, + pub blockindex: Option, + pub blocktime: Option, + pub blockheight: Option, + pub txid: Txid, + pub time: u64, + pub timereceived: u64, + pub bip125_replaceable: Option, + pub wallet_conflicts: Vec, +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct RawTransaction { + pub info: WalletTxInfo, + pub amount: i64, + pub fee: Option, + pub details: Vec, + pub hex: Vec, +} From 72005351ebb604c1e0e768618c33c8b4f20b153b Mon Sep 17 00:00:00 2001 From: nagarajm22 Date: Mon, 10 Jun 2024 14:06:34 +0800 Subject: [PATCH 05/17] updated request to json rawtx --- lib/Cargo.lock | 203 +++++++++++++++--------------- lib/ain-ocean/src/api/rawtx.rs | 129 +++++++++++-------- lib/ain-ocean/src/error.rs | 6 + lib/ain-ocean/src/lib.rs | 3 +- lib/ain-ocean/src/model/raw_tx.rs | 29 +++-- 5 files changed, 208 insertions(+), 162 deletions(-) diff --git a/lib/Cargo.lock b/lib/Cargo.lock index b944da3bdd..f5cf509dea 100644 --- a/lib/Cargo.lock +++ b/lib/Cargo.lock @@ -23,11 +23,11 @@ dependencies = [ [[package]] name = "addr2line" -version = "0.21.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" dependencies = [ - "gimli 0.28.1", + "gimli 0.29.0", ] [[package]] @@ -196,7 +196,7 @@ dependencies = [ "evm", "heck 0.4.1", "hex", - "hyper 0.14.28", + "hyper 0.14.29", "jsonrpsee 0.16.3", "jsonrpsee-server", "lazy_static", @@ -217,7 +217,7 @@ dependencies = [ "serde_json", "serde_with", "sha3", - "syn 2.0.65", + "syn 2.0.66", "tokio", "tonic", "tonic-build", @@ -231,7 +231,7 @@ version = "0.1.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.65", + "syn 2.0.66", ] [[package]] @@ -253,7 +253,7 @@ dependencies = [ "env_logger", "futures", "hex", - "hyper 0.14.28", + "hyper 0.14.29", "indexmap 2.2.6", "json", "jsonrpc-async", @@ -445,9 +445,9 @@ dependencies = [ [[package]] name = "async-compression" -version = "0.4.10" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c90a406b4495d129f00461241616194cb8a032c8d1c53c657f0961d5f8e0498" +checksum = "cd066d0b4ef8ecb03a55319dc13aa6910616d0f44008a045bb1835af830abff5" dependencies = [ "brotli", "flate2", @@ -467,7 +467,7 @@ checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" dependencies = [ "proc-macro2", "quote", - "syn 2.0.65", + "syn 2.0.66", ] [[package]] @@ -489,7 +489,7 @@ checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" dependencies = [ "proc-macro2", "quote", - "syn 2.0.65", + "syn 2.0.66", ] [[package]] @@ -511,7 +511,7 @@ dependencies = [ "futures-util", "http 0.2.12", "http-body 0.4.6", - "hyper 0.14.28", + "hyper 0.14.29", "itoa", "matchit", "memchr", @@ -608,21 +608,21 @@ dependencies = [ "heck 0.4.1", "proc-macro2", "quote", - "syn 2.0.65", + "syn 2.0.66", ] [[package]] name = "backtrace" -version = "0.3.71" +version = "0.3.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" +checksum = "17c6a35df3749d2e8bb1b7b21a976d82b15548788d2735b9d82f329268f71a11" dependencies = [ - "addr2line 0.21.0", + "addr2line 0.22.0", "cc", "cfg-if", "libc", "miniz_oxide", - "object 0.32.2", + "object 0.35.0", "rustc-demangle", ] @@ -717,7 +717,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.65", + "syn 2.0.66", ] [[package]] @@ -860,9 +860,9 @@ dependencies = [ [[package]] name = "borsh" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbe5b10e214954177fb1dc9fbd20a1a2608fe99e6c832033bdc7cea287a20d77" +checksum = "a6362ed55def622cddc70a4746a68554d7b687713770de539e59a739b249f8ed" dependencies = [ "borsh-derive", "cfg_aliases", @@ -870,15 +870,15 @@ dependencies = [ [[package]] name = "borsh-derive" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7a8646f94ab393e43e8b35a2558b1624bed28b97ee09c5d15456e3c9463f46d" +checksum = "c3ef8005764f53cd4dca619f5bf64cafd4664dada50ece25e4d81de54c80cc0b" dependencies = [ "once_cell", "proc-macro-crate 3.1.0", "proc-macro2", "quote", - "syn 2.0.65", + "syn 2.0.66", "syn_derive", ] @@ -907,9 +907,9 @@ dependencies = [ [[package]] name = "brotli-decompressor" -version = "4.0.0" +version = "4.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6221fe77a248b9117d431ad93761222e1cf8ff282d9d1d5d9f53d6299a1cf76" +checksum = "9a45bd2e4095a8b518033b128020dd4a55aab1c0a381ba4404a472630f4bc362" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -1077,9 +1077,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cfg_aliases" -version = "0.1.1" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "chrono" @@ -1108,9 +1108,9 @@ dependencies = [ [[package]] name = "clang-sys" -version = "1.7.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67523a3b4be3ce1989d607a828d036249522dd9c1c8de7f4dd2dae43a37369d1" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" dependencies = [ "glob", "libc", @@ -1163,7 +1163,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.65", + "syn 2.0.66", ] [[package]] @@ -1190,9 +1190,9 @@ checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" [[package]] name = "const-hex" -version = "1.11.4" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ff96486ccc291d36a958107caf2c0af8c78c0af7d31ae2f35ce055130de1a6" +checksum = "94fb8a24a26d37e1ffd45343323dc9fe6654ceea44c12f2fcb3d7ac29e610bc6" dependencies = [ "cfg-if", "cpufeatures", @@ -1395,7 +1395,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.65", + "syn 2.0.66", ] [[package]] @@ -1422,7 +1422,7 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 2.0.65", + "syn 2.0.66", ] [[package]] @@ -1434,7 +1434,7 @@ dependencies = [ "codespan-reporting", "proc-macro2", "quote", - "syn 2.0.65", + "syn 2.0.66", ] [[package]] @@ -1451,7 +1451,7 @@ checksum = "928bc249a7e3cd554fd2e8e08a426e9670c50bbfc9a621653cfa9accc9641783" dependencies = [ "proc-macro2", "quote", - "syn 2.0.65", + "syn 2.0.66", ] [[package]] @@ -1499,7 +1499,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.11.1", - "syn 2.0.65", + "syn 2.0.66", ] [[package]] @@ -1521,13 +1521,13 @@ checksum = "733cabb43482b1a1b53eee8583c2b9e8684d592215ea83efd305dd31bc2f0178" dependencies = [ "darling_core 0.20.9", "quote", - "syn 2.0.65", + "syn 2.0.66", ] [[package]] name = "defichain-rpc" version = "0.18.0" -source = "git+https://github.com/defich/rust-defichain-rpc.git#ef716fe7080188ddfe5674e88a3aaed9e2c0497d" +source = "git+https://github.com/defich/rust-defichain-rpc.git#9d0a769b11c24b855843ecb6dbe556a3b30dfcdf" dependencies = [ "async-trait", "defichain-rpc-json", @@ -1540,7 +1540,7 @@ dependencies = [ [[package]] name = "defichain-rpc-json" version = "0.18.0" -source = "git+https://github.com/defich/rust-defichain-rpc.git#ef716fe7080188ddfe5674e88a3aaed9e2c0497d" +source = "git+https://github.com/defich/rust-defichain-rpc.git#9d0a769b11c24b855843ecb6dbe556a3b30dfcdf" dependencies = [ "bitcoin", "serde", @@ -2182,7 +2182,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.65", + "syn 2.0.66", ] [[package]] @@ -2288,9 +2288,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.28.1" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" [[package]] name = "glob" @@ -2581,9 +2581,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.28" +version = "0.14.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" +checksum = "f361cde2f109281a220d4307746cdfd5ee3f410da58a70377762396775634b33" dependencies = [ "bytes", "futures-channel", @@ -2630,7 +2630,7 @@ checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" dependencies = [ "futures-util", "http 0.2.12", - "hyper 0.14.28", + "hyper 0.14.29", "log", "rustls", "rustls-native-certs", @@ -2645,7 +2645,7 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" dependencies = [ - "hyper 0.14.28", + "hyper 0.14.29", "pin-project-lite", "tokio", "tokio-io-timeout", @@ -2653,9 +2653,9 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.3" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca38ef113da30126bbff9cd1705f9273e15d45498615d138b0c20279ac7a76aa" +checksum = "7b875924a60b96e5d7b9ae7b066540b1dd1cbd90d1828f54c92e02a283351c56" dependencies = [ "bytes", "futures-util", @@ -2663,7 +2663,6 @@ dependencies = [ "http-body 1.0.0", "hyper 1.3.1", "pin-project-lite", - "socket2", "tokio", ] @@ -2928,7 +2927,7 @@ dependencies = [ "futures-channel", "futures-util", "globset", - "hyper 0.14.28", + "hyper 0.14.29", "jsonrpsee-types 0.16.3", "parking_lot", "rand 0.8.5", @@ -2951,7 +2950,7 @@ dependencies = [ "async-trait", "beef", "futures-util", - "hyper 0.14.28", + "hyper 0.14.29", "jsonrpsee-types 0.18.2", "serde", "serde_json", @@ -2967,7 +2966,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e5f9fabdd5d79344728521bb65e3106b49ec405a78b66fbff073b72b389fa43" dependencies = [ "async-trait", - "hyper 0.14.28", + "hyper 0.14.29", "hyper-rustls", "jsonrpsee-core 0.16.3", "jsonrpsee-types 0.16.3", @@ -2986,7 +2985,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1705c65069729e3dccff6fd91ee431d5d31cabcf00ce68a62a2c6435ac713af9" dependencies = [ "async-trait", - "hyper 0.14.28", + "hyper 0.14.29", "hyper-rustls", "jsonrpsee-core 0.18.2", "jsonrpsee-types 0.18.2", @@ -3020,7 +3019,7 @@ dependencies = [ "futures-channel", "futures-util", "http 0.2.12", - "hyper 0.14.28", + "hyper 0.14.29", "jsonrpsee-core 0.16.3", "jsonrpsee-types 0.16.3", "serde", @@ -3267,9 +3266,9 @@ dependencies = [ [[package]] name = "libz-sys" -version = "1.1.16" +version = "1.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e143b5e666b2695d28f6bca6497720813f699c9602dd7f5cac91008b8ada7f9" +checksum = "c15da26e5af7e25c90b37a2d75cdbf940cf4a55316de9d84c679c9b8bfabf82e" dependencies = [ "cc", "pkg-config", @@ -3655,7 +3654,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2", "quote", - "syn 2.0.65", + "syn 2.0.66", ] [[package]] @@ -3672,9 +3671,9 @@ dependencies = [ [[package]] name = "object" -version = "0.32.2" +version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +checksum = "b8ec7ab813848ba4522158d5517a6093db1ded27575b070f4177b8d12b41db5e" dependencies = [ "memchr", ] @@ -3763,9 +3762,9 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.12.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e4af0ca4f6caed20e900d564c242b8e5d4903fdacf31d3daf527b66fe6f42fb" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", "parking_lot_core", @@ -3882,7 +3881,7 @@ dependencies = [ "phf_shared 0.11.2", "proc-macro2", "quote", - "syn 2.0.65", + "syn 2.0.66", ] [[package]] @@ -3920,7 +3919,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.65", + "syn 2.0.66", ] [[package]] @@ -3992,7 +3991,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f12335488a2f3b0a83b14edad48dca9879ce89b2edd10e80237e4e852dd645e" dependencies = [ "proc-macro2", - "syn 2.0.65", + "syn 2.0.66", ] [[package]] @@ -4054,9 +4053,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.83" +version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b33eb56c327dec362a9e55b3ad14f9d2f0904fb5a5b03b513ab5465399e9f43" +checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23" dependencies = [ "unicode-ident", ] @@ -4365,7 +4364,7 @@ checksum = "bcc303e793d3734489387d205e9b186fac9c6cfacedd98cbb2e8a5943595f3e6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.65", + "syn 2.0.66", ] [[package]] @@ -4444,7 +4443,7 @@ dependencies = [ "h2", "http 0.2.12", "http-body 0.4.6", - "hyper 0.14.28", + "hyper 0.14.29", "hyper-rustls", "ipnet", "js-sys", @@ -4968,22 +4967,22 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.202" +version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "226b61a0d411b2ba5ff6d7f73a476ac4f8bb900373459cd00fab8512828ba395" +checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.202" +version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6048858004bcff69094cd972ed40a32500f153bd3be9f716b2eed2e8217c4838" +checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" dependencies = [ "proc-macro2", "quote", - "syn 2.0.65", + "syn 2.0.66", ] [[package]] @@ -5046,7 +5045,7 @@ dependencies = [ "darling 0.20.9", "proc-macro2", "quote", - "syn 2.0.65", + "syn 2.0.66", ] [[package]] @@ -5307,7 +5306,7 @@ checksum = "f12dae7cf6c1e825d13ffd4ce16bd9309db7c539929d0302b4443ed451a9f4e5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.65", + "syn 2.0.66", ] [[package]] @@ -5401,7 +5400,7 @@ dependencies = [ "proc-macro-crate 1.3.1", "proc-macro2", "quote", - "syn 2.0.65", + "syn 2.0.66", ] [[package]] @@ -5551,9 +5550,9 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "statrs" -version = "0.16.0" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d08e5e1748192713cc281da8b16924fb46be7b0c2431854eadc785823e5696e" +checksum = "b35a062dbadac17a42e0fc64c27f419b25d6fae98572eb43c8814c9e873d7721" dependencies = [ "approx", "lazy_static", @@ -5628,15 +5627,15 @@ dependencies = [ [[package]] name = "strum_macros" -version = "0.26.2" +version = "0.26.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6cf59daf282c0a494ba14fd21610a0325f9f90ec9d1231dea26bcb1d696c946" +checksum = "f7993a8e3a9e88a00351486baae9522c91b123a088f76469e5bd5cc17198ea87" dependencies = [ - "heck 0.4.1", + "heck 0.5.0", "proc-macro2", "quote", "rustversion", - "syn 2.0.65", + "syn 2.0.66", ] [[package]] @@ -5704,9 +5703,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.65" +version = "2.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2863d96a84c6439701d7a38f9de935ec562c8832cc55d1dde0f513b52fad106" +checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" dependencies = [ "proc-macro2", "quote", @@ -5722,7 +5721,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.65", + "syn 2.0.66", ] [[package]] @@ -5838,7 +5837,7 @@ checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" dependencies = [ "proc-macro2", "quote", - "syn 2.0.65", + "syn 2.0.66", ] [[package]] @@ -5936,9 +5935,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.37.0" +version = "1.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" +checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a" dependencies = [ "backtrace", "bytes", @@ -5965,13 +5964,13 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" +checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.65", + "syn 2.0.66", ] [[package]] @@ -6052,7 +6051,7 @@ dependencies = [ "h2", "http 0.2.12", "http-body 0.4.6", - "hyper 0.14.28", + "hyper 0.14.29", "hyper-timeout", "percent-encoding", "pin-project", @@ -6160,7 +6159,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.65", + "syn 2.0.66", ] [[package]] @@ -6517,7 +6516,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.65", + "syn 2.0.66", "wasm-bindgen-shared", ] @@ -6551,7 +6550,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.65", + "syn 2.0.66", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -6734,9 +6733,9 @@ dependencies = [ [[package]] name = "wide" -version = "0.7.20" +version = "0.7.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21e005a4cc35784183a9e39cb22e9a9c46353ef6a7f113fd8d36ddc58c15ef3c" +checksum = "2c5cb32c74fe55350a3272ba792f050613e692253ae0d89ad5d83eb0dcea15e1" dependencies = [ "bytemuck", "safe_arch", @@ -7038,14 +7037,14 @@ checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.65", + "syn 2.0.66", ] [[package]] name = "zeroize" -version = "1.7.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" dependencies = [ "zeroize_derive", ] @@ -7058,7 +7057,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.65", + "syn 2.0.66", ] [[package]] diff --git a/lib/ain-ocean/src/api/rawtx.rs b/lib/ain-ocean/src/api/rawtx.rs index 2a5b73646c..4985d59535 100644 --- a/lib/ain-ocean/src/api/rawtx.rs +++ b/lib/ain-ocean/src/api/rawtx.rs @@ -2,55 +2,86 @@ use std::{str::FromStr, sync::Arc}; use ain_macros::ocean_endpoint; use axum::{ - extract::Path, - response::Json, + extract::{Json, Path}, + http::StatusCode, routing::{get, post}, Extension, Router, }; use bitcoin::{consensus::encode::deserialize, Transaction, Txid}; -use defichain_rpc::{ - json::{Bip125Replaceable, GetTransactionResult, TestMempoolAcceptResult}, - RpcApi, +use defichain_rpc::{json::Bip125Replaceable, RpcApi}; +use rust_decimal::{ + prelude::{FromPrimitive, ToPrimitive}, + Decimal, }; -use rust_decimal::Decimal; -use rust_decimal_macros::dec; -use super::{response::Response, AppContext}; +use super::{fee, response::Response, AppContext}; use crate::{ - api::response::ApiPagedResponse, error::ApiError, - model::{RawTransaction, RawTxDto, TransctionDetails, WalletTxInfo}, - Result, + model::{ + default_max_fee_rate, MempoolAcceptResult, RawTransaction, RawTxDto, TransctionDetails, + WalletTxInfo, + }, + ApiResult, Error, Result, }; -const DEFAULT_MAX_FEE_RATE: Decimal = dec!(0.1); #[ocean_endpoint] async fn send_rawtx( - Path(tx): Path, Extension(ctx): Extension>, + Json(raw_tx_dto): Json, ) -> Result> { - let mut tx = tx.clone(); - if tx.max_fee_rate.is_none() { - tx.max_fee_rate = Some(DEFAULT_MAX_FEE_RATE); - }; - let trx = defichain_rpc::RawTx::raw_hex(tx.hex); - let tx_hash = ctx.client.send_raw_transaction(trx).await?; - Ok(Response::new(tx_hash.to_string())) + let max_fee = default_max_fee_rate(); + if raw_tx_dto.max_fee_rate.is_some() { + let fees = raw_tx_dto + .max_fee_rate + .and_then(Decimal::from_u64) + .map(|d| d.to_u64()) + .flatten(); + } + let trx = defichain_rpc::RawTx::raw_hex(raw_tx_dto.hex); + match ctx.client.send_raw_transaction(trx, max_fee).await { + Ok(tx_hash) => Ok(Response::new(tx_hash.to_string())), + Err(e) => { + eprintln!("Failed to send raw transaction: {:?}", e); + Err(Error::RpcError(e)) + } + } } - #[ocean_endpoint] async fn test_rawtx( - Path(tx): Path, Extension(ctx): Extension>, -) -> Result>> { - let mut tx = tx.clone(); - if tx.max_fee_rate.is_none() { - tx.max_fee_rate = Some(DEFAULT_MAX_FEE_RATE); - }; - let trx = defichain_rpc::RawTx::raw_hex(tx.hex); - let mempool_tx = ctx.client.test_mempool_accept(&[trx]).await?; - Ok(Response::new(mempool_tx)) + Json(raw_tx_dto): Json, +) -> Result>> { + let trx = defichain_rpc::RawTx::raw_hex(raw_tx_dto.hex); + let max_fee = default_max_fee_rate(); + if raw_tx_dto.max_fee_rate.is_some() { + let fees = raw_tx_dto + .max_fee_rate + .and_then(Decimal::from_u64) + .map(|d| d.to_u64()) + .flatten(); + } + + match ctx.client.test_mempool_accept(&[trx], max_fee).await { + Ok(mempool_tx) => { + let results = mempool_tx + .into_iter() + .map(|tx_result| MempoolAcceptResult { + txid: tx_result.txid, + allowed: tx_result.allowed, + reject_reason: tx_result.reject_reason, + vsize: tx_result.vsize, + fees: tx_result.fees.map(|f| f.base), + }) + .collect::>(); + Ok(Response::new(results)) + } + Err(e) => { + eprintln!("Failed to send raw transaction: {:?}", e); + Err(Error::RpcError(e)) + } + } } + #[ocean_endpoint] async fn get_raw_tx( Path(txid): Path, @@ -59,30 +90,23 @@ async fn get_raw_tx( format!("Details of raw transaction with txid {}", txid); let tx_hash = Txid::from_str(&txid)?; let tx_result = ctx.client.get_transaction(&tx_hash, Some(true)).await?; - + println!("the txid : {:?}", tx_result); let details: Vec = tx_result .details .into_iter() - .map(|detail| { - let address = match detail.address { - Some(addr) => Some(addr), - None => None, - }; - - TransctionDetails { - address: address, - category: detail.category.to_owned(), - amount: detail.amount.to_sat(), - label: detail.label, - vout: detail.vout, - fee: detail.fee.map(|f| f.to_sat()), - abandoned: detail.abandoned, - hex: hex::encode(&tx_result.hex), - blockhash: tx_result.info.blockhash.clone(), - confirmations: tx_result.info.confirmations, - time: tx_result.info.time, - blocktime: tx_result.info.blocktime, - } + .map(|detail| TransctionDetails { + address: detail.address.map(|addr| addr), + category: detail.category.to_owned(), + amount: detail.amount.to_sat(), + label: detail.label, + vout: detail.vout, + fee: detail.fee.map(|f| f.to_sat()), + abandoned: detail.abandoned, + hex: hex::encode(&tx_result.hex), + blockhash: tx_result.info.blockhash, + confirmations: tx_result.info.confirmations, + time: tx_result.info.time, + blocktime: tx_result.info.blocktime, }) .collect(); @@ -125,9 +149,10 @@ async fn validate(hex: String) { } pub fn router(ctx: Arc) -> Router { + println!("{:?}", ctx.network); Router::new() .route("/send", post(send_rawtx)) - .route("/test", get(test_rawtx)) + .route("/test", post(test_rawtx)) .route("/:txid", get(get_raw_tx)) .layer(Extension(ctx)) } diff --git a/lib/ain-ocean/src/error.rs b/lib/ain-ocean/src/error.rs index 617b1e6c06..97c24f0539 100644 --- a/lib/ain-ocean/src/error.rs +++ b/lib/ain-ocean/src/error.rs @@ -154,3 +154,9 @@ impl From<&str> for Error { Error::Other(format_err!("{s}")) } } +impl IntoResponse for Error { + fn into_response(self) -> Response { + let error_message = format!("Internal server error: {}", self); + (StatusCode::INTERNAL_SERVER_ERROR, error_message).into_response() + } +} diff --git a/lib/ain-ocean/src/lib.rs b/lib/ain-ocean/src/lib.rs index 9c75b2712e..70ccf92a0c 100644 --- a/lib/ain-ocean/src/lib.rs +++ b/lib/ain-ocean/src/lib.rs @@ -5,7 +5,7 @@ pub mod network; use std::{path::PathBuf, sync::Arc}; pub use api::ocean_router; -use error::Error; +use error::{ApiError, Error}; pub use indexer::{ index_block, invalidate_block, oracle::invalidate_oracle_interval, transaction::index_transaction, tx_result, PoolCreationHeight, @@ -34,6 +34,7 @@ pub mod storage; use crate::storage::ocean_store::OceanStore; pub type Result = std::result::Result; +pub type ApiResult = std::result::Result; lazy_static::lazy_static! { // Global services exposed by the library diff --git a/lib/ain-ocean/src/model/raw_tx.rs b/lib/ain-ocean/src/model/raw_tx.rs index e3fbb828dc..80f9dc9731 100644 --- a/lib/ain-ocean/src/model/raw_tx.rs +++ b/lib/ain-ocean/src/model/raw_tx.rs @@ -1,15 +1,21 @@ -use bitcoin::{address::NetworkUnchecked, Address, BlockHash, Txid}; +use std::str::FromStr; + +use bitcoin::{address::NetworkUnchecked, Address, Amount, BlockHash, Txid}; use defichain_rpc::json::GetTransactionResultDetailCategory; -use rust_decimal::Decimal; +use rust_decimal::{prelude::ToPrimitive, Decimal}; use serde::{Deserialize, Serialize}; - -use super::{TransactionVin, TransactionVout}; - -#[derive(Serialize, Deserialize, Debug, Default, Clone)] +#[derive(Serialize, Deserialize, Default, Clone)] #[serde(rename_all = "camelCase")] pub struct RawTxDto { pub hex: String, - pub max_fee_rate: Option, + #[serde(default = "default_max_fee_rate")] + pub max_fee_rate: Option, +} + +pub fn default_max_fee_rate() -> Option { + let default_max_fee_rate = Decimal::from_str("0.1").expect("Invalid decimal"); + let default_fee = default_max_fee_rate.to_u64(); + default_fee } #[derive(Serialize, Deserialize, Debug)] @@ -50,3 +56,12 @@ pub struct RawTransaction { pub details: Vec, pub hex: Vec, } + +#[derive(Serialize, Deserialize, Debug)] +pub struct MempoolAcceptResult { + pub txid: Txid, + pub allowed: bool, + pub reject_reason: Option, + pub vsize: Option, + pub fees: Option, +} From 2dd45181bb24b6bb9f8009f21adac945bbe10962 Mon Sep 17 00:00:00 2001 From: nagarajm22 Date: Wed, 12 Jun 2024 15:58:43 +0800 Subject: [PATCH 06/17] updated raw tx api --- lib/ain-ocean/src/api/rawtx.rs | 35 +++++++++++++------------------ lib/ain-ocean/src/model/raw_tx.rs | 10 ++++----- 2 files changed, 18 insertions(+), 27 deletions(-) diff --git a/lib/ain-ocean/src/api/rawtx.rs b/lib/ain-ocean/src/api/rawtx.rs index 4985d59535..79841d9fe8 100644 --- a/lib/ain-ocean/src/api/rawtx.rs +++ b/lib/ain-ocean/src/api/rawtx.rs @@ -28,18 +28,16 @@ use crate::{ async fn send_rawtx( Extension(ctx): Extension>, Json(raw_tx_dto): Json, -) -> Result> { - let max_fee = default_max_fee_rate(); - if raw_tx_dto.max_fee_rate.is_some() { - let fees = raw_tx_dto - .max_fee_rate - .and_then(Decimal::from_u64) - .map(|d| d.to_u64()) - .flatten(); +) -> Result { + let mut max_fee = Some(default_max_fee_rate().unwrap().to_sat()); + if let Some(fee_rate) = raw_tx_dto.max_fee_rate { + let sat_per_bitcoin = Decimal::new(100_000_000, 0); + let fee_in_satoshis = fee_rate * sat_per_bitcoin; + max_fee = fee_in_satoshis.round().to_u64(); } let trx = defichain_rpc::RawTx::raw_hex(raw_tx_dto.hex); match ctx.client.send_raw_transaction(trx, max_fee).await { - Ok(tx_hash) => Ok(Response::new(tx_hash.to_string())), + Ok(tx_hash) => Ok(tx_hash.to_string()), Err(e) => { eprintln!("Failed to send raw transaction: {:?}", e); Err(Error::RpcError(e)) @@ -52,15 +50,12 @@ async fn test_rawtx( Json(raw_tx_dto): Json, ) -> Result>> { let trx = defichain_rpc::RawTx::raw_hex(raw_tx_dto.hex); - let max_fee = default_max_fee_rate(); - if raw_tx_dto.max_fee_rate.is_some() { - let fees = raw_tx_dto - .max_fee_rate - .and_then(Decimal::from_u64) - .map(|d| d.to_u64()) - .flatten(); + let mut max_fee = Some(default_max_fee_rate().unwrap().to_sat()); + if let Some(fee_rate) = raw_tx_dto.max_fee_rate { + let sat_per_bitcoin = Decimal::new(100_000_000, 0); + let fee_in_satoshis = fee_rate * sat_per_bitcoin; + max_fee = fee_in_satoshis.round().to_u64(); } - match ctx.client.test_mempool_accept(&[trx], max_fee).await { Ok(mempool_tx) => { let results = mempool_tx @@ -84,13 +79,11 @@ async fn test_rawtx( #[ocean_endpoint] async fn get_raw_tx( - Path(txid): Path, + Path((txid, verbose)): Path<(String, bool)>, Extension(ctx): Extension>, ) -> Result> { - format!("Details of raw transaction with txid {}", txid); let tx_hash = Txid::from_str(&txid)?; - let tx_result = ctx.client.get_transaction(&tx_hash, Some(true)).await?; - println!("the txid : {:?}", tx_result); + let tx_result = ctx.client.get_transaction(&tx_hash, Some(verbose)).await?; let details: Vec = tx_result .details .into_iter() diff --git a/lib/ain-ocean/src/model/raw_tx.rs b/lib/ain-ocean/src/model/raw_tx.rs index 80f9dc9731..14af932040 100644 --- a/lib/ain-ocean/src/model/raw_tx.rs +++ b/lib/ain-ocean/src/model/raw_tx.rs @@ -8,14 +8,12 @@ use serde::{Deserialize, Serialize}; #[serde(rename_all = "camelCase")] pub struct RawTxDto { pub hex: String, - #[serde(default = "default_max_fee_rate")] - pub max_fee_rate: Option, + pub max_fee_rate: Option, } -pub fn default_max_fee_rate() -> Option { - let default_max_fee_rate = Decimal::from_str("0.1").expect("Invalid decimal"); - let default_fee = default_max_fee_rate.to_u64(); - default_fee +pub fn default_max_fee_rate() -> Option { + let default_max_fee_rate = Amount::from_btc(0.1).unwrap_or_default(); + Some(default_max_fee_rate) } #[derive(Serialize, Deserialize, Debug)] From 467d6ae03f404eb0172e5540eddaead083ed667c Mon Sep 17 00:00:00 2001 From: nagarajm22 Date: Wed, 12 Jun 2024 16:26:53 +0800 Subject: [PATCH 07/17] added validate to rawtx --- lib/ain-ocean/src/api/rawtx.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/ain-ocean/src/api/rawtx.rs b/lib/ain-ocean/src/api/rawtx.rs index 79841d9fe8..fb2ba4faff 100644 --- a/lib/ain-ocean/src/api/rawtx.rs +++ b/lib/ain-ocean/src/api/rawtx.rs @@ -29,6 +29,7 @@ async fn send_rawtx( Extension(ctx): Extension>, Json(raw_tx_dto): Json, ) -> Result { + validate(raw_tx_dto.hex.clone()).await; let mut max_fee = Some(default_max_fee_rate().unwrap().to_sat()); if let Some(fee_rate) = raw_tx_dto.max_fee_rate { let sat_per_bitcoin = Decimal::new(100_000_000, 0); From cabd88d43a736948303287b0820bd9cb104d0ef9 Mon Sep 17 00:00:00 2001 From: nagarajm22 Date: Fri, 14 Jun 2024 11:40:34 +0800 Subject: [PATCH 08/17] update send_rawtx --- lib/ain-ocean/src/api/pool_pair/service.rs | 2 +- lib/ain-ocean/src/api/rawtx.rs | 23 ++++++++++++---------- lib/ain-ocean/src/error.rs | 2 ++ 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/lib/ain-ocean/src/api/pool_pair/service.rs b/lib/ain-ocean/src/api/pool_pair/service.rs index b8b93fd6dd..d6d317c879 100644 --- a/lib/ain-ocean/src/api/pool_pair/service.rs +++ b/lib/ain-ocean/src/api/pool_pair/service.rs @@ -1,5 +1,6 @@ use std::{collections::HashMap, str::FromStr, sync::Arc}; +use ain_dftx::{deserialize, pool::CompositeSwap, DfTx, Stack}; use anyhow::{format_err, Context}; use bitcoin::Txid; use defichain_rpc::{json::poolpair::PoolPairInfo, AccountRPC, BlockchainRPC}; @@ -21,7 +22,6 @@ use crate::{ storage::SortOrder, Result, }; -use ain_dftx::{deserialize, pool::CompositeSwap, DfTx, Stack}; #[allow(clippy::upper_case_acronyms)] #[derive(Serialize, Deserialize, Debug, Clone)] diff --git a/lib/ain-ocean/src/api/rawtx.rs b/lib/ain-ocean/src/api/rawtx.rs index fb2ba4faff..67b6d7eff3 100644 --- a/lib/ain-ocean/src/api/rawtx.rs +++ b/lib/ain-ocean/src/api/rawtx.rs @@ -7,8 +7,11 @@ use axum::{ routing::{get, post}, Extension, Router, }; -use bitcoin::{consensus::encode::deserialize, Transaction, Txid}; -use defichain_rpc::{json::Bip125Replaceable, RpcApi}; +use bitcoin::{consensus::encode::deserialize, Txid}; +use defichain_rpc::{ + json::{blockchain::Transaction, Bip125Replaceable}, + RpcApi, +}; use rust_decimal::{ prelude::{FromPrimitive, ToPrimitive}, Decimal, @@ -29,7 +32,8 @@ async fn send_rawtx( Extension(ctx): Extension>, Json(raw_tx_dto): Json, ) -> Result { - validate(raw_tx_dto.hex.clone()).await; + println!("{:?}", raw_tx_dto.hex.clone()); + validate(raw_tx_dto.hex.clone())?; let mut max_fee = Some(default_max_fee_rate().unwrap().to_sat()); if let Some(fee_rate) = raw_tx_dto.max_fee_rate { let sat_per_bitcoin = Decimal::new(100_000_000, 0); @@ -131,15 +135,14 @@ async fn get_raw_tx( Ok(Response::new(raw_tx)) } -async fn validate(hex: String) { +fn validate(hex: String) -> Result<()> { + println!("{:?}", hex); if !hex.starts_with("040000000001") { - return; - } - let buffer = hex::decode(hex).expect("Decoding failed"); - let transaction: Transaction = deserialize(&buffer).expect("Failed to deserialize transaction"); - if transaction.output.len() != 2 { - return; + return Err(Error::ValidationError( + "Transaction does not start with the expected prefix.".to_string(), + )); } + Ok(()) } pub fn router(ctx: Arc) -> Router { diff --git a/lib/ain-ocean/src/error.rs b/lib/ain-ocean/src/error.rs index a3b0b7a721..60fa605db9 100644 --- a/lib/ain-ocean/src/error.rs +++ b/lib/ain-ocean/src/error.rs @@ -70,6 +70,8 @@ pub enum Error { TryFromIntError(#[from] std::num::TryFromIntError), #[error(transparent)] Other(#[from] anyhow::Error), + #[error("Validation error: {0}")] + ValidationError(String), } #[derive(Serialize)] From 4a8028d249f3cbfbb1856461a518adeb06285be6 Mon Sep 17 00:00:00 2001 From: nagarajm22 Date: Fri, 14 Jun 2024 12:02:21 +0800 Subject: [PATCH 09/17] fixed clippy --- lib/ain-ocean/src/api/rawtx.rs | 21 +++++++-------------- lib/ain-ocean/src/model/raw_tx.rs | 4 +--- 2 files changed, 8 insertions(+), 17 deletions(-) diff --git a/lib/ain-ocean/src/api/rawtx.rs b/lib/ain-ocean/src/api/rawtx.rs index 67b6d7eff3..86d262d2a1 100644 --- a/lib/ain-ocean/src/api/rawtx.rs +++ b/lib/ain-ocean/src/api/rawtx.rs @@ -3,28 +3,21 @@ use std::{str::FromStr, sync::Arc}; use ain_macros::ocean_endpoint; use axum::{ extract::{Json, Path}, - http::StatusCode, routing::{get, post}, Extension, Router, }; -use bitcoin::{consensus::encode::deserialize, Txid}; -use defichain_rpc::{ - json::{blockchain::Transaction, Bip125Replaceable}, - RpcApi, -}; -use rust_decimal::{ - prelude::{FromPrimitive, ToPrimitive}, - Decimal, -}; +use bitcoin::Txid; +use defichain_rpc::{json::Bip125Replaceable, RpcApi}; +use rust_decimal::{prelude::ToPrimitive, Decimal}; -use super::{fee, response::Response, AppContext}; +use super::{response::Response, AppContext}; use crate::{ error::ApiError, model::{ default_max_fee_rate, MempoolAcceptResult, RawTransaction, RawTxDto, TransctionDetails, WalletTxInfo, }, - ApiResult, Error, Result, + Error, Result, }; #[ocean_endpoint] @@ -93,7 +86,7 @@ async fn get_raw_tx( .details .into_iter() .map(|detail| TransctionDetails { - address: detail.address.map(|addr| addr), + address: detail.address, category: detail.category.to_owned(), amount: detail.amount.to_sat(), label: detail.label, @@ -129,7 +122,7 @@ async fn get_raw_tx( }, amount: tx_result.amount.to_sat(), fee: tx_result.fee.map(|amount| amount.to_sat()), - details: details, + details, hex: tx_result.hex, }; Ok(Response::new(raw_tx)) diff --git a/lib/ain-ocean/src/model/raw_tx.rs b/lib/ain-ocean/src/model/raw_tx.rs index 14af932040..c96acf490f 100644 --- a/lib/ain-ocean/src/model/raw_tx.rs +++ b/lib/ain-ocean/src/model/raw_tx.rs @@ -1,8 +1,6 @@ -use std::str::FromStr; - use bitcoin::{address::NetworkUnchecked, Address, Amount, BlockHash, Txid}; use defichain_rpc::json::GetTransactionResultDetailCategory; -use rust_decimal::{prelude::ToPrimitive, Decimal}; +use rust_decimal::Decimal; use serde::{Deserialize, Serialize}; #[derive(Serialize, Deserialize, Default, Clone)] #[serde(rename_all = "camelCase")] From e3cb077a2e51210e93618ba6d92f5b873e523901 Mon Sep 17 00:00:00 2001 From: nagarajm22 Date: Fri, 14 Jun 2024 15:22:24 +0800 Subject: [PATCH 10/17] resolved issue --- lib/ain-ocean/src/api/rawtx.rs | 44 ++++++++++++++++++++----------- lib/ain-ocean/src/lib.rs | 1 - lib/ain-ocean/src/model/raw_tx.rs | 5 ++-- 3 files changed, 30 insertions(+), 20 deletions(-) diff --git a/lib/ain-ocean/src/api/rawtx.rs b/lib/ain-ocean/src/api/rawtx.rs index 86d262d2a1..7d524722ee 100644 --- a/lib/ain-ocean/src/api/rawtx.rs +++ b/lib/ain-ocean/src/api/rawtx.rs @@ -9,6 +9,7 @@ use axum::{ use bitcoin::Txid; use defichain_rpc::{json::Bip125Replaceable, RpcApi}; use rust_decimal::{prelude::ToPrimitive, Decimal}; +use rust_decimal_macros::dec; use super::{response::Response, AppContext}; use crate::{ @@ -25,16 +26,23 @@ async fn send_rawtx( Extension(ctx): Extension>, Json(raw_tx_dto): Json, ) -> Result { - println!("{:?}", raw_tx_dto.hex.clone()); validate(raw_tx_dto.hex.clone())?; - let mut max_fee = Some(default_max_fee_rate().unwrap().to_sat()); - if let Some(fee_rate) = raw_tx_dto.max_fee_rate { - let sat_per_bitcoin = Decimal::new(100_000_000, 0); - let fee_in_satoshis = fee_rate * sat_per_bitcoin; - max_fee = fee_in_satoshis.round().to_u64(); - } - let trx = defichain_rpc::RawTx::raw_hex(raw_tx_dto.hex); - match ctx.client.send_raw_transaction(trx, max_fee).await { + let max_fee = match raw_tx_dto.max_fee_rate { + Some(fee_rate) => { + let sat_per_bitcoin = dec!(100_000_000); + let fee_in_satoshis = fee_rate.checked_mul(sat_per_bitcoin); + match fee_in_satoshis { + Some(value) => Some(value.to_u64().unwrap_or_default()), + None => Some(default_max_fee_rate().to_sat()), + } + } + None => Some(default_max_fee_rate().to_sat()), + }; + match ctx + .client + .send_raw_transaction(raw_tx_dto.hex, max_fee) + .await + { Ok(tx_hash) => Ok(tx_hash.to_string()), Err(e) => { eprintln!("Failed to send raw transaction: {:?}", e); @@ -48,12 +56,17 @@ async fn test_rawtx( Json(raw_tx_dto): Json, ) -> Result>> { let trx = defichain_rpc::RawTx::raw_hex(raw_tx_dto.hex); - let mut max_fee = Some(default_max_fee_rate().unwrap().to_sat()); - if let Some(fee_rate) = raw_tx_dto.max_fee_rate { - let sat_per_bitcoin = Decimal::new(100_000_000, 0); - let fee_in_satoshis = fee_rate * sat_per_bitcoin; - max_fee = fee_in_satoshis.round().to_u64(); - } + let max_fee = match raw_tx_dto.max_fee_rate { + Some(fee_rate) => { + let sat_per_bitcoin = dec!(100_000_000); + let fee_in_satoshis = fee_rate.checked_mul(sat_per_bitcoin); + match fee_in_satoshis { + Some(value) => Some(value.to_u64().unwrap_or_default()), + None => Some(default_max_fee_rate().to_sat()), + } + } + None => Some(default_max_fee_rate().to_sat()), + }; match ctx.client.test_mempool_accept(&[trx], max_fee).await { Ok(mempool_tx) => { let results = mempool_tx @@ -129,7 +142,6 @@ async fn get_raw_tx( } fn validate(hex: String) -> Result<()> { - println!("{:?}", hex); if !hex.starts_with("040000000001") { return Err(Error::ValidationError( "Transaction does not start with the expected prefix.".to_string(), diff --git a/lib/ain-ocean/src/lib.rs b/lib/ain-ocean/src/lib.rs index 61a7d58cfb..767585c8c4 100644 --- a/lib/ain-ocean/src/lib.rs +++ b/lib/ain-ocean/src/lib.rs @@ -34,7 +34,6 @@ pub mod storage; use crate::storage::ocean_store::OceanStore; pub type Result = std::result::Result; -pub type ApiResult = std::result::Result; lazy_static::lazy_static! { // Global services exposed by the library diff --git a/lib/ain-ocean/src/model/raw_tx.rs b/lib/ain-ocean/src/model/raw_tx.rs index c96acf490f..5c1605743e 100644 --- a/lib/ain-ocean/src/model/raw_tx.rs +++ b/lib/ain-ocean/src/model/raw_tx.rs @@ -9,9 +9,8 @@ pub struct RawTxDto { pub max_fee_rate: Option, } -pub fn default_max_fee_rate() -> Option { - let default_max_fee_rate = Amount::from_btc(0.1).unwrap_or_default(); - Some(default_max_fee_rate) +pub fn default_max_fee_rate() -> Amount { + Amount::from_btc(0.1).unwrap_or_default() } #[derive(Serialize, Deserialize, Debug)] From f1fe72c2300234c8994651cec506953fe42e2b5c Mon Sep 17 00:00:00 2001 From: nagarajm22 Date: Fri, 14 Jun 2024 19:36:42 +0800 Subject: [PATCH 11/17] fixed get method --- lib/ain-ocean/src/api/rawtx.rs | 89 ++++++++++++------------------- lib/ain-ocean/src/lib.rs | 2 +- lib/ain-ocean/src/model/raw_tx.rs | 56 +++++++------------ 3 files changed, 54 insertions(+), 93 deletions(-) diff --git a/lib/ain-ocean/src/api/rawtx.rs b/lib/ain-ocean/src/api/rawtx.rs index 7d524722ee..7e299b8632 100644 --- a/lib/ain-ocean/src/api/rawtx.rs +++ b/lib/ain-ocean/src/api/rawtx.rs @@ -7,17 +7,15 @@ use axum::{ Extension, Router, }; use bitcoin::Txid; -use defichain_rpc::{json::Bip125Replaceable, RpcApi}; -use rust_decimal::{prelude::ToPrimitive, Decimal}; +use defichain_rpc::RpcApi; +use rust_decimal::prelude::ToPrimitive; use rust_decimal_macros::dec; +use serde::Deserialize; -use super::{response::Response, AppContext}; +use super::{query::Query, response::Response, AppContext}; use crate::{ error::ApiError, - model::{ - default_max_fee_rate, MempoolAcceptResult, RawTransaction, RawTxDto, TransctionDetails, - WalletTxInfo, - }, + model::{default_max_fee_rate, MempoolAcceptResult, RawTransactionResult, RawTxDto}, Error, Result, }; @@ -88,57 +86,40 @@ async fn test_rawtx( } } +#[derive(Deserialize, Default)] +struct QueryParams { + verbose: bool, +} #[ocean_endpoint] async fn get_raw_tx( - Path((txid, verbose)): Path<(String, bool)>, + Path(txid): Path, + Query(QueryParams { verbose }): Query, Extension(ctx): Extension>, -) -> Result> { +) -> Result<(String, Option)> { let tx_hash = Txid::from_str(&txid)?; - let tx_result = ctx.client.get_transaction(&tx_hash, Some(verbose)).await?; - let details: Vec = tx_result - .details - .into_iter() - .map(|detail| TransctionDetails { - address: detail.address, - category: detail.category.to_owned(), - amount: detail.amount.to_sat(), - label: detail.label, - vout: detail.vout, - fee: detail.fee.map(|f| f.to_sat()), - abandoned: detail.abandoned, - hex: hex::encode(&tx_result.hex), - blockhash: tx_result.info.blockhash, - confirmations: tx_result.info.confirmations, - time: tx_result.info.time, - blocktime: tx_result.info.blocktime, - }) - .collect(); - - let bip_125 = match tx_result.info.bip125_replaceable { - Bip125Replaceable::Yes => Some("Yes".to_string()), - Bip125Replaceable::No => Some("No".to_string()), - Bip125Replaceable::Unknown => Some("Unknown".to_string()), - }; - - let raw_tx = RawTransaction { - info: WalletTxInfo { - confirmations: tx_result.info.confirmations, - blockhash: tx_result.info.blockhash, - blockindex: tx_result.info.blockindex, - blocktime: tx_result.info.blocktime, - blockheight: tx_result.info.blockheight, - txid: tx_result.info.txid, - time: tx_result.info.time, - timereceived: tx_result.info.timereceived, - bip125_replaceable: bip_125, - wallet_conflicts: tx_result.info.wallet_conflicts, - }, - amount: tx_result.amount.to_sat(), - fee: tx_result.fee.map(|amount| amount.to_sat()), - details, - hex: tx_result.hex, - }; - Ok(Response::new(raw_tx)) + if !verbose { + let tx_hex = ctx.client.get_raw_transaction_hex(&tx_hash, None).await?; + Ok((txid, None)) + } else { + let tx_info = ctx.client.get_raw_transaction_info(&tx_hash, None).await?; + let result = RawTransactionResult { + in_active_chain: tx_info.in_active_chain, + hex: tx_info.hex, + txid: tx_info.txid, + hash: tx_info.hash, + size: tx_info.size, + vsize: tx_info.vsize, + version: tx_info.version, + locktime: tx_info.locktime, + vin: tx_info.vin, + vout: tx_info.vout, + blockhash: tx_info.blockhash, + confirmations: tx_info.confirmations, + time: tx_info.time, + blocktime: tx_info.blocktime, + }; + Ok((txid, Some(result))) // Correctly wrap in a tuple and Some + } } fn validate(hex: String) -> Result<()> { diff --git a/lib/ain-ocean/src/lib.rs b/lib/ain-ocean/src/lib.rs index 767585c8c4..21e76713e1 100644 --- a/lib/ain-ocean/src/lib.rs +++ b/lib/ain-ocean/src/lib.rs @@ -5,7 +5,7 @@ pub mod network; use std::{path::PathBuf, sync::Arc}; pub use api::ocean_router; -use error::{ApiError, Error}; +use error::Error; pub use indexer::{ index_block, invalidate_block, oracle::invalidate_oracle_interval, transaction::index_transaction, tx_result, PoolCreationHeight, diff --git a/lib/ain-ocean/src/model/raw_tx.rs b/lib/ain-ocean/src/model/raw_tx.rs index 5c1605743e..5d4f2e9e7f 100644 --- a/lib/ain-ocean/src/model/raw_tx.rs +++ b/lib/ain-ocean/src/model/raw_tx.rs @@ -1,5 +1,5 @@ -use bitcoin::{address::NetworkUnchecked, Address, Amount, BlockHash, Txid}; -use defichain_rpc::json::GetTransactionResultDetailCategory; +use bitcoin::{Amount, Txid}; +use defichain_rpc::json::{GetRawTransactionResultVin, GetRawTransactionResultVout}; use rust_decimal::Decimal; use serde::{Deserialize, Serialize}; #[derive(Serialize, Deserialize, Default, Clone)] @@ -13,43 +13,23 @@ pub fn default_max_fee_rate() -> Amount { Amount::from_btc(0.1).unwrap_or_default() } -#[derive(Serialize, Deserialize, Debug)] -pub struct TransctionDetails { - pub address: Option>, - pub category: GetTransactionResultDetailCategory, - pub amount: i64, - pub label: Option, - pub vout: u32, - pub fee: Option, - pub abandoned: Option, - pub hex: String, - pub blockhash: Option, - pub confirmations: i32, - pub time: u64, - pub blocktime: Option, -} - -#[derive(Serialize, Deserialize, Debug)] -pub struct WalletTxInfo { - pub confirmations: i32, - pub blockhash: Option, - pub blockindex: Option, - pub blocktime: Option, - pub blockheight: Option, - pub txid: Txid, - pub time: u64, - pub timereceived: u64, - pub bip125_replaceable: Option, - pub wallet_conflicts: Vec, -} - -#[derive(Serialize, Deserialize, Debug)] -pub struct RawTransaction { - pub info: WalletTxInfo, - pub amount: i64, - pub fee: Option, - pub details: Vec, +#[derive(Clone, PartialEq, Eq, Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct RawTransactionResult { + pub in_active_chain: Option, pub hex: Vec, + pub txid: bitcoin::Txid, + pub hash: bitcoin::Wtxid, + pub size: usize, + pub vsize: usize, + pub version: u32, + pub locktime: u32, + pub vin: Vec, + pub vout: Vec, + pub blockhash: Option, + pub confirmations: Option, + pub time: Option, + pub blocktime: Option, } #[derive(Serialize, Deserialize, Debug)] From 23efe761baaddbfbb70f6bf6982dc086213ddfb3 Mon Sep 17 00:00:00 2001 From: nagarajm22 Date: Wed, 19 Jun 2024 18:58:42 +0800 Subject: [PATCH 12/17] fixed validate in raw_tx --- lib/ain-dftx/src/types/pool.rs | 7 ++- lib/ain-ocean/src/api/rawtx.rs | 101 ++++++++++++++++++++++++++++----- lib/ain-ocean/src/error.rs | 2 + 3 files changed, 94 insertions(+), 16 deletions(-) diff --git a/lib/ain-dftx/src/types/pool.rs b/lib/ain-dftx/src/types/pool.rs index 3d3c7a97a5..d8b8513646 100644 --- a/lib/ain-dftx/src/types/pool.rs +++ b/lib/ain-dftx/src/types/pool.rs @@ -1,6 +1,6 @@ use ain_macros::ConsensusEncoding; use bitcoin::{io, ScriptBuf}; - +use std::fmt; use super::{ balance::{ScriptBalances, TokenBalanceUInt32, TokenBalanceVarInt}, common::{CompactVec, Maybe}, @@ -65,3 +65,8 @@ pub struct PoolUpdatePair { pub owner_address: ScriptBuf, pub custom_rewards: Maybe>, } +impl fmt::Display for PoolId { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "PoolId: {:?}", self.id) + } +} \ No newline at end of file diff --git a/lib/ain-ocean/src/api/rawtx.rs b/lib/ain-ocean/src/api/rawtx.rs index 7e299b8632..fea5336498 100644 --- a/lib/ain-ocean/src/api/rawtx.rs +++ b/lib/ain-ocean/src/api/rawtx.rs @@ -1,16 +1,17 @@ -use std::{str::FromStr, sync::Arc}; +use std::{result::Result as StdResult, str::FromStr, sync::Arc}; +use ain_dftx::{deserialize, DfTx}; use ain_macros::ocean_endpoint; use axum::{ extract::{Json, Path}, routing::{get, post}, Extension, Router, }; -use bitcoin::Txid; -use defichain_rpc::RpcApi; +use bitcoin::{Transaction, Txid}; +use defichain_rpc::{PoolPairRPC, RpcApi}; use rust_decimal::prelude::ToPrimitive; use rust_decimal_macros::dec; -use serde::Deserialize; +use serde::{Deserialize, Serialize, Serializer}; use super::{query::Query, response::Response, AppContext}; use crate::{ @@ -19,12 +20,22 @@ use crate::{ Error, Result, }; +enum TransactionResponse { + HexString(String), + TransactionDetails(Box), +} + +#[derive(Deserialize, Default)] +struct QueryParams { + verbose: bool, +} + #[ocean_endpoint] async fn send_rawtx( Extension(ctx): Extension>, Json(raw_tx_dto): Json, ) -> Result { - validate(raw_tx_dto.hex.clone())?; + validate(ctx.clone(), raw_tx_dto.hex.clone()).await?; let max_fee = match raw_tx_dto.max_fee_rate { Some(fee_rate) => { let sat_per_bitcoin = dec!(100_000_000); @@ -44,7 +55,11 @@ async fn send_rawtx( Ok(tx_hash) => Ok(tx_hash.to_string()), Err(e) => { eprintln!("Failed to send raw transaction: {:?}", e); - Err(Error::RpcError(e)) + if e.to_string().contains("Transaction decode failed") { + Err(Error::BadRequest("Transaction decode failed".to_string())) + } else { + Err(Error::RpcError(e)) + } } } } @@ -86,20 +101,28 @@ async fn test_rawtx( } } -#[derive(Deserialize, Default)] -struct QueryParams { - verbose: bool, +impl Serialize for TransactionResponse { + fn serialize(&self, serializer: S) -> StdResult + where + S: Serializer, + { + match *self { + TransactionResponse::HexString(ref s) => serializer.serialize_str(s), + TransactionResponse::TransactionDetails(ref details) => details.serialize(serializer), + } + } } + #[ocean_endpoint] async fn get_raw_tx( + Extension(ctx): Extension>, Path(txid): Path, Query(QueryParams { verbose }): Query, - Extension(ctx): Extension>, -) -> Result<(String, Option)> { +) -> Result { let tx_hash = Txid::from_str(&txid)?; if !verbose { let tx_hex = ctx.client.get_raw_transaction_hex(&tx_hash, None).await?; - Ok((txid, None)) + Ok(TransactionResponse::HexString(tx_hex)) } else { let tx_info = ctx.client.get_raw_transaction_info(&tx_hash, None).await?; let result = RawTransactionResult { @@ -118,17 +141,65 @@ async fn get_raw_tx( time: tx_info.time, blocktime: tx_info.blocktime, }; - Ok((txid, Some(result))) // Correctly wrap in a tuple and Some + Ok(TransactionResponse::TransactionDetails(Box::new(result))) } } -fn validate(hex: String) -> Result<()> { +async fn validate(ctx: Arc, hex: String) -> Result<()> { if !hex.starts_with("040000000001") { return Err(Error::ValidationError( "Transaction does not start with the expected prefix.".to_string(), )); } - Ok(()) + let data = hex::decode(hex)?; + println!("decode_hex {:?}", data); + let trx = deserialize::(&data)?; + let bytes = trx.output[0].clone().script_pubkey.into_bytes(); + let tx: Option = if bytes.len() > 2 && bytes[0] == 0x6a && bytes[1] <= 0x4e { + let offset = 1 + match bytes[1] { + 0x4c => 2, + 0x4d => 3, + 0x4e => 4, + _ => 1, + }; + + let raw_tx = &bytes[offset..]; + Some(deserialize::(raw_tx)?) + } else { + None + }; + + if let Some(tx) = tx { + if let DfTx::CompositeSwap(composite_swap) = tx { + if composite_swap.pools.as_ref().is_empty() { + return Err(Error::BadRequest( + "Composite swap pool length is empty".to_string(), + )); + } + let pool_id = composite_swap.pools.iter().last().unwrap(); + let tokio_id = composite_swap.pool_swap.to_token_id.0.to_string(); + let pool_pair = ctx + .client + .get_pool_pair(pool_id.to_string(), Some(true)) + .await?; + for (_, pool_pair_info) in pool_pair.0 { + if pool_pair_info.id_token_a.eq(&tokio_id) + || pool_pair_info.id_token_b.eq(&tokio_id) + { + println!("Found a match: {:?}", pool_pair_info); + } + } + Ok(()) + } else { + Err(Error::BadRequest( + "Transaction is not a composite swap".to_string(), + )) + } + } else { + Err(Error::BadRequest( + "No valid raw transaction found".to_string(), + )) + } } pub fn router(ctx: Arc) -> Router { diff --git a/lib/ain-ocean/src/error.rs b/lib/ain-ocean/src/error.rs index 60fa605db9..b6171e50ee 100644 --- a/lib/ain-ocean/src/error.rs +++ b/lib/ain-ocean/src/error.rs @@ -72,6 +72,8 @@ pub enum Error { Other(#[from] anyhow::Error), #[error("Validation error: {0}")] ValidationError(String), + #[error("Validation error: {0}")] + BadRequest(String), } #[derive(Serialize)] From 68b978b69534407ac8852523dd23a6c863773e0c Mon Sep 17 00:00:00 2001 From: nagarajm22 Date: Thu, 20 Jun 2024 13:19:08 +0800 Subject: [PATCH 13/17] fixed pool format --- lib/ain-dftx/src/types/pool.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/ain-dftx/src/types/pool.rs b/lib/ain-dftx/src/types/pool.rs index d8b8513646..d9550fef9b 100644 --- a/lib/ain-dftx/src/types/pool.rs +++ b/lib/ain-dftx/src/types/pool.rs @@ -1,6 +1,8 @@ +use std::fmt; + use ain_macros::ConsensusEncoding; use bitcoin::{io, ScriptBuf}; -use std::fmt; + use super::{ balance::{ScriptBalances, TokenBalanceUInt32, TokenBalanceVarInt}, common::{CompactVec, Maybe}, @@ -69,4 +71,4 @@ impl fmt::Display for PoolId { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "PoolId: {:?}", self.id) } -} \ No newline at end of file +} From 04469346088f7ef7c67e86ebea087d09ff2bce46 Mon Sep 17 00:00:00 2001 From: nagarajm22 Date: Fri, 21 Jun 2024 01:48:25 +0800 Subject: [PATCH 14/17] fixed rawtx bad request test cases --- lib/ain-ocean/src/api/rawtx.rs | 35 ++++++++++++++++++++++++---------- lib/ain-ocean/src/error.rs | 11 ++++------- 2 files changed, 29 insertions(+), 17 deletions(-) diff --git a/lib/ain-ocean/src/api/rawtx.rs b/lib/ain-ocean/src/api/rawtx.rs index fea5336498..25d7ba5155 100644 --- a/lib/ain-ocean/src/api/rawtx.rs +++ b/lib/ain-ocean/src/api/rawtx.rs @@ -3,7 +3,7 @@ use std::{result::Result as StdResult, str::FromStr, sync::Arc}; use ain_dftx::{deserialize, DfTx}; use ain_macros::ocean_endpoint; use axum::{ - extract::{Json, Path}, + extract::{path::ErrorKind, Json, Path}, routing::{get, post}, Extension, Router, }; @@ -15,14 +15,14 @@ use serde::{Deserialize, Serialize, Serializer}; use super::{query::Query, response::Response, AppContext}; use crate::{ - error::ApiError, + error::{ApiError, NotFoundKind}, model::{default_max_fee_rate, MempoolAcceptResult, RawTransactionResult, RawTxDto}, Error, Result, }; enum TransactionResponse { HexString(String), - TransactionDetails(Box), + TransactionDetails(RawTransactionResult), } #[derive(Deserialize, Default)] @@ -96,7 +96,11 @@ async fn test_rawtx( } Err(e) => { eprintln!("Failed to send raw transaction: {:?}", e); - Err(Error::RpcError(e)) + if e.to_string().contains("TX decode failed") { + Err(Error::BadRequest("Transaction decode failed".to_string())) + } else { + Err(Error::RpcError(e)) + } } } } @@ -121,10 +125,23 @@ async fn get_raw_tx( ) -> Result { let tx_hash = Txid::from_str(&txid)?; if !verbose { - let tx_hex = ctx.client.get_raw_transaction_hex(&tx_hash, None).await?; + let tx_hex = ctx.client.get_raw_transaction_hex(&tx_hash, None).await.map_err(|e| { + if e.to_string().contains("No such mempool or blockchain transaction. Use gettransaction for wallet transactions.") { + Error::NotFound(NotFoundKind::RawTx) + } else { + Error::RpcError(e) + } + })?; Ok(TransactionResponse::HexString(tx_hex)) } else { - let tx_info = ctx.client.get_raw_transaction_info(&tx_hash, None).await?; + let tx_info = ctx + .client + .get_raw_transaction_info(&tx_hash, None) + .await + .map_err(|e| { + eprintln!("Failed to get raw transaction hex: {:?}", e); + Error::RpcError(e) + })?; let result = RawTransactionResult { in_active_chain: tx_info.in_active_chain, hex: tx_info.hex, @@ -141,15 +158,13 @@ async fn get_raw_tx( time: tx_info.time, blocktime: tx_info.blocktime, }; - Ok(TransactionResponse::TransactionDetails(Box::new(result))) + Ok(TransactionResponse::TransactionDetails(result)) } } async fn validate(ctx: Arc, hex: String) -> Result<()> { if !hex.starts_with("040000000001") { - return Err(Error::ValidationError( - "Transaction does not start with the expected prefix.".to_string(), - )); + return Err(Error::BadRequest("Transaction decode failed".to_string())); } let data = hex::decode(hex)?; println!("decode_hex {:?}", data); diff --git a/lib/ain-ocean/src/error.rs b/lib/ain-ocean/src/error.rs index b6171e50ee..4ad4ccf3c7 100644 --- a/lib/ain-ocean/src/error.rs +++ b/lib/ain-ocean/src/error.rs @@ -26,6 +26,8 @@ pub enum NotFoundKind { Token, #[error("poolpair")] PoolPair, + #[error("rawtx")] + RawTx, } #[derive(Error, Debug)] @@ -72,7 +74,7 @@ pub enum Error { Other(#[from] anyhow::Error), #[error("Validation error: {0}")] ValidationError(String), - #[error("Validation error: {0}")] + #[error("{0}")] BadRequest(String), } @@ -150,6 +152,7 @@ impl Error { ) } Error::NotFound(_) => (StatusCode::NOT_FOUND, format!("{self}")), + Error::BadRequest(msg) => (StatusCode::BAD_REQUEST, msg.clone()), _ => (StatusCode::INTERNAL_SERVER_ERROR, self.to_string()), }; (code, reason) @@ -167,9 +170,3 @@ impl From<&str> for Error { Error::Other(format_err!("{s}")) } } -impl IntoResponse for Error { - fn into_response(self) -> Response { - let error_message = format!("Internal server error: {}", self); - (StatusCode::INTERNAL_SERVER_ERROR, error_message).into_response() - } -} From 9004bb75dea292c1aaca0ee8745cf5280a602910 Mon Sep 17 00:00:00 2001 From: nagarajm22 Date: Fri, 21 Jun 2024 17:35:55 +0800 Subject: [PATCH 15/17] fixed validate return type --- lib/ain-ocean/src/api/rawtx.rs | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/lib/ain-ocean/src/api/rawtx.rs b/lib/ain-ocean/src/api/rawtx.rs index 25d7ba5155..763573851f 100644 --- a/lib/ain-ocean/src/api/rawtx.rs +++ b/lib/ain-ocean/src/api/rawtx.rs @@ -3,7 +3,7 @@ use std::{result::Result as StdResult, str::FromStr, sync::Arc}; use ain_dftx::{deserialize, DfTx}; use ain_macros::ocean_endpoint; use axum::{ - extract::{path::ErrorKind, Json, Path}, + extract::{Json, Path}, routing::{get, post}, Extension, Router, }; @@ -31,7 +31,7 @@ struct QueryParams { } #[ocean_endpoint] -async fn send_rawtx( +async fn send_raw_tx( Extension(ctx): Extension>, Json(raw_tx_dto): Json, ) -> Result { @@ -64,7 +64,7 @@ async fn send_rawtx( } } #[ocean_endpoint] -async fn test_rawtx( +async fn test_raw_tx( Extension(ctx): Extension>, Json(raw_tx_dto): Json, ) -> Result>> { @@ -164,7 +164,7 @@ async fn get_raw_tx( async fn validate(ctx: Arc, hex: String) -> Result<()> { if !hex.starts_with("040000000001") { - return Err(Error::BadRequest("Transaction decode failed".to_string())); + return Ok(()); } let data = hex::decode(hex)?; println!("decode_hex {:?}", data); @@ -181,15 +181,13 @@ async fn validate(ctx: Arc, hex: String) -> Result<()> { let raw_tx = &bytes[offset..]; Some(deserialize::(raw_tx)?) } else { - None + return Ok(()); }; if let Some(tx) = tx { if let DfTx::CompositeSwap(composite_swap) = tx { if composite_swap.pools.as_ref().is_empty() { - return Err(Error::BadRequest( - "Composite swap pool length is empty".to_string(), - )); + return Ok(()); } let pool_id = composite_swap.pools.iter().last().unwrap(); let tokio_id = composite_swap.pool_swap.to_token_id.0.to_string(); @@ -211,17 +209,15 @@ async fn validate(ctx: Arc, hex: String) -> Result<()> { )) } } else { - Err(Error::BadRequest( - "No valid raw transaction found".to_string(), - )) + Ok(()) } } pub fn router(ctx: Arc) -> Router { println!("{:?}", ctx.network); Router::new() - .route("/send", post(send_rawtx)) - .route("/test", post(test_rawtx)) + .route("/send", post(send_raw_tx)) + .route("/test", post(test_raw_tx)) .route("/:txid", get(get_raw_tx)) .layer(Extension(ctx)) } From ce6ad85c51fc497a3f587f8a36ac3f0568c3c2e5 Mon Sep 17 00:00:00 2001 From: nagarajm22 Date: Sat, 22 Jun 2024 00:53:24 +0800 Subject: [PATCH 16/17] updated send error message --- lib/ain-ocean/src/api/rawtx.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ain-ocean/src/api/rawtx.rs b/lib/ain-ocean/src/api/rawtx.rs index 763573851f..2960ea9090 100644 --- a/lib/ain-ocean/src/api/rawtx.rs +++ b/lib/ain-ocean/src/api/rawtx.rs @@ -55,7 +55,7 @@ async fn send_raw_tx( Ok(tx_hash) => Ok(tx_hash.to_string()), Err(e) => { eprintln!("Failed to send raw transaction: {:?}", e); - if e.to_string().contains("Transaction decode failed") { + if e.to_string().contains("TX decode failed") { Err(Error::BadRequest("Transaction decode failed".to_string())) } else { Err(Error::RpcError(e)) From e6e5a70c36406012578693bcf422deb0b63879fd Mon Sep 17 00:00:00 2001 From: nagarajm22 Date: Mon, 24 Jun 2024 13:22:45 +0800 Subject: [PATCH 17/17] fixed lint issue --- lib/ain-ocean/src/api/rawtx.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/ain-ocean/src/api/rawtx.rs b/lib/ain-ocean/src/api/rawtx.rs index 2960ea9090..f178b16c74 100644 --- a/lib/ain-ocean/src/api/rawtx.rs +++ b/lib/ain-ocean/src/api/rawtx.rs @@ -22,7 +22,7 @@ use crate::{ enum TransactionResponse { HexString(String), - TransactionDetails(RawTransactionResult), + TransactionDetails(Box), } #[derive(Deserialize, Default)] @@ -158,7 +158,7 @@ async fn get_raw_tx( time: tx_info.time, blocktime: tx_info.blocktime, }; - Ok(TransactionResponse::TransactionDetails(result)) + Ok(TransactionResponse::TransactionDetails(Box::new(result))) } }