Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
11 changes: 10 additions & 1 deletion orm/src/transactions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,16 @@ use crate::schema::{
inner_transactions, transaction_history, wrapper_transactions,
};

#[derive(Debug, Clone, Serialize, Deserialize, diesel_derive_enum::DbEnum)]
#[derive(
Debug,
Clone,
Serialize,
Deserialize,
diesel_derive_enum::DbEnum,
Eq,
PartialEq,
Hash,
)]
#[ExistingTypePath = "crate::schema::sql_types::TransactionKind"]
pub enum TransactionKindDb {
TransparentTransfer,
Expand Down
5 changes: 5 additions & 0 deletions swagger.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1004,6 +1004,11 @@ paths:
minItems: 1
maxItems: 10
description: The list of address. Must contain at least 1 element
- in: query
name: transaction_types
schema:
type: string
description: Comma-separated list of transaction types to filter by. If not provided, all transaction types are returned. The options are transparentTransfer, shieldedTransfer, shieldingTransfer, unshieldingTransfer, mixedTransfer, ibcMsgTransfer, ibcTransparentTransfer, ibcShieldingTransfer, ibcUnshieldingTransfer, bond, redelegation, unbond, withdraw, claimRewards, voteProposal, initProposal, changeMetadata, changeCommission, revealPk, becomeValidator, reactivateValidator, deactivateValidator, unjailValidator
responses:
"200":
description: Pagined historic transaction list.
Expand Down
4 changes: 4 additions & 0 deletions webserver/src/dto/transaction.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::collections::HashSet;

use serde::{Deserialize, Serialize};
use validator::Validate;

Expand All @@ -8,4 +10,6 @@ pub struct TransactionHistoryQueryParams {
pub page: Option<u64>,
#[validate(length(min = 1, max = 10))]
pub addresses: Vec<String>,
#[validate(length(min = 1, max = 20))]
pub transaction_types: Option<HashSet<String>>,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could also just have an empty set without the need for an Option

}
2 changes: 1 addition & 1 deletion webserver/src/handler/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ pub async fn get_transaction_history(

let (transactions, total_pages, total_items) = state
.transaction_service
.get_addresses_history(query.addresses, page)
.get_addresses_history(query.addresses, page, query.transaction_types)
.await?;

let response =
Expand Down
18 changes: 16 additions & 2 deletions webserver/src/repository/tranasaction.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::collections::HashSet;

use axum::async_trait;
use diesel::{
ExpressionMethods, JoinOnDsl, QueryDsl, RunQueryDsl, SelectableHelper,
Expand All @@ -6,7 +8,8 @@ use orm::schema::{
inner_transactions, transaction_history, wrapper_transactions,
};
use orm::transactions::{
InnerTransactionDb, TransactionHistoryDb, WrapperTransactionDb,
InnerTransactionDb, TransactionHistoryDb, TransactionKindDb,
WrapperTransactionDb,
};

use super::utils::{Paginate, PaginatedResponseDb};
Expand Down Expand Up @@ -37,6 +40,7 @@ pub trait TransactionRepositoryTrait {
&self,
addresses: Vec<String>,
page: i64,
transaction_types: Option<HashSet<TransactionKindDb>>,
) -> Result<
PaginatedResponseDb<(TransactionHistoryDb, InnerTransactionDb, i32)>,
String,
Expand Down Expand Up @@ -108,17 +112,27 @@ impl TransactionRepositoryTrait for TransactionRepository {
&self,
addresses: Vec<String>,
page: i64,
transaction_types: Option<HashSet<TransactionKindDb>>,
) -> Result<
PaginatedResponseDb<(TransactionHistoryDb, InnerTransactionDb, i32)>,
String,
> {
let conn = self.app_state.get_db_connection().await;

conn.interact(move |conn| {
transaction_history::table
let mut query = transaction_history::table
.filter(transaction_history::dsl::target.eq_any(addresses))
.inner_join(inner_transactions::table.on(transaction_history::dsl::inner_tx_id.eq(inner_transactions::dsl::id)))
.inner_join(wrapper_transactions::table.on(inner_transactions::dsl::wrapper_id.eq(wrapper_transactions::dsl::id)))
.into_boxed();
// Apply transaction type filter if provided
if let Some(types) = transaction_types {
if !types.is_empty() {
query = query.filter(inner_transactions::dsl::kind.eq_any(types));
}
}

query
.order(wrapper_transactions::dsl::block_height.desc())
.select((transaction_history::all_columns, inner_transactions::all_columns, wrapper_transactions::dsl::block_height))
.paginate(page)
Expand Down
72 changes: 70 additions & 2 deletions webserver/src/service/transaction.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use orm::transactions::WrapperTransactionDb;
use std::collections::HashSet;

use orm::transactions::{TransactionKindDb, WrapperTransactionDb};

use crate::appstate::AppState;
use crate::error::transaction::TransactionError;
Expand Down Expand Up @@ -75,14 +77,80 @@ impl TransactionService {
Ok(inner_txs.into_iter().map(InnerTransaction::from).collect())
}

// Helper function to parse transaction types from comma-separated string
fn parse_transaction_types(
transaction_types: HashSet<String>,
) -> HashSet<TransactionKindDb> {
transaction_types
.iter()
.filter_map(|type_str| {
let type_str = type_str.trim();
match type_str {
"transparentTransfer" => {
Some(TransactionKindDb::TransparentTransfer)
}
"shieldedTransfer" => {
Some(TransactionKindDb::ShieldedTransfer)
}
"shieldingTransfer" => {
Some(TransactionKindDb::ShieldingTransfer)
}
"unshieldingTransfer" => {
Some(TransactionKindDb::UnshieldingTransfer)
}
"mixedTransfer" => Some(TransactionKindDb::MixedTransfer),
"ibcMsgTransfer" => Some(TransactionKindDb::IbcMsgTransfer),
"ibcTransparentTransfer" => {
Some(TransactionKindDb::IbcTransparentTransfer)
}
"ibcShieldingTransfer" => {
Some(TransactionKindDb::IbcShieldingTransfer)
}
"ibcUnshieldingTransfer" => {
Some(TransactionKindDb::IbcUnshieldingTransfer)
}
"bond" => Some(TransactionKindDb::Bond),
"redelegation" => Some(TransactionKindDb::Redelegation),
"unbond" => Some(TransactionKindDb::Unbond),
"withdraw" => Some(TransactionKindDb::Withdraw),
"claimRewards" => Some(TransactionKindDb::ClaimRewards),
"voteProposal" => Some(TransactionKindDb::VoteProposal),
"initProposal" => Some(TransactionKindDb::InitProposal),
"changeMetadata" => Some(TransactionKindDb::ChangeMetadata),
"changeCommission" => {
Some(TransactionKindDb::ChangeCommission)
}
"revealPk" => Some(TransactionKindDb::RevealPk),
"becomeValidator" => {
Some(TransactionKindDb::BecomeValidator)
}
"reactivateValidator" => {
Some(TransactionKindDb::ReactivateValidator)
}
"deactivateValidator" => {
Some(TransactionKindDb::DeactivateValidator)
}
"unjailValidator" => {
Some(TransactionKindDb::UnjailValidator)
}
_ => None, // Skip invalid types
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Better to return an error maybe? To avoid typos going unnoticed

}
})
.collect::<HashSet<_>>()
}

pub async fn get_addresses_history(
&self,
addresses: Vec<String>,
page: u64,
transaction_types: Option<HashSet<String>>,
) -> Result<(Vec<TransactionHistory>, u64, u64), TransactionError> {
let transaction_types =
transaction_types.map(Self::parse_transaction_types);

let (txs, total_pages, total_items) = self
.transaction_repo
.find_addresses_history(addresses, page as i64)
.find_addresses_history(addresses, page as i64, transaction_types)
.await
.map_err(TransactionError::Database)?;

Expand Down
Loading