From 0e337379e5193ac98279e7cae84ba0f13b83640d Mon Sep 17 00:00:00 2001 From: Patrice Tisserand Date: Mon, 19 Aug 2024 10:20:07 +0200 Subject: [PATCH 1/7] fix(arkchain-indexer): cancelled event are now inserted by arkchain indexer Add `TokenEventType` enum to modelize database token events --- .../migrations/marketplace/0_marketplace.sql | 5 +- ark-sqlx/src/providers/marketplace/mod.rs | 1 + ark-sqlx/src/providers/marketplace/order.rs | 243 ++++++++---------- ark-sqlx/src/providers/marketplace/types.rs | 101 ++++++++ 4 files changed, 216 insertions(+), 134 deletions(-) create mode 100644 ark-sqlx/src/providers/marketplace/types.rs diff --git a/ark-sqlx/migrations/marketplace/0_marketplace.sql b/ark-sqlx/migrations/marketplace/0_marketplace.sql index 1e59f8ca..b4d32ec2 100644 --- a/ark-sqlx/migrations/marketplace/0_marketplace.sql +++ b/ark-sqlx/migrations/marketplace/0_marketplace.sql @@ -70,7 +70,10 @@ CREATE TABLE token_event ( order_hash TEXT, token_id TEXT NOT NULL, token_id_hex TEXT NOT NULL, - event_type TEXT CHECK (event_type IN ('Listing', 'CollectionOffer', 'Offer', 'Auction', 'Fulfill', 'Cancelled', 'Executed', 'Sale', 'Mint', 'Burn', 'Transfer')), + event_type TEXT CHECK (event_type IN + ('Listing', 'CollectionOffer', 'Offer', 'Auction', + 'Fulfill', 'Cancelled', 'Executed', 'Sale', 'Mint', + 'Burn', 'Transfer', 'ListingCancelled', 'AuctionCancelled', 'OfferCancelled')), block_timestamp BIGINT NOT NULL, transaction_hash TEXT NULL, to_address TEXT, -- NULL if not transfer diff --git a/ark-sqlx/src/providers/marketplace/mod.rs b/ark-sqlx/src/providers/marketplace/mod.rs index fd116adf..e400b54f 100644 --- a/ark-sqlx/src/providers/marketplace/mod.rs +++ b/ark-sqlx/src/providers/marketplace/mod.rs @@ -1,2 +1,3 @@ pub mod order; pub use order::OrderProvider; +pub mod types; diff --git a/ark-sqlx/src/providers/marketplace/order.rs b/ark-sqlx/src/providers/marketplace/order.rs index 6d6a8a9f..127695e5 100644 --- a/ark-sqlx/src/providers/marketplace/order.rs +++ b/ark-sqlx/src/providers/marketplace/order.rs @@ -1,4 +1,6 @@ use crate::providers::{ProviderError, SqlxCtxPg}; +use crate::providers::marketplace::types::{TokenEventType, AUCTION_CANCELLED_STR, AUCTION_STR, BURN_STR, CANCELLED_STR, COLLECTION_OFFER_STR, EXECUTED_STR, FULFILL_STR, LISTING_CANCELLED_STR, LISTING_STR, MINT_STR, OFFER_CANCELLED_STR, OFFER_STR, ROLLBACK_STR, SALE_STR, TRANSFER_STR}; + use arkproject::diri::storage::types::{ CancelledData, ExecutedData, FulfilledData, PlacedData, RollbackStatusData, }; @@ -15,6 +17,59 @@ use std::sync::Arc; use tokio::sync::Mutex; use tracing::{error, info, trace}; +// conversion from Diri string +impl FromStr for TokenEventType { + type Err = &'static str; + + fn from_str(s: &str) -> Result { + match s { + LISTING_STR => Ok(TokenEventType::Listing), + AUCTION_STR => Ok(TokenEventType::Auction), + OFFER_STR => Ok(TokenEventType::Offer), + COLLECTION_OFFER_STR => Ok(TokenEventType::CollectionOffer), + FULFILL_STR => Ok(TokenEventType::Fulfill), + EXECUTED_STR => Ok(TokenEventType::Executed), + CANCELLED_STR => Ok(TokenEventType::Cancelled), + SALE_STR => Ok(TokenEventType::Sale), + MINT_STR => Ok(TokenEventType::Mint), + BURN_STR => Ok(TokenEventType::Burn), + TRANSFER_STR => Ok(TokenEventType::Transfer), + ROLLBACK_STR => Ok(TokenEventType::Rollback), + LISTING_CANCELLED_STR => Ok(TokenEventType::ListingCancelled), + AUCTION_CANCELLED_STR => Ok(TokenEventType::AuctionCancelled), + OFFER_CANCELLED_STR => Ok(TokenEventType::OfferCancelled), + _ => Err("Unknown event type"), + } + } +} + + +impl fmt::Display for TokenEventType { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "{}", + match self { + TokenEventType::Listing => LISTING_STR, + TokenEventType::Auction => AUCTION_STR, + TokenEventType::Offer => OFFER_STR, + TokenEventType::CollectionOffer => COLLECTION_OFFER_STR, + TokenEventType::Fulfill => FULFILL_STR, + TokenEventType::Executed => EXECUTED_STR, + TokenEventType::Cancelled => CANCELLED_STR, + TokenEventType::Sale => SALE_STR, + TokenEventType::Mint => MINT_STR, + TokenEventType::Burn => BURN_STR, + TokenEventType::Transfer => TRANSFER_STR, + TokenEventType::Rollback => ROLLBACK_STR, + TokenEventType::ListingCancelled => LISTING_CANCELLED_STR, + TokenEventType::AuctionCancelled => AUCTION_CANCELLED_STR, + TokenEventType::OfferCancelled => OFFER_CANCELLED_STR, + } + ) + } +} + #[derive(Debug)] #[allow(clippy::enum_variant_names)] enum RollbackStatus { @@ -72,104 +127,6 @@ pub enum OrderStatus { Executed, } -#[derive(Debug, Copy, Clone, PartialEq)] -pub enum EventType { - Listing, - Auction, - Offer, - CollectionOffer, - Fulfill, - Executed, - Cancelled, - Mint, - Burn, - Transfer, - Rollback, -} - -impl From for EventType { - fn from(s: String) -> Self { - match s.as_str() { - "Listing" => EventType::Listing, - "Auction" => EventType::Auction, - "Offer" => EventType::Offer, - "CollectionOffer" => EventType::CollectionOffer, - "Fulfill" => EventType::Fulfill, - "Executed" => EventType::Executed, - "Cancelled" => EventType::Cancelled, - "Mint" => EventType::Mint, - "Burn" => EventType::Burn, - "Transfer" => EventType::Transfer, - "Rollback" => EventType::Rollback, - _ => { - error!("Unknown event type: {}", s); - EventType::Listing - } - } - } -} - -impl FromStr for EventType { - type Err = &'static str; - - fn from_str(s: &str) -> Result { - match s { - "Listing" => Ok(EventType::Listing), - "Auction" => Ok(EventType::Auction), - "Offer" => Ok(EventType::Offer), - "CollectionOffer" => Ok(EventType::CollectionOffer), - "Fulfill" => Ok(EventType::Fulfill), - "Executed" => Ok(EventType::Executed), - "Cancelled" => Ok(EventType::Cancelled), - "Mint" => Ok(EventType::Mint), - "Burn" => Ok(EventType::Burn), - "Transfer" => Ok(EventType::Transfer), - "Rollback" => Ok(EventType::Rollback), - _ => Err("Unknown event type"), - } - } -} - -impl EventType { - pub fn as_str(&self) -> &'static str { - match self { - EventType::Listing => "Listing", - EventType::Auction => "Auction", - EventType::Offer => "Offer", - EventType::CollectionOffer => "CollectionOffer", - EventType::Fulfill => "Fulfill", - EventType::Executed => "Executed", - EventType::Cancelled => "Cancelled", - EventType::Mint => "Mint", - EventType::Burn => "Burn", - EventType::Transfer => "Transfer", - EventType::Rollback => "Rollback", - } - } -} - -impl fmt::Display for EventType { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "{}", - match self { - EventType::Listing => "Listing", - EventType::Auction => "Auction", - EventType::Offer => "Offer", - EventType::CollectionOffer => "CollectionOffer", - EventType::Fulfill => "Fulfill", - EventType::Executed => "Executed", - EventType::Cancelled => "Cancelled", - EventType::Mint => "Mint", - EventType::Burn => "Burn", - EventType::Transfer => "Transfer", - EventType::Rollback => "Rollback", - } - ) - } -} - impl fmt::Display for OrderStatus { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( @@ -187,13 +144,14 @@ impl fmt::Display for OrderStatus { pub struct OrderProvider {} +#[derive(sqlx::FromRow)] struct EventHistoryData { order_hash: String, token_id: String, token_id_hex: String, contract_address: String, chain_id: String, - event_type: EventType, + event_type: TokenEventType, block_timestamp: i64, from_address: Option, to_address: Option, @@ -527,7 +485,7 @@ impl OrderProvider { .bind(token_id) .bind(chain_id) .bind(order_hash) - .bind(EventType::Fulfill.to_string()) + .bind(TokenEventType::Fulfill.to_string()) .fetch_optional(&client.pool) .await?; @@ -871,7 +829,7 @@ impl OrderProvider { let q = " INSERT INTO token_event (token_event_id, order_hash, token_id, token_id_hex, contract_address, chain_id, event_type, block_timestamp, from_address, to_address, amount, canceled_reason) - VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12); + VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12); "; let _r = sqlx::query(q) @@ -893,6 +851,49 @@ impl OrderProvider { Ok(()) } + async fn insert_cancel_event( + client: &SqlxCtxPg, + order_hash: String, + block_timestamp: i64, + reason: String, + ) -> Result<(), ProviderError> { + // retrieve previous order hash event + let query = " + SELECT + order_hash, + token_id, + token_id_hex, + contract_address, + chain_id, + event_type, + block_timestamp, + from_address, + to_address, + amount, + canceled_reason + FROM token_event + WHERE order_hash = $1 + ORDER BY block_timestamp DESC + LIMIT 1 + "; + if let Ok(mut event_history) = sqlx::query_as::<_, EventHistoryData>(query) + .bind(order_hash) + .fetch_one(&client.pool) + .await { + event_history.block_timestamp = block_timestamp; + event_history.canceled_reason = reason.into(); + event_history.event_type = match event_history.event_type { + TokenEventType::Listing => TokenEventType::ListingCancelled, + TokenEventType::Auction => TokenEventType::AuctionCancelled, + TokenEventType::Offer => TokenEventType::OfferCancelled, + _ => TokenEventType::Cancelled, + }; + + Self::insert_event_history(client, &event_history).await?; + } + Ok(()) + } + async fn offer_exists( client: &SqlxCtxPg, order_hash: &str, @@ -1103,7 +1104,7 @@ impl OrderProvider { None => return Err(ProviderError::from("Missing token id")), }; - let event_type = EventType::from_str(&data.order_type).map_err(ProviderError::from)?; + let event_type = TokenEventType::from_str(&data.order_type).map_err(ProviderError::from)?; let contract_address = Self::get_or_create_contract( client, &data.token_address, @@ -1119,7 +1120,7 @@ impl OrderProvider { } } - if event_type == EventType::Offer || event_type == EventType::CollectionOffer { + if event_type == TokenEventType::Offer || event_type == TokenEventType::CollectionOffer { // create token without listing information let upsert_query = " INSERT INTO token (contract_address, token_id, token_id_hex, chain_id, updated_timestamp, listing_orderhash, block_timestamp, status) @@ -1352,32 +1353,6 @@ impl OrderProvider { } } - let token_id = match BigInt::from_str(&token_data.token_id) { - Ok(token_id) => token_id.to_string(), - Err(e) => { - error!("Failed to parse token id: {}", e); - return Err(ProviderError::from("Failed to parse token id")); - } - }; - - Self::insert_event_history( - client, - &EventHistoryData { - order_hash: data.order_hash.clone(), - token_id: token_id.clone(), - token_id_hex: token_data.token_id_hex.clone(), - contract_address: token_data.contract_address.clone(), - chain_id: token_data.chain_id.clone(), - event_type: EventType::Cancelled, - block_timestamp: block_timestamp as i64, - canceled_reason: data.reason.clone().into(), - to_address: None, - amount: None, - from_address: None, - }, - ) - .await?; - Self::update_token_status( client, &token_data.contract_address, @@ -1401,6 +1376,8 @@ impl OrderProvider { { Self::update_offer_status(client, &data.order_hash, OrderStatus::Cancelled).await?; } + // insert cancelled event + Self::insert_cancel_event(client, data.order_hash.clone(), block_timestamp as i64, data.reason.clone()).await?; Ok(()) } @@ -1439,7 +1416,7 @@ impl OrderProvider { token_id_hex: token_data.token_id_hex.clone(), contract_address: token_data.contract_address.clone(), chain_id: token_data.chain_id.clone(), - event_type: EventType::Fulfill, + event_type: TokenEventType::Fulfill, block_timestamp: block_timestamp as i64, canceled_reason: None, to_address: None, @@ -1516,7 +1493,7 @@ impl OrderProvider { token_id_hex: token_data.token_id_hex.clone(), contract_address: offer_data.contract_address.clone(), chain_id: offer_data.chain_id.clone(), - event_type: EventType::Executed, + event_type: TokenEventType::Executed, block_timestamp: block_timestamp as i64, canceled_reason: None, to_address, @@ -1572,7 +1549,7 @@ impl OrderProvider { token_id_hex: token_data.token_id_hex.clone(), contract_address: token_data.contract_address.clone(), chain_id: token_data.chain_id, - event_type: EventType::Executed, + event_type: TokenEventType::Executed, canceled_reason: None, to_address: None, amount: token_data.listing_start_amount, @@ -1620,7 +1597,7 @@ impl OrderProvider { token_id_hex: token_data.token_id_hex.clone(), contract_address: token_data.contract_address, chain_id: token_data.chain_id, - event_type: EventType::Rollback, + event_type: TokenEventType::Rollback, canceled_reason: Some(string_reason), to_address: None, amount: None, diff --git a/ark-sqlx/src/providers/marketplace/types.rs b/ark-sqlx/src/providers/marketplace/types.rs new file mode 100644 index 00000000..9bcb39e5 --- /dev/null +++ b/ark-sqlx/src/providers/marketplace/types.rs @@ -0,0 +1,101 @@ + +#[derive(Debug, Copy, Clone, PartialEq)] +pub enum TokenEventType { + Listing, + Auction, + Offer, + CollectionOffer, + Fulfill, + Executed, + Cancelled, + Sale, + Mint, + Burn, + Transfer, + Rollback, + // Cancel event type + ListingCancelled, + AuctionCancelled, + OfferCancelled, +} + + +/// DB for EventType +pub(crate) const LISTING_STR: &str = "Listing"; +pub(crate) const AUCTION_STR: &str = "Auction"; +pub(crate) const OFFER_STR: &str = "Offer"; +pub(crate) const COLLECTION_OFFER_STR: &str = "CollectionOffer"; +pub(crate) const FULFILL_STR: &str = "Fulfill"; +pub(crate) const EXECUTED_STR: &str = "Executed"; +pub(crate) const CANCELLED_STR: &str = "Cancelled"; +pub(crate) const SALE_STR: &str = "Sale"; +pub(crate) const MINT_STR: &str = "Mint"; +pub(crate) const BURN_STR: &str = "Burn"; +pub(crate) const TRANSFER_STR: &str = "Transfer"; +pub(crate) const ROLLBACK_STR: &str = "Rollback"; +pub(crate) const LISTING_CANCELLED_STR: &str = "ListingCancelled"; +pub(crate) const AUCTION_CANCELLED_STR: &str = "AuctionCancelled"; +pub(crate) const OFFER_CANCELLED_STR: &str = "OfferCancelled"; + + +impl sqlx::Type for TokenEventType +where + DB: sqlx::Database, + String: sqlx::Type, +{ + fn type_info() -> ::TypeInfo { + >::type_info() + } +} + +impl<'r, DB> sqlx::Decode<'r, DB> for TokenEventType +where + DB: sqlx::Database, + &'r str: sqlx::Decode<'r, DB>, +{ + fn decode( + value: >::ValueRef, + ) -> Result { + let s = <&str as sqlx::Decode>::decode(value)?; + match s { + LISTING_STR => Ok(TokenEventType::Listing), + COLLECTION_OFFER_STR => Ok(TokenEventType::CollectionOffer), + OFFER_STR => Ok(TokenEventType::Offer), + AUCTION_STR => Ok(TokenEventType::Auction), + FULFILL_STR => Ok(TokenEventType::Fulfill), + CANCELLED_STR => Ok(TokenEventType::Cancelled), + EXECUTED_STR => Ok(TokenEventType::Executed), + SALE_STR => Ok(TokenEventType::Sale), + MINT_STR => Ok(TokenEventType::Mint), + BURN_STR => Ok(TokenEventType::Burn), + TRANSFER_STR => Ok(TokenEventType::Transfer), + ROLLBACK_STR => Ok(TokenEventType::Rollback), + LISTING_CANCELLED_STR => Ok(TokenEventType::ListingCancelled), + AUCTION_CANCELLED_STR => Ok(TokenEventType::AuctionCancelled), + OFFER_CANCELLED_STR => Ok(TokenEventType::OfferCancelled), + _ => Err("Invalid event type".into()), + } + } +} + +impl TokenEventType { + pub fn to_db_string(&self) -> String { + match self { + TokenEventType::Listing => LISTING_STR.to_string(), + TokenEventType::Auction => AUCTION_STR.to_string(), + TokenEventType::Offer => OFFER_STR.to_string(), + TokenEventType::CollectionOffer => COLLECTION_OFFER_STR.to_string(), + TokenEventType::Fulfill => FULFILL_STR.to_string(), + TokenEventType::Executed => EXECUTED_STR.to_string(), + TokenEventType::Cancelled => CANCELLED_STR.to_string(), + TokenEventType::Sale => SALE_STR.to_string(), + TokenEventType::Mint => MINT_STR.to_string(), + TokenEventType::Burn => BURN_STR.to_string(), + TokenEventType::Transfer => TRANSFER_STR.to_string(), + TokenEventType::Rollback => ROLLBACK_STR.to_string(), + TokenEventType::ListingCancelled => LISTING_CANCELLED_STR.to_string(), + TokenEventType::AuctionCancelled => AUCTION_CANCELLED_STR.to_string(), + TokenEventType::OfferCancelled => OFFER_CANCELLED_STR.to_string(), + } + } +} \ No newline at end of file From f601d754dd1916838fda406507c59ace20e270ee Mon Sep 17 00:00:00 2001 From: Patrice Tisserand Date: Mon, 19 Aug 2024 10:21:01 +0200 Subject: [PATCH 2/7] DRY --- ark-marketplace-api/src/utils/db_utils.rs | 106 ++++++++++------------ 1 file changed, 47 insertions(+), 59 deletions(-) diff --git a/ark-marketplace-api/src/utils/db_utils.rs b/ark-marketplace-api/src/utils/db_utils.rs index 3ad762a0..e9b7bcc8 100644 --- a/ark-marketplace-api/src/utils/db_utils.rs +++ b/ark-marketplace-api/src/utils/db_utils.rs @@ -1,4 +1,5 @@ use crate::models::token::TokenEventType; +use ark_sqlx::providers::marketplace::types::TokenEventType as TokenEventTypeDB; pub fn event_type_list(values: &[TokenEventType]) -> String { let mut types = values @@ -6,29 +7,36 @@ pub fn event_type_list(values: &[TokenEventType]) -> String { .map(|v| format!("'{}'", v.to_db_string())) .collect::>(); - if types.contains(&format!("'{}'", TOKEN_EVENT_SALE_STR)) { - types.push(format!("'{}'", TOKEN_EVENT_EXECUTED_STR)); + if types.contains(&format!("'{}'", TokenEventType::Sale.to_db_string())) { + types.push(format!("'{}'", TokenEventType::Executed.to_db_string())); } types.join(", ") } -/// DB conversion for TokenEventType -const TOKEN_EVENT_LISTING_STR: &str = "Listing"; -const TOKEN_EVENT_COLLECTION_OFFER_STR: &str = "CollectionOffer"; -const TOKEN_EVENT_OFFER_STR: &str = "Offer"; -const TOKEN_EVENT_AUCTION_STR: &str = "Auction"; -const TOKEN_EVENT_FULFILL_STR: &str = "Fulfill"; -const TOKEN_EVENT_CANCELLED_STR: &str = "Cancelled"; -const TOKEN_EVENT_EXECUTED_STR: &str = "Executed"; -const TOKEN_EVENT_SALE_STR: &str = "Sale"; -const TOKEN_EVENT_MINT_STR: &str = "Mint"; -const TOKEN_EVENT_BURN_STR: &str = "Burn"; -const TOKEN_EVENT_TRANSFER_STR: &str = "Transfer"; -// Cancel event -const TOKEN_EVENT_LISTING_CANCELLED_STR: &str = "ListingCancelled"; -const TOKEN_EVENT_AUCTION_CANCELLED_STR: &str = "AuctionCancelled"; -const TOKEN_EVENT_OFFER_CANCELLED_STR: &str = "OfferCancelled"; + +/// Convert TokenEventType to matching keys in DB +impl TokenEventType { + pub fn to_db_string(&self) -> String { + match self { + Self::Listing => TokenEventTypeDB::Listing.to_db_string(), + Self::CollectionOffer => TokenEventTypeDB::CollectionOffer.to_db_string(), + Self::Offer => TokenEventTypeDB::Offer.to_string(), + Self::Auction => TokenEventTypeDB::Auction.to_string(), + Self::Fulfill => TokenEventTypeDB::Fulfill.to_string(), + Self::Cancelled => TokenEventTypeDB::Cancelled.to_string(), + Self::Executed => TokenEventTypeDB::Executed.to_string(), + Self::Sale => TokenEventTypeDB::Sale.to_string(), + Self::Mint => TokenEventTypeDB::Mint.to_string(), + Self::Burn => TokenEventTypeDB::Burn.to_string(), + Self::Transfer => TokenEventType::Transfer.to_string(), + // Cancel event + Self::ListingCancelled => TokenEventTypeDB::ListingCancelled.to_string(), + Self::AuctionCancelled => TokenEventTypeDB::AuctionCancelled.to_string(), + Self::OfferCancelled => TokenEventTypeDB::OfferCancelled.to_string(), + } + } +} impl sqlx::Type for TokenEventType where @@ -48,47 +56,27 @@ where fn decode( value: >::ValueRef, ) -> Result { - let s = <&str as sqlx::Decode>::decode(value)?; - match s { - TOKEN_EVENT_LISTING_STR => Ok(TokenEventType::Listing), - TOKEN_EVENT_COLLECTION_OFFER_STR => Ok(TokenEventType::CollectionOffer), - TOKEN_EVENT_OFFER_STR => Ok(TokenEventType::Offer), - TOKEN_EVENT_AUCTION_STR => Ok(TokenEventType::Auction), - TOKEN_EVENT_FULFILL_STR => Ok(TokenEventType::Fulfill), - TOKEN_EVENT_CANCELLED_STR => Ok(TokenEventType::Cancelled), - TOKEN_EVENT_EXECUTED_STR => Ok(TokenEventType::Executed), - TOKEN_EVENT_SALE_STR => Ok(TokenEventType::Sale), - TOKEN_EVENT_MINT_STR => Ok(TokenEventType::Mint), - TOKEN_EVENT_BURN_STR => Ok(TokenEventType::Burn), - TOKEN_EVENT_TRANSFER_STR => Ok(TokenEventType::Transfer), - // Cancel event - TOKEN_EVENT_LISTING_CANCELLED_STR => Ok(TokenEventType::ListingCancelled), - TOKEN_EVENT_AUCTION_CANCELLED_STR => Ok(TokenEventType::AuctionCancelled), - TOKEN_EVENT_OFFER_CANCELLED_STR => Ok(TokenEventType::OfferCancelled), - _ => Err("Invalid event type".into()), - } - } -} - -/// Convert TokenEventType to matching keys in DB -impl TokenEventType { - pub fn to_db_string(&self) -> String { - match self { - Self::Listing => TOKEN_EVENT_LISTING_STR.to_string(), - Self::CollectionOffer => TOKEN_EVENT_COLLECTION_OFFER_STR.to_string(), - Self::Offer => TOKEN_EVENT_OFFER_STR.to_string(), - Self::Auction => TOKEN_EVENT_AUCTION_STR.to_string(), - Self::Fulfill => TOKEN_EVENT_FULFILL_STR.to_string(), - Self::Cancelled => TOKEN_EVENT_CANCELLED_STR.to_string(), - Self::Executed => TOKEN_EVENT_EXECUTED_STR.to_string(), - Self::Sale => TOKEN_EVENT_SALE_STR.to_string(), - Self::Mint => TOKEN_EVENT_MINT_STR.to_string(), - Self::Burn => TOKEN_EVENT_BURN_STR.to_string(), - Self::Transfer => TOKEN_EVENT_TRANSFER_STR.to_string(), - // Cancel event - Self::ListingCancelled => TOKEN_EVENT_LISTING_CANCELLED_STR.to_string(), - Self::AuctionCancelled => TOKEN_EVENT_AUCTION_CANCELLED_STR.to_string(), - Self::OfferCancelled => TOKEN_EVENT_OFFER_CANCELLED_STR.to_string(), + if let Ok(e) = TokenEventTypeDB::decode(value) { + match e { + TokenEventTypeDB::Listing => Ok(TokenEventType::Listing), + TokenEventTypeDB::Auction => Ok(TokenEventType::Auction), + TokenEventTypeDB::Offer => Ok(TokenEventType::Offer), + TokenEventTypeDB::CollectionOffer => Ok(TokenEventType::CollectionOffer), + TokenEventTypeDB::Fulfill => Ok(TokenEventType::Offer), + TokenEventTypeDB::Executed => Ok(TokenEventType::Executed), + TokenEventTypeDB::Cancelled => Ok(TokenEventType::Cancelled), + TokenEventTypeDB::Sale => Ok(TokenEventType::Sale), + TokenEventTypeDB::Mint => Ok(TokenEventType::Mint), + TokenEventTypeDB::Burn => Ok(TokenEventType::Burn), + TokenEventTypeDB::Transfer => Ok(TokenEventType::Transfer), + TokenEventTypeDB::ListingCancelled => Ok(TokenEventType::ListingCancelled), + TokenEventTypeDB::AuctionCancelled => Ok(TokenEventType::AuctionCancelled), + TokenEventTypeDB::OfferCancelled => Ok(TokenEventType::OfferCancelled), + TokenEventTypeDB::Rollback => Err("Unsupported rollback event".into()) + // _ => Ok(TokenEventType::Burn), + } + } else { + Err("Invalid event type".into()) } } } From 895e790ec7f3c37dc378707e6e95c36b4c30c4d2 Mon Sep 17 00:00:00 2001 From: Patrice Tisserand Date: Mon, 26 Aug 2024 16:28:37 +0200 Subject: [PATCH 3/7] cargo fmt --- ark-marketplace-api/src/utils/db_utils.rs | 4 +-- ark-sqlx/src/providers/marketplace/order.rs | 28 ++++++++++++++------- ark-sqlx/src/providers/marketplace/types.rs | 5 +--- 3 files changed, 21 insertions(+), 16 deletions(-) diff --git a/ark-marketplace-api/src/utils/db_utils.rs b/ark-marketplace-api/src/utils/db_utils.rs index e9b7bcc8..02f5995a 100644 --- a/ark-marketplace-api/src/utils/db_utils.rs +++ b/ark-marketplace-api/src/utils/db_utils.rs @@ -14,7 +14,6 @@ pub fn event_type_list(values: &[TokenEventType]) -> String { types.join(", ") } - /// Convert TokenEventType to matching keys in DB impl TokenEventType { pub fn to_db_string(&self) -> String { @@ -72,8 +71,7 @@ where TokenEventTypeDB::ListingCancelled => Ok(TokenEventType::ListingCancelled), TokenEventTypeDB::AuctionCancelled => Ok(TokenEventType::AuctionCancelled), TokenEventTypeDB::OfferCancelled => Ok(TokenEventType::OfferCancelled), - TokenEventTypeDB::Rollback => Err("Unsupported rollback event".into()) - // _ => Ok(TokenEventType::Burn), + TokenEventTypeDB::Rollback => Err("Unsupported rollback event".into()), // _ => Ok(TokenEventType::Burn), } } else { Err("Invalid event type".into()) diff --git a/ark-sqlx/src/providers/marketplace/order.rs b/ark-sqlx/src/providers/marketplace/order.rs index 127695e5..5cd20188 100644 --- a/ark-sqlx/src/providers/marketplace/order.rs +++ b/ark-sqlx/src/providers/marketplace/order.rs @@ -1,5 +1,9 @@ +use crate::providers::marketplace::types::{ + TokenEventType, AUCTION_CANCELLED_STR, AUCTION_STR, BURN_STR, CANCELLED_STR, + COLLECTION_OFFER_STR, EXECUTED_STR, FULFILL_STR, LISTING_CANCELLED_STR, LISTING_STR, MINT_STR, + OFFER_CANCELLED_STR, OFFER_STR, ROLLBACK_STR, SALE_STR, TRANSFER_STR, +}; use crate::providers::{ProviderError, SqlxCtxPg}; -use crate::providers::marketplace::types::{TokenEventType, AUCTION_CANCELLED_STR, AUCTION_STR, BURN_STR, CANCELLED_STR, COLLECTION_OFFER_STR, EXECUTED_STR, FULFILL_STR, LISTING_CANCELLED_STR, LISTING_STR, MINT_STR, OFFER_CANCELLED_STR, OFFER_STR, ROLLBACK_STR, SALE_STR, TRANSFER_STR}; use arkproject::diri::storage::types::{ CancelledData, ExecutedData, FulfilledData, PlacedData, RollbackStatusData, @@ -43,7 +47,6 @@ impl FromStr for TokenEventType { } } - impl fmt::Display for TokenEventType { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( @@ -65,7 +68,7 @@ impl fmt::Display for TokenEventType { TokenEventType::ListingCancelled => LISTING_CANCELLED_STR, TokenEventType::AuctionCancelled => AUCTION_CANCELLED_STR, TokenEventType::OfferCancelled => OFFER_CANCELLED_STR, - } + } ) } } @@ -877,9 +880,10 @@ impl OrderProvider { LIMIT 1 "; if let Ok(mut event_history) = sqlx::query_as::<_, EventHistoryData>(query) - .bind(order_hash) - .fetch_one(&client.pool) - .await { + .bind(order_hash) + .fetch_one(&client.pool) + .await + { event_history.block_timestamp = block_timestamp; event_history.canceled_reason = reason.into(); event_history.event_type = match event_history.event_type { @@ -893,7 +897,7 @@ impl OrderProvider { } Ok(()) } - + async fn offer_exists( client: &SqlxCtxPg, order_hash: &str, @@ -1376,8 +1380,14 @@ impl OrderProvider { { Self::update_offer_status(client, &data.order_hash, OrderStatus::Cancelled).await?; } - // insert cancelled event - Self::insert_cancel_event(client, data.order_hash.clone(), block_timestamp as i64, data.reason.clone()).await?; + // insert cancelled event + Self::insert_cancel_event( + client, + data.order_hash.clone(), + block_timestamp as i64, + data.reason.clone(), + ) + .await?; Ok(()) } diff --git a/ark-sqlx/src/providers/marketplace/types.rs b/ark-sqlx/src/providers/marketplace/types.rs index 9bcb39e5..3421d0cd 100644 --- a/ark-sqlx/src/providers/marketplace/types.rs +++ b/ark-sqlx/src/providers/marketplace/types.rs @@ -1,4 +1,3 @@ - #[derive(Debug, Copy, Clone, PartialEq)] pub enum TokenEventType { Listing, @@ -19,7 +18,6 @@ pub enum TokenEventType { OfferCancelled, } - /// DB for EventType pub(crate) const LISTING_STR: &str = "Listing"; pub(crate) const AUCTION_STR: &str = "Auction"; @@ -37,7 +35,6 @@ pub(crate) const LISTING_CANCELLED_STR: &str = "ListingCancelled"; pub(crate) const AUCTION_CANCELLED_STR: &str = "AuctionCancelled"; pub(crate) const OFFER_CANCELLED_STR: &str = "OfferCancelled"; - impl sqlx::Type for TokenEventType where DB: sqlx::Database, @@ -98,4 +95,4 @@ impl TokenEventType { TokenEventType::OfferCancelled => OFFER_CANCELLED_STR.to_string(), } } -} \ No newline at end of file +} From 2f64e2c6b3156a8a4f230da505b28349a552b64c Mon Sep 17 00:00:00 2001 From: Patrice Tisserand Date: Mon, 26 Aug 2024 16:29:09 +0200 Subject: [PATCH 4/7] add missing dependency between ark-sqlx and ark-marketplace-api --- Cargo.lock | 1 + ark-marketplace-api/Cargo.toml | 1 + 2 files changed, 2 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 4f177f3f..03ef5718 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -570,6 +570,7 @@ dependencies = [ "actix-web", "actix-web-httpauth", "anyhow", + "ark-sqlx", "async-std", "async-trait", "aws-config", diff --git a/ark-marketplace-api/Cargo.toml b/ark-marketplace-api/Cargo.toml index ae2aa3a3..812ff355 100644 --- a/ark-marketplace-api/Cargo.toml +++ b/ark-marketplace-api/Cargo.toml @@ -10,6 +10,7 @@ actix-web = "4.4.0" actix-cors = "0.7.0" actix-rt = "2.9.0" actix-web-httpauth = "0.8.1" +ark-sqlx.workspace = true bigdecimal = { version = "0.3", features = ["serde"] } env_logger = "0.11.3" num-bigint = "0.4.4" From 9d8108f44c6ce4f1738299366716b8f35945b961 Mon Sep 17 00:00:00 2001 From: Patrice Tisserand Date: Mon, 26 Aug 2024 18:56:06 +0200 Subject: [PATCH 5/7] fix: `from_address` and `to_address` doesn't exist in `token_offer` table --- ark-marketplace-api/src/db/db_access.rs | 48 +++++-------------- .../src/db/portfolio_db_access.rs | 24 +++------- 2 files changed, 18 insertions(+), 54 deletions(-) diff --git a/ark-marketplace-api/src/db/db_access.rs b/ark-marketplace-api/src/db/db_access.rs index 46ea7421..d2120bc1 100644 --- a/ark-marketplace-api/src/db/db_access.rs +++ b/ark-marketplace-api/src/db/db_access.rs @@ -570,25 +570,13 @@ impl DatabaseAccess for PgPool { event_type_list(&[TokenEventType::Fulfill, TokenEventType::Executed]) ); - let from_select_part = format!( - " - CASE - WHEN te.event_type in ({}) THEN token_offer.from_address - ELSE te.from_address - END AS from - ", - event_type_list(&[TokenEventType::Fulfill, TokenEventType::Executed]) - ); + let from_select_part = " + te.from_address AS from + "; - let to_select_part = format!( - " - CASE - WHEN te.event_type in ({}) THEN token_offer.to_address - ELSE te.to_address - END AS to - ", - event_type_list(&[TokenEventType::Fulfill, TokenEventType::Executed]) - ); + let to_select_part = " + te.to_address AS to + "; let activity_sql_query = format!( " @@ -1208,25 +1196,13 @@ impl DatabaseAccess for PgPool { event_type_list(&[TokenEventType::Fulfill, TokenEventType::Executed]) ); - let from_select_part = format!( - " - CASE - WHEN te.event_type in ({}) THEN token_offer.from_address - ELSE te.from_address - END AS from - ", - event_type_list(&[TokenEventType::Fulfill, TokenEventType::Executed]) - ); + let from_select_part = " + te.from_address AS from + "; - let to_select_part = format!( - " - CASE - WHEN te.event_type in ({}) THEN token_offer.to_address - ELSE te.to_address - END AS to - ", - event_type_list(&[TokenEventType::Fulfill, TokenEventType::Executed]) - ); + let to_select_part = " + te.to_address AS to + "; let result_ordering = format!( " diff --git a/ark-marketplace-api/src/db/portfolio_db_access.rs b/ark-marketplace-api/src/db/portfolio_db_access.rs index b44749fe..7cb2f513 100644 --- a/ark-marketplace-api/src/db/portfolio_db_access.rs +++ b/ark-marketplace-api/src/db/portfolio_db_access.rs @@ -81,25 +81,13 @@ impl DatabaseAccess for PgPool { event_type_list(&[TokenEventType::Fulfill, TokenEventType::Executed]) ); - let from_select_part = format!( - " - CASE - WHEN te.event_type in ({}) THEN token_offer.from_address - ELSE te.from_address - END AS from - ", - event_type_list(&[TokenEventType::Fulfill, TokenEventType::Executed]) - ); + let from_select_part = " + te.from_address AS from + "; - let to_select_part = format!( - " - CASE - WHEN te.event_type in ({}) THEN token_offer.to_address - ELSE te.to_address - END AS to - ", - event_type_list(&[TokenEventType::Fulfill, TokenEventType::Executed]) - ); + let to_select_part = " + te.to_address AS to + "; let from_sql_query = format!( " From 25a38aa7e06ecc3c4343e6c56fac090c7e6c9821 Mon Sep 17 00:00:00 2001 From: Patrice Tisserand Date: Tue, 27 Aug 2024 00:29:25 +0200 Subject: [PATCH 6/7] fix(ark-marketplace-api): remove not more needed CTE --- ark-marketplace-api/src/db/db_access.rs | 51 ++----------------- .../src/db/portfolio_db_access.rs | 2 +- 2 files changed, 6 insertions(+), 47 deletions(-) diff --git a/ark-marketplace-api/src/db/db_access.rs b/ark-marketplace-api/src/db/db_access.rs index d2120bc1..119cad15 100644 --- a/ark-marketplace-api/src/db/db_access.rs +++ b/ark-marketplace-api/src/db/db_access.rs @@ -1108,54 +1108,16 @@ impl DatabaseAccess for PgPool { ) -> Result<(Vec, bool, i64), Error> { let offset = (page - 1) * items_per_page; - let token_event_with_previous_cte_part = format!( - " - WITH temporary_event_with_previous AS ( - ( - SELECT - *, - -- LAG() function is a window function that provides access to a row at a specified physical offset which comes before the current row. - -- Here we want to retrieve the previous event type for given order_hash - LAG(event_type) OVER (PARTITION BY order_hash ORDER BY block_timestamp) AS previous_event_type - FROM token_event WHERE contract_address = $1 AND chain_id = $2 AND token_id = $3 - ) - ), - token_event_with_previous AS ( - SELECT - *, - -- Create new event type if needed - CASE - WHEN event_type = '{executed_type}' THEN '{sale_type}' - WHEN event_type = '{cancelled_type}' AND previous_event_type = '{listing_type}' THEN '{listing_cancelled_type}' - WHEN event_type = '{cancelled_type}' AND previous_event_type = '{auction_type}' THEN '{auction_cancelled_type}' - WHEN event_type = '{cancelled_type}' AND previous_event_type = '{offer_type}' THEN '{offer_cancelled_type}' - ELSE event_type - END AS new_event_type - FROM temporary_event_with_previous - WHERE contract_address = $1 AND chain_id = $2 AND token_id = $3 - ) - ", - executed_type = TokenEventType::Executed.to_db_string(), - sale_type = TokenEventType::Sale.to_db_string(), - cancelled_type = TokenEventType::Cancelled.to_db_string(), - listing_type = TokenEventType::Listing.to_db_string(), - auction_type = TokenEventType::Auction.to_db_string(), - offer_type = TokenEventType::Offer.to_db_string(), - listing_cancelled_type = TokenEventType::ListingCancelled.to_db_string(), - auction_cancelled_type = TokenEventType::AuctionCancelled.to_db_string(), - offer_cancelled_type = TokenEventType::OfferCancelled.to_db_string(), - ); - let types_filter = match types { None => String::from(""), Some(values) => { - format!("AND te.new_event_type IN ({})", event_type_list(values)) + format!("AND te.event_type IN ({})", event_type_list(values)) } }; let common_where_part = format!( " - FROM token_event_with_previous as te + FROM token_event as te LEFT JOIN token_offer ON te.order_hash = token_offer.order_hash LEFT JOIN token ON te.token_id = token.token_id and te.contract_address = token.contract_address and te.chain_id = token.chain_id LEFT JOIN contract ON te.contract_address = contract.contract_address and te.chain_id = contract.chain_id @@ -1163,7 +1125,7 @@ impl DatabaseAccess for PgPool { AND te.chain_id = $2 AND te.token_id = $3 {} - AND te.new_event_type NOT IN ({}) + AND te.event_type NOT IN ({}) ", types_filter, event_type_list(&[TokenEventType::Fulfill]) @@ -1171,11 +1133,10 @@ impl DatabaseAccess for PgPool { let count_sql_query = format!( " - {} SELECT COUNT(*) AS total {} ", - token_event_with_previous_cte_part, common_where_part, + common_where_part, ); let total_count: Count = sqlx::query_as(&count_sql_query) @@ -1216,11 +1177,10 @@ impl DatabaseAccess for PgPool { let activity_sql_query = format!( " - {token_event_with_previous_cte} SELECT te.block_timestamp AS time_stamp, te.transaction_hash, - te.new_event_type AS activity_type, + te.event_type AS activity_type, token.metadata, contract.contract_name as collection_name, contract.is_verified as collection_is_verified, @@ -1231,7 +1191,6 @@ impl DatabaseAccess for PgPool { {common_where} {result_ordering} ", - token_event_with_previous_cte = token_event_with_previous_cte_part, common_where = common_where_part, price_select = price_select_part, from_select = from_select_part, diff --git a/ark-marketplace-api/src/db/portfolio_db_access.rs b/ark-marketplace-api/src/db/portfolio_db_access.rs index 7cb2f513..00d1c8e3 100644 --- a/ark-marketplace-api/src/db/portfolio_db_access.rs +++ b/ark-marketplace-api/src/db/portfolio_db_access.rs @@ -120,7 +120,7 @@ impl DatabaseAccess for PgPool { {}, {} {} - ORDER BY te.block_timestamp {} + ORDER BY te.block_timestamp {}, te.token_event_id LIMIT {} OFFSET {} ", price_select_part, From 0117899c1e9d937afd3eda8bea922769a6a2dd7a Mon Sep 17 00:00:00 2001 From: Patrice Tisserand Date: Fri, 30 Aug 2024 08:22:08 +0200 Subject: [PATCH 7/7] fix clippy error --- ark-marketplace-api/src/handlers/token_handler.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ark-marketplace-api/src/handlers/token_handler.rs b/ark-marketplace-api/src/handlers/token_handler.rs index 8a48c4f9..a08e454b 100644 --- a/ark-marketplace-api/src/handlers/token_handler.rs +++ b/ark-marketplace-api/src/handlers/token_handler.rs @@ -75,7 +75,7 @@ pub async fn get_tokens( let mut redis_con_ref = redis_con.get_ref().lock().await; let mut token_ids = None; if let Some(filters_param) = &query_parameters.filters { - let decoded_filters = decode(&filters_param).expect("Failed to decode filters"); + let decoded_filters = decode(filters_param).expect("Failed to decode filters"); let filters_map: HashMap = serde_json::from_str(&decoded_filters).expect("Failed to parse JSON");