Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
203 changes: 101 additions & 102 deletions lib/Cargo.lock

Large diffs are not rendered by default.

12 changes: 5 additions & 7 deletions lib/ain-ocean/src/api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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)))
Expand Down
3 changes: 1 addition & 2 deletions lib/ain-ocean/src/api/pool_pair/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand All @@ -42,8 +43,6 @@ use crate::{
Result, TokenIdentifier,
};

use price::DexPriceResponse;

pub mod path;
pub mod price;
pub mod service;
Expand Down
3 changes: 1 addition & 2 deletions lib/ain-ocean/src/api/pool_pair/price.rs
Original file line number Diff line number Diff line change
@@ -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},
Expand Down
149 changes: 137 additions & 12 deletions lib/ain-ocean/src/api/rawtx.rs
Original file line number Diff line number Diff line change
@@ -1,27 +1,152 @@
use std::sync::Arc;
use std::{str::FromStr, sync::Arc};

use ain_macros::ocean_endpoint;
use axum::{
extract::{Json, Path},
http::StatusCode,
routing::{get, post},
Router,
Extension, Router,
};
use bitcoin::{consensus::encode::deserialize, Transaction, Txid};
use defichain_rpc::{json::Bip125Replaceable, RpcApi};
use rust_decimal::{
prelude::{FromPrimitive, ToPrimitive},
Decimal,
};

use super::{fee, response::Response, AppContext};
use crate::{
error::ApiError,
model::{
default_max_fee_rate, MempoolAcceptResult, RawTransaction, RawTxDto, TransctionDetails,
WalletTxInfo,
},
ApiResult, Error, Result,
};
use defichain_rpc::{Client, RpcApi};
use super::path::Path;

async fn send_rawtx() -> String {
"Sending raw transaction".to_string()
#[ocean_endpoint]
async fn send_rawtx(
Extension(ctx): Extension<Arc<AppContext>>,
Json(raw_tx_dto): Json<RawTxDto>,
) -> Result<String> {
validate(raw_tx_dto.hex.clone()).await;
let mut max_fee = Some(default_max_fee_rate().unwrap().to_sat());
Comment thread
nagarajm22 marked this conversation as resolved.
Outdated
if let Some(fee_rate) = raw_tx_dto.max_fee_rate {
let sat_per_bitcoin = Decimal::new(100_000_000, 0);
Comment thread
nagarajm22 marked this conversation as resolved.
Outdated
let fee_in_satoshis = fee_rate * sat_per_bitcoin;
Comment thread
nagarajm22 marked this conversation as resolved.
Outdated
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 {
Comment thread
nagarajm22 marked this conversation as resolved.
Outdated
Ok(tx_hash) => Ok(tx_hash.to_string()),
Err(e) => {
eprintln!("Failed to send raw transaction: {:?}", e);
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 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
.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))
}
}
}

#[ocean_endpoint]
async fn get_raw_tx(
Comment thread
nagarajm22 marked this conversation as resolved.
Path((txid, verbose)): Path<(String, bool)>,
Extension(ctx): Extension<Arc<AppContext>>,
) -> Result<Response<RawTransaction>> {
let tx_hash = Txid::from_str(&txid)?;
let tx_result = ctx.client.get_transaction(&tx_hash, Some(verbose)).await?;
let details: Vec<TransctionDetails> = tx_result
.details
.into_iter()
.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();

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()),
};

async fn test_rawtx() -> String {
"Testing raw transaction".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 get_rawtx(Path(txid): Path<String>) -> String {
format!("Details of raw transaction with txid {}", txid)
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;
}
Comment thread
nagarajm22 marked this conversation as resolved.
Outdated
}

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))
Comment thread
nagarajm22 marked this conversation as resolved.
Outdated
.layer(Extension(ctx))
}
6 changes: 6 additions & 0 deletions lib/ain-ocean/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
}
}
3 changes: 2 additions & 1 deletion lib/ain-ocean/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -34,6 +34,7 @@ pub mod storage;
use crate::storage::ocean_store::OceanStore;

pub type Result<T> = std::result::Result<T, Error>;
pub type ApiResult<T> = std::result::Result<T, ApiError>;
Comment thread
nagarajm22 marked this conversation as resolved.
Outdated

lazy_static::lazy_static! {
// Global services exposed by the library
Expand Down
2 changes: 2 additions & 0 deletions lib/ain-ocean/src/model/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -33,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::*;
Expand Down
65 changes: 65 additions & 0 deletions lib/ain-ocean/src/model/raw_tx.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
use std::str::FromStr;

use bitcoin::{address::NetworkUnchecked, Address, Amount, BlockHash, Txid};
use defichain_rpc::json::GetTransactionResultDetailCategory;
use rust_decimal::{prelude::ToPrimitive, Decimal};
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Default, Clone)]
#[serde(rename_all = "camelCase")]
pub struct RawTxDto {
pub hex: String,
pub max_fee_rate: Option<Decimal>,
}

pub fn default_max_fee_rate() -> Option<Amount> {
let default_max_fee_rate = Amount::from_btc(0.1).unwrap_or_default();
Some(default_max_fee_rate)
}
Comment thread
nagarajm22 marked this conversation as resolved.
Outdated

#[derive(Serialize, Deserialize, Debug)]
pub struct TransctionDetails {
pub address: Option<Address<NetworkUnchecked>>,
pub category: GetTransactionResultDetailCategory,
pub amount: i64,
pub label: Option<String>,
pub vout: u32,
pub fee: Option<i64>,
pub abandoned: Option<bool>,
pub hex: String,
pub blockhash: Option<BlockHash>,
pub confirmations: i32,
pub time: u64,
pub blocktime: Option<u64>,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct WalletTxInfo {
pub confirmations: i32,
pub blockhash: Option<BlockHash>,
pub blockindex: Option<usize>,
pub blocktime: Option<u64>,
pub blockheight: Option<u32>,
pub txid: Txid,
pub time: u64,
pub timereceived: u64,
pub bip125_replaceable: Option<String>,
pub wallet_conflicts: Vec<bitcoin::Txid>,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct RawTransaction {
pub info: WalletTxInfo,
pub amount: i64,
pub fee: Option<i64>,
pub details: Vec<TransctionDetails>,
pub hex: Vec<u8>,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct MempoolAcceptResult {
pub txid: Txid,
pub allowed: bool,
pub reject_reason: Option<String>,
pub vsize: Option<u64>,
pub fees: Option<Amount>,
}