-
Notifications
You must be signed in to change notification settings - Fork 129
RawTx API #2921
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
RawTx API #2921
Changes from 14 commits
Commits
Show all changes
18 commits
Select commit
Hold shift + click to select a range
c5e42e3
ocean rawtx api
nagarajm22 180c77d
updated validate
nagarajm22 7aeb6cd
updated api for raw_trasaction
nagarajm22 2c3a5df
fixed get_raw_tx
nagarajm22 7200535
updated request to json rawtx
nagarajm22 2dd4518
updated raw tx api
nagarajm22 467d6ae
added validate to rawtx
nagarajm22 ea779f0
Merge branch feature/ocean-archive into feature/ocean-rawtx
Jouzo cabd88d
update send_rawtx
nagarajm22 4a8028d
fixed clippy
nagarajm22 e3cb077
resolved issue
nagarajm22 f1fe72c
fixed get method
nagarajm22 23efe76
fixed validate in raw_tx
nagarajm22 68b978b
fixed pool format
nagarajm22 0446934
fixed rawtx bad request test cases
nagarajm22 9004bb7
fixed validate return type
nagarajm22 ce6ad85
updated send error message
nagarajm22 e6e5a70
fixed lint issue
nagarajm22 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,27 +1,212 @@ | ||
| use std::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}, | ||
| Router, | ||
| Extension, Router, | ||
| }; | ||
| use defichain_rpc::{Client, RpcApi}; | ||
| use super::path::Path; | ||
| use bitcoin::{Transaction, Txid}; | ||
| use defichain_rpc::{PoolPairRPC, RpcApi}; | ||
| use rust_decimal::prelude::ToPrimitive; | ||
| use rust_decimal_macros::dec; | ||
| use serde::{Deserialize, Serialize, Serializer}; | ||
|
|
||
| async fn send_rawtx() -> String { | ||
| "Sending raw transaction".to_string() | ||
| use super::{query::Query, response::Response, AppContext}; | ||
| use crate::{ | ||
| error::ApiError, | ||
| model::{default_max_fee_rate, MempoolAcceptResult, RawTransactionResult, RawTxDto}, | ||
| Error, Result, | ||
| }; | ||
|
|
||
| enum TransactionResponse { | ||
| HexString(String), | ||
| TransactionDetails(Box<RawTransactionResult>), | ||
| } | ||
|
|
||
| #[derive(Deserialize, Default)] | ||
| struct QueryParams { | ||
| verbose: bool, | ||
| } | ||
|
|
||
| async fn test_rawtx() -> String { | ||
| "Testing raw transaction".to_string() | ||
| #[ocean_endpoint] | ||
| async fn send_rawtx( | ||
| Extension(ctx): Extension<Arc<AppContext>>, | ||
| Json(raw_tx_dto): Json<RawTxDto>, | ||
| ) -> Result<String> { | ||
| 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); | ||
| 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); | ||
| if e.to_string().contains("Transaction decode failed") { | ||
| Err(Error::BadRequest("Transaction decode failed".to_string())) | ||
| } else { | ||
| Err(Error::RpcError(e)) | ||
| } | ||
| } | ||
| } | ||
| } | ||
| #[ocean_endpoint] | ||
| async fn test_rawtx( | ||
| Extension(ctx): Extension<Arc<AppContext>>, | ||
| Json(raw_tx_dto): Json<RawTxDto>, | ||
| ) -> Result<Response<Vec<MempoolAcceptResult>>> { | ||
| let trx = defichain_rpc::RawTx::raw_hex(raw_tx_dto.hex); | ||
| 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 | ||
| .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::<Vec<MempoolAcceptResult>>(); | ||
| Ok(Response::new(results)) | ||
| } | ||
| Err(e) => { | ||
| eprintln!("Failed to send raw transaction: {:?}", e); | ||
| Err(Error::RpcError(e)) | ||
| } | ||
| } | ||
| } | ||
|
|
||
| async fn get_rawtx(Path(txid): Path<String>) -> String { | ||
| format!("Details of raw transaction with txid {}", txid) | ||
| impl Serialize for TransactionResponse { | ||
| fn serialize<S>(&self, serializer: S) -> StdResult<S::Ok, S::Error> | ||
| 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<Arc<AppContext>>, | ||
| Path(txid): Path<String>, | ||
| Query(QueryParams { verbose }): Query<QueryParams>, | ||
| ) -> Result<TransactionResponse> { | ||
| let tx_hash = Txid::from_str(&txid)?; | ||
| if !verbose { | ||
| let tx_hex = ctx.client.get_raw_transaction_hex(&tx_hash, None).await?; | ||
| Ok(TransactionResponse::HexString(tx_hex)) | ||
| } 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(TransactionResponse::TransactionDetails(Box::new(result))) | ||
| } | ||
| } | ||
|
|
||
| async fn validate(ctx: Arc<AppContext>, hex: String) -> Result<()> { | ||
| if !hex.starts_with("040000000001") { | ||
| return Err(Error::ValidationError( | ||
| "Transaction does not start with the expected prefix.".to_string(), | ||
| )); | ||
| } | ||
| let data = hex::decode(hex)?; | ||
| println!("decode_hex {:?}", data); | ||
| let trx = deserialize::<Transaction>(&data)?; | ||
| let bytes = trx.output[0].clone().script_pubkey.into_bytes(); | ||
| let tx: Option<DfTx> = 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::<DfTx>(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<AppContext>) -> Router { | ||
| println!("{:?}", ctx.network); | ||
| Router::new() | ||
| .route("/send", post(send_rawtx)) | ||
| .route("/test", get(test_rawtx)) | ||
| .route("/:txid", get(get_rawtx)) | ||
| .route("/test", post(test_rawtx)) | ||
| .route("/:txid", get(get_raw_tx)) | ||
|
nagarajm22 marked this conversation as resolved.
Outdated
|
||
| .layer(Extension(ctx)) | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.