Skip to content
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

[token] Add is_deleted to token datas (v2 nfts only) #359

Merged
merged 6 commits into from
May 9, 2024
Merged
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-- This file should undo anything in `up.sql`
ALTER TABLE IF EXISTS current_token_datas_v2 DROP COLUMN is_deleted_v2;
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
-- Your SQL goes here
ALTER TABLE current_token_datas_v2
ADD COLUMN IF NOT EXISTS is_deleted_v2 BOOLEAN;
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ impl TokenActivityV2 {

// the new burn event has owner address now!
let owner_address = if let V2TokenEvent::Burn(inner) = token_event {
Some(inner.get_previous_owner_address())
inner.get_previous_owner_address()
} else {
// To handle a case with the old burn events, when a token is minted and burnt in the same transaction
None
Expand Down
73 changes: 70 additions & 3 deletions rust/processor/src/models/token_v2_models/v2_token_datas.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
#![allow(clippy::extra_unused_lifetimes)]
#![allow(clippy::unused_unit)]

use super::v2_token_utils::{TokenStandard, TokenV2};
use super::v2_token_utils::{TokenStandard, TokenV2, TokenV2Burned};
use crate::{
models::{
object_models::v2_object_utils::ObjectAggregatedDataMapping,
Expand All @@ -14,7 +14,7 @@ use crate::{
schema::{current_token_datas_v2, token_datas_v2},
utils::util::standardize_address,
};
use aptos_protos::transaction::v1::{WriteResource, WriteTableItem};
use aptos_protos::transaction::v1::{DeleteResource, WriteResource, WriteTableItem};
use bigdecimal::BigDecimal;
use diesel::prelude::*;
use field_count::FieldCount;
Expand Down Expand Up @@ -62,8 +62,9 @@ pub struct CurrentTokenDataV2 {
pub is_fungible_v2: Option<bool>,
pub last_transaction_version: i64,
pub last_transaction_timestamp: chrono::NaiveDateTime,
// Deperecated, but still here for backwards compatibility
// Deprecated, but still here for backwards compatibility
pub decimals: Option<i64>,
pub is_deleted_v2: Option<bool>,
}

impl TokenDataV2 {
Expand Down Expand Up @@ -139,13 +140,78 @@ impl TokenDataV2 {
last_transaction_version: txn_version,
last_transaction_timestamp: txn_timestamp,
decimals: None,
is_deleted_v2: Some(false),
},
)))
} else {
Ok(None)
}
}

/// This handles the case where token is burned but objectCore is still there
pub async fn get_burned_nft_v2_from_write_resource(
Copy link
Collaborator

Choose a reason for hiding this comment

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

isn't this case already covered by get_burned_nft_v2_from_delete_resource below?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

no. this is write resource.

Copy link
Collaborator

Choose a reason for hiding this comment

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

when a token gets burnt won't it always have a delete resource?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

What if it's a partial burn and there are resources left?

Copy link
Collaborator

Choose a reason for hiding this comment

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

won't the token resource get deleted so there will always be a delete resource?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

no that's not how it works. unless the resource group is entirely destroyed it'll emit a write resource event :(

write_resource: &WriteResource,
txn_version: i64,
txn_timestamp: chrono::NaiveDateTime,
tokens_burned: &TokenV2Burned,
) -> anyhow::Result<Option<CurrentTokenDataV2>> {
let token_data_id = standardize_address(&write_resource.address.to_string());
// reminder that v1 events won't get to this codepath
if let Some(burn_event_v2) = tokens_burned.get(&standardize_address(&token_data_id)) {
Ok(Some(CurrentTokenDataV2 {
token_data_id,
collection_id: burn_event_v2.get_collection_address(),
token_name: "".to_string(),
maximum: None,
supply: None,
largest_property_version_v1: None,
token_uri: "".to_string(),
token_properties: serde_json::Value::Null,
description: "".to_string(),
token_standard: TokenStandard::V2.to_string(),
is_fungible_v2: Some(false),
last_transaction_version: txn_version,
last_transaction_timestamp: txn_timestamp,
decimals: None,
is_deleted_v2: Some(true),
}))
} else {
Ok(None)
}
}

/// This handles the case where token is burned and objectCore is deleted
pub async fn get_burned_nft_v2_from_delete_resource(
delete_resource: &DeleteResource,
txn_version: i64,
txn_timestamp: chrono::NaiveDateTime,
tokens_burned: &TokenV2Burned,
) -> anyhow::Result<Option<CurrentTokenDataV2>> {
let token_data_id = standardize_address(&delete_resource.address.to_string());
// reminder that v1 events won't get to this codepath
if let Some(burn_event_v2) = tokens_burned.get(&standardize_address(&token_data_id)) {
Ok(Some(CurrentTokenDataV2 {
token_data_id,
collection_id: burn_event_v2.get_collection_address(),
token_name: "".to_string(),
maximum: None,
supply: None,
largest_property_version_v1: None,
token_uri: "".to_string(),
token_properties: serde_json::Value::Null,
description: "".to_string(),
token_standard: TokenStandard::V2.to_string(),
is_fungible_v2: Some(false),
last_transaction_version: txn_version,
last_transaction_timestamp: txn_timestamp,
decimals: None,
is_deleted_v2: Some(true),
}))
} else {
Ok(None)
}
}

pub fn get_v1_from_write_table_item(
table_item: &WriteTableItem,
txn_version: i64,
Expand Down Expand Up @@ -213,6 +279,7 @@ impl TokenDataV2 {
last_transaction_version: txn_version,
last_transaction_timestamp: txn_timestamp,
decimals: None,
is_deleted_v2: None,
},
)));
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -336,8 +336,10 @@ impl TokenOwnershipV2 {
let token_address = standardize_address(token_address);
if let Some(burn_event) = tokens_burned.get(&token_address) {
// 1. Try to lookup token address in burn event mapping
let previous_owner = if let Some(burn_event) = burn_event {
let previous_owner = if let Some(previous_owner) =
burn_event.get_previous_owner_address()
{
previous_owner
} else {
// 2. If it doesn't exist in burn event mapping, then it must be an old burn event that doesn't contain previous_owner.
// Do a lookup to get previous owner. This is necessary because previous owner is part of current token ownerships primary key.
Expand Down
26 changes: 20 additions & 6 deletions rust/processor/src/models/token_v2_models/v2_token_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ pub const TOKEN_V2_ADDR: &str =
pub const DEFAULT_OWNER_ADDRESS: &str = "unknown";

/// Tracks all token related data in a hashmap for quick access (keyed on address of the object core)
/// Maps address to burn event (new). The event is None if it's an old burn event.
pub type TokenV2Burned = AHashMap<CurrentObjectPK, Option<Burn>>;
/// Maps address to burn event. If it's an old event previous_owner will be empty
pub type TokenV2Burned = AHashMap<CurrentObjectPK, Burn>;
pub type TokenV2Minted = AHashSet<CurrentObjectPK>;
pub type TokenV2MintedPK = (CurrentObjectPK, i64);

Expand Down Expand Up @@ -348,13 +348,19 @@ impl BurnEvent {
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Burn {
collection: String,
#[serde(deserialize_with = "deserialize_from_string")]
index: BigDecimal,
token: String,
previous_owner: String,
}

impl Burn {
pub fn new(collection: String, token: String, previous_owner: String) -> Self {
Burn {
collection,
token,
previous_owner,
}
}

pub fn from_event(event: &Event, txn_version: i64) -> anyhow::Result<Option<Self>> {
if let Some(V2TokenEvent::Burn(inner)) =
V2TokenEvent::from_event(event.type_str.as_str(), &event.data, txn_version).unwrap()
Expand All @@ -369,8 +375,16 @@ impl Burn {
standardize_address(&self.token)
}

pub fn get_previous_owner_address(&self) -> String {
standardize_address(&self.previous_owner)
pub fn get_previous_owner_address(&self) -> Option<String> {
if self.previous_owner.is_empty() {
None
} else {
Some(standardize_address(&self.previous_owner))
}
}

pub fn get_collection_address(&self) -> String {
standardize_address(&self.collection)
}
}

Expand Down
Loading
Loading