diff --git a/api/src/context.rs b/api/src/context.rs index e1c6095d19307..2f07de56e8d94 100644 --- a/api/src/context.rs +++ b/api/src/context.rs @@ -32,7 +32,7 @@ use aptos_types::{ account_address::AccountAddress, account_config::{AccountResource, NewBlockEvent}, chain_id::ChainId, - contract_event::EventWithVersion, + contract_event::{ContractEvent, ContractEventV1, EventWithVersion}, event::EventKey, indexer::indexer_db_reader::IndexerReader, ledger_info::LedgerInfoWithSignatures, @@ -820,12 +820,23 @@ impl Context { .into_iter() .zip(infos) .enumerate() - .map(|(i, ((txn, txn_output), info))| { - let version = start_version + i as u64; - let (write_set, events, _, _, _) = txn_output.unpack(); - self.get_accumulator_root_hash(version) - .map(|h| (version, txn, info, events, h, write_set).into()) - }) + .map( + |(i, ((txn, txn_output), info))| -> Result { + let version = start_version + i as u64; + let (write_set, mut events, _, _, _) = txn_output.unpack(); + if self.indexer_reader.is_some() + && self + .node_config + .indexer_db_config + .enable_event_v2_translation + { + self.translate_v2_to_v1_events_for_version(version, &mut events) + .ok(); + } + let h = self.get_accumulator_root_hash(version)?; + Ok((version, txn, info, events, h, write_set).into()) + }, + ) .collect() } @@ -880,7 +891,19 @@ impl Context { })?; txns.into_inner() .into_iter() - .map(|t| self.convert_into_transaction_on_chain_data(t)) + .map(|t| -> Result { + let mut txn = self.convert_into_transaction_on_chain_data(t)?; + if self.indexer_reader.is_some() + && self + .node_config + .indexer_db_config + .enable_event_v2_translation + { + self.translate_v2_to_v1_events_for_version(txn.version, &mut txn.events) + .ok(); + } + Ok(txn) + }) .collect::>>() .context("Failed to parse account transactions") .map_err(|err| E::internal_with_code(err, AptosErrorCode::InternalError, ledger_info)) @@ -891,10 +914,24 @@ impl Context { hash: HashValue, ledger_version: u64, ) -> Result> { - self.db + if let Some(t) = self + .db .get_transaction_by_hash(hash, ledger_version, true)? - .map(|t| self.convert_into_transaction_on_chain_data(t)) - .transpose() + { + let mut txn: TransactionOnChainData = self.convert_into_transaction_on_chain_data(t)?; + if self.indexer_reader.is_some() + && self + .node_config + .indexer_db_config + .enable_event_v2_translation + { + self.translate_v2_to_v1_events_for_version(txn.version, &mut txn.events) + .ok(); + } + Ok(Some(txn)) + } else { + Ok(None) + } } pub async fn get_pending_transaction_by_hash( @@ -917,11 +954,66 @@ impl Context { version: u64, ledger_version: u64, ) -> Result { - self.convert_into_transaction_on_chain_data(self.db.get_transaction_by_version( - version, - ledger_version, - true, - )?) + let mut txn = self.convert_into_transaction_on_chain_data( + self.db + .get_transaction_by_version(version, ledger_version, true)?, + )?; + if self.indexer_reader.is_some() + && self + .node_config + .indexer_db_config + .enable_event_v2_translation + { + self.translate_v2_to_v1_events_for_version(version, &mut txn.events) + .ok(); + } + Ok(txn) + } + + fn translate_v2_to_v1_events_for_version( + &self, + version: u64, + events: &mut [ContractEvent], + ) -> Result<()> { + for (idx, event) in events.iter_mut().enumerate() { + let translated_event = self + .indexer_reader + .as_ref() + .ok_or(anyhow!("Internal indexer reader doesn't exist"))? + .get_translated_v1_event_by_version_and_index(version, idx as u64); + if let Ok(translated_event) = translated_event { + *event = ContractEvent::V1(translated_event); + } + } + Ok(()) + } + + pub fn translate_v2_to_v1_events_for_simulation( + &self, + events: &mut [ContractEvent], + ) -> Result<()> { + let mut count_map: HashMap = HashMap::new(); + for event in events.iter_mut() { + if let ContractEvent::V2(v2) = event { + let translated_event = self + .indexer_reader + .as_ref() + .ok_or(anyhow!("Internal indexer reader doesn't exist"))? + .translate_event_v2_to_v1(v2)?; + if let Some(v1) = translated_event { + let count = count_map.get(v1.key()).unwrap_or(&0); + let v1_adjusted = ContractEventV1::new( + *v1.key(), + v1.sequence_number() + count, + v1.type_tag().clone(), + v1.event_data().to_vec(), + ); + *event = ContractEvent::V1(v1_adjusted); + count_map.insert(*v1.key(), count + 1); + } + } + } + Ok(()) } pub fn get_accumulator_root_hash(&self, version: u64) -> Result { diff --git a/api/src/tests/event_v2_translation_test.rs b/api/src/tests/event_v2_translation_test.rs new file mode 100644 index 0000000000000..7c8ed0aa4a919 --- /dev/null +++ b/api/src/tests/event_v2_translation_test.rs @@ -0,0 +1,912 @@ +// Copyright © Aptos Foundation +// Parts of the project are originally copyright © Meta Platforms, Inc. +// SPDX-License-Identifier: Apache-2.0 + +use super::{new_test_context, new_test_context_with_db_sharding_and_internal_indexer}; +use aptos_api_test_context::{current_function_name, TestContext}; +use aptos_crypto::{ed25519::Ed25519PrivateKey, SigningKey, ValidCryptoMaterial}; +use aptos_sdk::types::LocalAccount; +use aptos_types::account_config::RotationProofChallenge; +use move_core_types::{account_address::AccountAddress, language_storage::CORE_CODE_ADDRESS}; +use serde_json::{json, Value}; +use std::path::PathBuf; + +static MODULE_EVENT_MIGRATION: u64 = 57; + +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn test_feature_enable_disable() { + let mut context = new_test_context(current_function_name!()); + context.enable_feature(MODULE_EVENT_MIGRATION).await; + assert!(context.is_feature_enabled(MODULE_EVENT_MIGRATION).await); + context.disable_feature(MODULE_EVENT_MIGRATION).await; + assert!(!context.is_feature_enabled(MODULE_EVENT_MIGRATION).await); + context.enable_feature(MODULE_EVENT_MIGRATION).await; + assert!(context.is_feature_enabled(MODULE_EVENT_MIGRATION).await); +} + +#[allow(clippy::cmp_owned)] +fn matches_event_details( + event: &Value, + event_type: &str, + creation_number: u64, + account_address: AccountAddress, + sequence_number: u64, +) -> bool { + event["type"] == event_type + && event["guid"]["creation_number"] == creation_number.to_string() + && event["guid"]["account_address"] == account_address.to_hex_literal() + && event["sequence_number"] == sequence_number.to_string() +} + +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn test_event_v2_translation_coin_deposit_event() { + let context = + &mut new_test_context_with_db_sharding_and_internal_indexer(current_function_name!()); + + // Start with the MODULE_EVENT_MIGRATION feature disabled + context.disable_feature(MODULE_EVENT_MIGRATION).await; + + // Create two accounts + let account1 = &mut context.api_create_account().await; + let account2 = &mut context.api_create_account().await; + + // Transfer coins from account1 to account2, emitting V1 events as the feature is disabled + context + .api_execute_aptos_account_transfer(account2, account1.address(), 101) + .await; + + // Enable the MODULE_EVENT_MIGRATION feature + context.enable_feature(MODULE_EVENT_MIGRATION).await; + + // Check the simulation API outputs the translated V1 event rather than the V2 event as it is + let payload = json!({ + "type": "entry_function_payload", + "function": "0x1::coin::transfer", + "type_arguments": ["0x1::aptos_coin::AptosCoin"], + "arguments": [ + account1.address().to_hex_literal(), "102" + ] + }); + let resp = context.simulate_transaction(account2, payload, 200).await; + + let is_expected_event = |e: &Value| { + matches_event_details(e, "0x1::coin::DepositEvent", 2, account1.address(), 2) + && e["data"]["amount"] == "102" + }; + + assert!(resp[0]["events"] + .as_array() + .unwrap() + .iter() + .any(is_expected_event)); + + // Transfer coins from account2 to account1, emitting V2 events as the feature is enabled + context + .api_execute_aptos_account_transfer(account2, account1.address(), 102) + .await; + + // Check the event_by_creation_number API outputs the translated V1 event + let resp = context + .gen_events_by_creation_num(&account1.address(), 2) + .await; + assert!(is_expected_event(resp.as_array().unwrap().last().unwrap())); + + // Check the event_by_handle API outputs the translated V1 event + let resp = context + .gen_events_by_handle( + &account1.address(), + "0x1::coin::CoinStore%3C0x1::aptos_coin::AptosCoin%3E", + "deposit_events", + ) + .await; + assert!(is_expected_event(resp.as_array().unwrap().last().unwrap())); + + // Check the accounts-transactions API outputs the translated V1 event + let resp = context + .get( + format!( + "/accounts/{}/transactions?limit=1", + account2.address().to_hex_literal() + ) + .as_str(), + ) + .await; + assert!(resp[0]["events"] + .as_array() + .unwrap() + .iter() + .any(is_expected_event)); + let hash = resp[0]["hash"].as_str().unwrap(); + let version = resp[0]["version"].as_str().unwrap(); + + // Check the transactions API outputs the translated V1 event + let resp = context + .get(format!("/transactions?start={}&limit=1", version).as_str()) + .await; + assert!(resp[0]["events"] + .as_array() + .unwrap() + .iter() + .any(is_expected_event)); + + // Check the transactions_by_hash API outputs the translated V1 event + let resp = context + .get(format!("/transactions/by_hash/{}", hash).as_str()) + .await; + assert!(resp["events"] + .as_array() + .unwrap() + .iter() + .any(is_expected_event)); + + // Check the transactions_by_version API outputs the translated V1 event + let resp = context + .get(format!("/transactions/by_version/{}", version).as_str()) + .await; + assert!(resp["events"] + .as_array() + .unwrap() + .iter() + .any(is_expected_event)); +} + +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn test_event_v2_translation_coin_withdraw_event() { + let context = + &mut new_test_context_with_db_sharding_and_internal_indexer(current_function_name!()); + + // Start with the MODULE_EVENT_MIGRATION feature disabled + context.disable_feature(MODULE_EVENT_MIGRATION).await; + + // Create two accounts + let account1 = &mut context.api_create_account().await; + let account2 = &mut context.api_create_account().await; + + // Transfer coins from account1 to account2, emitting V1 events as the feature is disabled + context + .api_execute_aptos_account_transfer(account2, account1.address(), 101) + .await; + + // Enable the MODULE_EVENT_MIGRATION feature + context.enable_feature(MODULE_EVENT_MIGRATION).await; + + // Check the simulation API outputs the translated V1 event rather than the V2 event as it is + let payload = json!({ + "type": "entry_function_payload", + "function": "0x1::coin::transfer", + "type_arguments": ["0x1::aptos_coin::AptosCoin"], + "arguments": [ + account1.address().to_hex_literal(), "102" + ] + }); + let resp = context.simulate_transaction(account2, payload, 200).await; + let address2_address = account2.address(); + let is_expected_event = |e: &Value| { + matches_event_details(e, "0x1::coin::WithdrawEvent", 3, address2_address, 1) + && e["data"]["amount"] == "102" + }; + assert!(resp[0]["events"] + .as_array() + .unwrap() + .iter() + .any(is_expected_event)); + + // Transfer coins from account2 to account1, emitting V2 events as the feature is enabled + context + .api_execute_aptos_account_transfer(account2, account1.address(), 102) + .await; + + // Check the event_by_creation_number API outputs the translated V1 event + let resp = context + .gen_events_by_creation_num(&account2.address(), 3) + .await; + assert!(is_expected_event(resp.as_array().unwrap().last().unwrap())); + + // Check the event_by_handle API outputs the translated V1 event + let resp = context + .gen_events_by_handle( + &account2.address(), + "0x1::coin::CoinStore%3C0x1::aptos_coin::AptosCoin%3E", + "withdraw_events", + ) + .await; + assert!(is_expected_event(resp.as_array().unwrap().last().unwrap())); + + // Check the accounts-transactions API outputs the translated V1 event + let resp = context + .get( + format!( + "/accounts/{}/transactions?limit=1", + account2.address().to_hex_literal() + ) + .as_str(), + ) + .await; + assert!(resp[0]["events"] + .as_array() + .unwrap() + .iter() + .any(is_expected_event)); + let hash = resp[0]["hash"].as_str().unwrap(); + let version = resp[0]["version"].as_str().unwrap(); + + // Check the transactions API outputs the translated V1 event + let resp = context + .get(format!("/transactions?start={}&limit=1", version).as_str()) + .await; + assert!(resp[0]["events"] + .as_array() + .unwrap() + .iter() + .any(is_expected_event)); + + // Check the transactions_by_hash API outputs the translated V1 event + let resp = context + .get(format!("/transactions/by_hash/{}", hash).as_str()) + .await; + assert!(resp["events"] + .as_array() + .unwrap() + .iter() + .any(is_expected_event)); + + // Check the transactions_by_version API outputs the translated V1 event + let resp = context + .get(format!("/transactions/by_version/{}", version).as_str()) + .await; + assert!(resp["events"] + .as_array() + .unwrap() + .iter() + .any(is_expected_event)); +} + +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn test_event_v2_translation_account_coin_register_event() { + let context = + &mut new_test_context_with_db_sharding_and_internal_indexer(current_function_name!()); + + // Make sure that the MODULE_EVENT_MIGRATION feature is enabled + context.enable_feature(MODULE_EVENT_MIGRATION).await; + + // Create two accounts + let account1 = &mut context.api_create_account().await; + let account2 = &mut context.gen_account(); + + let is_expected_event = |e: &Value| { + matches_event_details( + e, + "0x1::account::CoinRegisterEvent", + 0, + account2.address(), + 0, + ) && e["data"]["type_info"]["struct_name"] + == format!("0x{}", hex::encode("AptosCoin".to_string().as_bytes())) + }; + + // Transfer coins from account2 to account1, emitting V2 events as the feature is enabled + context + .api_execute_aptos_account_transfer(account1, account2.address(), 102) + .await; + + // Check the event_by_creation_number API outputs the translated V1 event + let resp = context + .gen_events_by_creation_num(&account2.address(), 0) + .await; + assert!(is_expected_event(resp.as_array().unwrap().last().unwrap())); + + // Check the event_by_handle API outputs the translated V1 event + let resp = context + .gen_events_by_handle( + &account2.address(), + "0x1::account::Account", + "coin_register_events", + ) + .await; + assert!(is_expected_event(resp.as_array().unwrap().last().unwrap())); + + // Check the accounts-transactions API outputs the translated V1 event + let resp = context + .get( + format!( + "/accounts/{}/transactions?limit=1", + account1.address().to_hex_literal() + ) + .as_str(), + ) + .await; + assert!(resp[0]["events"] + .as_array() + .unwrap() + .iter() + .any(is_expected_event)); + let hash = resp[0]["hash"].as_str().unwrap(); + let version = resp[0]["version"].as_str().unwrap(); + + // Check the transactions API outputs the translated V1 event + let resp = context + .get(format!("/transactions?start={}&limit=1", version).as_str()) + .await; + assert!(resp[0]["events"] + .as_array() + .unwrap() + .iter() + .any(is_expected_event)); + + // Check the transactions_by_hash API outputs the translated V1 event + let resp = context + .get(format!("/transactions/by_hash/{}", hash).as_str()) + .await; + assert!(resp["events"] + .as_array() + .unwrap() + .iter() + .any(is_expected_event)); + + // Check the transactions_by_version API outputs the translated V1 event + let resp = context + .get(format!("/transactions/by_version/{}", version).as_str()) + .await; + assert!(resp["events"] + .as_array() + .unwrap() + .iter() + .any(is_expected_event)); +} + +fn rotate_authentication_key_payload( + account: &LocalAccount, + new_private_key: &Ed25519PrivateKey, + new_public_key_bytes: Vec, +) -> Value { + let from_scheme = 0; + let to_scheme = 0; + + // Construct a proof challenge struct that proves that + // the user intends to rotate their auth key. + let rotation_proof = RotationProofChallenge { + account_address: CORE_CODE_ADDRESS, + module_name: String::from("account"), + struct_name: String::from("RotationProofChallenge"), + sequence_number: account.sequence_number(), + originator: account.address(), + current_auth_key: AccountAddress::from_bytes(account.authentication_key()).unwrap(), + new_public_key: new_public_key_bytes.clone(), + }; + + let rotation_msg = bcs::to_bytes(&rotation_proof).unwrap(); + + // Sign the rotation message by the current private key and the new private key. + let signature_by_curr_privkey = account.private_key().sign_arbitrary_message(&rotation_msg); + let signature_by_new_privkey = new_private_key.sign_arbitrary_message(&rotation_msg); + + json!({ + "type": "entry_function_payload", + "function": "0x1::account::rotate_authentication_key", + "type_arguments": [], + "arguments": [ + from_scheme, + hex::encode(account.public_key().to_bytes()), + to_scheme, + hex::encode(new_public_key_bytes), + hex::encode(signature_by_curr_privkey.to_bytes()), + hex::encode(signature_by_new_privkey.to_bytes()), + ] + }) +} + +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn test_event_v2_translation_account_key_rotation_event() { + let context = + &mut new_test_context_with_db_sharding_and_internal_indexer(current_function_name!()); + + // Make sure that the MODULE_EVENT_MIGRATION feature is enabled + context.enable_feature(MODULE_EVENT_MIGRATION).await; + + // Create two accounts + let account1 = &mut context.api_create_account().await; + let account2 = &mut context.gen_account(); + + // Check the simulation API outputs the translated V1 event rather than the V2 event as it is + let payload = rotate_authentication_key_payload( + account1, + account2.private_key(), + account2.public_key().to_bytes().to_vec(), + ); + let resp = context + .simulate_transaction(account1, payload.clone(), 200) + .await; + + let account1_address = account1.address(); + let account1_authentication_key = account1.authentication_key(); + let is_expected_event = |e: &Value| { + matches_event_details(e, "0x1::account::KeyRotationEvent", 1, account1_address, 0) + && e["data"]["old_authentication_key"] + == format!("0x{}", hex::encode(account1_authentication_key.to_bytes())) + && e["data"]["new_authentication_key"] + == format!( + "0x{}", + hex::encode(account2.authentication_key().to_bytes()) + ) + }; + + assert!(resp[0]["events"] + .as_array() + .unwrap() + .iter() + .any(is_expected_event)); + + // Rotate authentication key, emitting V2 events as the feature is enabled + context.api_execute_txn(account1, payload).await; + context.wait_for_internal_indexer_caught_up().await; + + // Check the event_by_creation_number API outputs the translated V1 event + let resp = context + .gen_events_by_creation_num(&account1.address(), 1) + .await; + assert!(resp.as_array().unwrap().iter().any(is_expected_event)); + + // Check the event_by_handle API outputs the translated V1 event + let resp = context + .gen_events_by_handle( + &account1.address(), + "0x1::account::Account", + "key_rotation_events", + ) + .await; + assert!(resp.as_array().unwrap().iter().any(is_expected_event)); + + // Check the accounts-transactions API outputs the translated V1 event + let resp = context + .get( + format!( + "/accounts/{}/transactions?limit=1", + account1.address().to_hex_literal() + ) + .as_str(), + ) + .await; + assert!(resp[0]["events"] + .as_array() + .unwrap() + .iter() + .any(is_expected_event)); + let hash = resp[0]["hash"].as_str().unwrap(); + let version = resp[0]["version"].as_str().unwrap(); + + // Check the transactions API outputs the translated V1 event + let resp = context + .get(format!("/transactions?start={}&limit=1", version).as_str()) + .await; + assert!(resp[0]["events"] + .as_array() + .unwrap() + .iter() + .any(is_expected_event)); + + // Check the transactions_by_hash API outputs the translated V1 event + let resp = context + .get(format!("/transactions/by_hash/{}", hash).as_str()) + .await; + assert!(resp["events"] + .as_array() + .unwrap() + .iter() + .any(is_expected_event)); + + // Check the transactions_by_version API outputs the translated V1 event + let resp = context + .get(format!("/transactions/by_version/{}", version).as_str()) + .await; + assert!(resp["events"] + .as_array() + .unwrap() + .iter() + .any(is_expected_event)); +} + +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn test_event_v2_translation_token_objects() { + let context = + &mut new_test_context_with_db_sharding_and_internal_indexer(current_function_name!()); + + // Make sure that the MODULE_EVENT_MIGRATION feature is enabled + context.enable_feature(MODULE_EVENT_MIGRATION).await; + + // Create two accounts + let creator = &mut context.api_create_account().await; + let user = &mut context.api_create_account().await; + + let creator_addr = creator.address(); + let user_addr = user.address(); + + let named_addresses = vec![("addr".to_string(), creator_addr)]; + let txn = futures::executor::block_on(async move { + let path = PathBuf::from(std::env!("CARGO_MANIFEST_DIR")) + .join("src/tests/move/pack_token_objects"); + TestContext::build_package(path, named_addresses) + }); + context.publish_package(creator, txn).await; + context.wait_for_internal_indexer_caught_up().await; + + let payload = json!({ + "type": "entry_function_payload", + "function": format!("{}::token_objects::run", creator_addr.to_hex_literal()), + "type_arguments": [], + "arguments": [ + user_addr.to_hex_literal() + ] + }); + context.api_execute_txn(creator, payload).await; + context.wait_for_internal_indexer_caught_up().await; + let resp = context + .get( + format!( + "/accounts/{}/transactions?limit=1", + creator_addr.to_hex_literal() + ) + .as_str(), + ) + .await; + + // Test TransferTranslator + assert!(resp[0]["events"] + .as_array() + .unwrap() + .iter() + .any(|e: &Value| { + e["type"] == "0x1::object::TransferEvent" + && e["sequence_number"] == "0" + && e["data"]["from"] == creator_addr.to_hex_literal() + && e["data"]["to"] == user_addr.to_hex_literal() + })); + + // Test TokenMutationTranslator + assert!(resp[0]["events"] + .as_array() + .unwrap() + .iter() + .any(|e: &Value| { + e["type"] == "0x4::token::MutationEvent" + && e["sequence_number"] == "0" + && e["data"]["mutated_field_name"] == *"uri" + })); + + // Test CollectionMutationTranslator + assert!(resp[0]["events"] + .as_array() + .unwrap() + .iter() + .any(|e: &Value| { + e["type"] == "0x4::collection::MutationEvent" + && e["sequence_number"] == "0" + && e["data"]["mutated_field_name"] == *"uri" + })); + + // Test MintTranslator + // The example Move package uses ConcurrentSupply which doesn't have the mint event handle. + // So, the mint event is not translated in this case. + assert!(resp[0]["events"] + .as_array() + .unwrap() + .iter() + .any(|e: &Value| { + e["type"] == "0x4::collection::Mint" + && e["guid"]["account_address"] == *"0x0" + && e["sequence_number"] == "0" + })); + // The cases with FixedSupply and UnlimitedSupply have been tested in the localnet. + // In those cases, the mint event is translated correctly as follows: + // Object { + // "guid": Object { + // "creation_number": String("1125899906842626"), + // "account_address": String("0x999a601c1abf720ccb54acae160a980f9a35209611a12b1e31e091172ed061fc"), + // }, + // "sequence_number": String("0"), + // "type": String("0x4::collection::MintEvent"), + // "data": Object { + // "index": String("1"), + // "token": String("0x7dbdec16c12211da2db477a15941df2495218ceb6c221da7bd3efcb93d75cffe"), + // }, + // }, + + let payload = json!({ + "type": "entry_function_payload", + "function": format!("{}::token_objects::burn", creator_addr.to_hex_literal()), + "type_arguments": [], + "arguments": [ + "0x7dbdec16c12211da2db477a15941df2495218ceb6c221da7bd3efcb93d75cffe" + ] + }); + context.api_execute_txn(creator, payload).await; + context.wait_for_internal_indexer_caught_up().await; + let resp = context + .get( + format!( + "/accounts/{}/transactions?limit=1", + creator_addr.to_hex_literal() + ) + .as_str(), + ) + .await; + + // Test BurnTranslator + // The example Move package uses ConcurrentSupply which doesn't have the burn event handle. + // So, the burn event is not translated in this case. + assert!(resp[0]["events"] + .as_array() + .unwrap() + .iter() + .any(|e: &Value| { + e["type"] == "0x4::collection::Burn" + && e["guid"]["account_address"] == *"0x0" + && e["sequence_number"] == "0" + })); + // The cases with FixedSupply and UnlimitedSupply have been tested in the localnet. + // In those cases, the burn event is translated correctly as follows: + // Object { + // "guid": Object { + // "creation_number": String("1125899906842625"), + // "account_address": String("0x999a601c1abf720ccb54acae160a980f9a35209611a12b1e31e091172ed061fc"), + // }, + // "sequence_number": String("0"), + // "type": String("0x4::collection::BurnEvent"), + // "data": Object { + // "index": String("1"), + // "token": String("0x7dbdec16c12211da2db477a15941df2495218ceb6c221da7bd3efcb93d75cffe"), + // }, + // }, +} + +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn test_event_v2_translation_token_v1() { + let context = + &mut new_test_context_with_db_sharding_and_internal_indexer(current_function_name!()); + + // Make sure that the MODULE_EVENT_MIGRATION feature is enabled + context.enable_feature(MODULE_EVENT_MIGRATION).await; + + // Create two accounts + let creator = &mut context.api_create_account().await; + // let user = &mut context.api_create_account().await; + + let creator_addr = creator.address(); + // let user_addr = user.address(); + + let named_addresses = vec![("addr".to_string(), creator_addr)]; + let txn = futures::executor::block_on(async move { + let path = + PathBuf::from(std::env!("CARGO_MANIFEST_DIR")).join("src/tests/move/pack_token_v1"); + TestContext::build_package(path, named_addresses) + }); + context.publish_package(creator, txn).await; + context.wait_for_internal_indexer_caught_up().await; + + let payload = json!({ + "type": "entry_function_payload", + "function": format!("{}::token_v1::run", creator_addr.to_hex_literal()), + "type_arguments": [], + "arguments": [ + ] + }); + context.api_execute_txn(creator, payload).await; + context.wait_for_internal_indexer_caught_up().await; + let resp = context + .get( + format!( + "/accounts/{}/transactions?limit=1", + creator_addr.to_hex_literal() + ) + .as_str(), + ) + .await; + + // Test TokenDepositTranslator + assert!(resp[0]["events"] + .as_array() + .unwrap() + .iter() + .any(|e: &Value| { + e["type"] == "0x3::token::DepositEvent" + && e["sequence_number"] == "4" + && e["data"]["id"]["token_data_id"]["creator"] == creator_addr.to_hex_literal() + })); + + // Test TokenWithdrawTranslator + assert!(resp[0]["events"] + .as_array() + .unwrap() + .iter() + .any(|e: &Value| { + e["type"] == "0x3::token::WithdrawEvent" + && e["sequence_number"] == "4" + && e["data"]["id"]["token_data_id"]["creator"] == creator_addr.to_hex_literal() + })); + + // Test BurnTokenTranslator + assert!(resp[0]["events"] + .as_array() + .unwrap() + .iter() + .any(|e: &Value| { + e["type"] == "0x3::token::BurnTokenEvent" + && e["sequence_number"] == "0" + && e["data"]["id"]["token_data_id"]["creator"] == creator_addr.to_hex_literal() + })); + + // Test MutatePropertyMapTranslator + assert!(resp[0]["events"] + .as_array() + .unwrap() + .iter() + .any(|e: &Value| { + e["type"] == "0x3::token::MutateTokenPropertyMapEvent" + && e["sequence_number"] == "0" + && e["data"]["new_id"]["property_version"] == "1" + })); + + // Test MintTokenTranslator + assert!(resp[0]["events"] + .as_array() + .unwrap() + .iter() + .any(|e: &Value| { + e["type"] == "0x3::token::MintTokenEvent" + && e["sequence_number"] == "0" + && e["data"]["amount"] == "10" + })); + + // Test CreateCollectionTranslator + assert!(resp[0]["events"] + .as_array() + .unwrap() + .iter() + .any(|e: &Value| { + e["type"] == "0x3::token::CreateCollectionEvent" + && e["sequence_number"] == "0" + && e["data"]["creator"] == creator_addr.to_hex_literal() + })); + + // Test TokenDataCreationTranslator + assert!(resp[0]["events"] + .as_array() + .unwrap() + .iter() + .any(|e: &Value| { + e["type"] == "0x3::token::CreateTokenDataEvent" + && e["sequence_number"] == "0" + && e["data"]["name"] == "Token 1" + })); + + // Test OfferTranslator + assert!(resp[0]["events"] + .as_array() + .unwrap() + .iter() + .any(|e: &Value| { + e["type"] == "0x3::token_transfers::TokenOfferEvent" + && e["sequence_number"] == "1" + && e["data"]["amount"] == "1" + })); + + // Test CancelOfferTranslator + assert!(resp[0]["events"] + .as_array() + .unwrap() + .iter() + .any(|e: &Value| { + e["type"] == "0x3::token_transfers::TokenCancelOfferEvent" + && e["sequence_number"] == "0" + && e["data"]["amount"] == "1" + })); + + // Test ClaimTranslator + assert!(resp[0]["events"] + .as_array() + .unwrap() + .iter() + .any(|e: &Value| { + e["type"] == "0x3::token_transfers::TokenClaimEvent" + && e["sequence_number"] == "0" + && e["data"]["amount"] == "1" + })); + + // Test CollectionDescriptionMutateTranslator + assert!(resp[0]["events"] + .as_array() + .unwrap() + .iter() + .any(|e: &Value| { + e["type"] == "0x3::token_event_store::CollectionDescriptionMutateEvent" + && e["sequence_number"] == "0" + && e["data"]["creator_addr"] == creator_addr.to_hex_literal() + })); + + // Test CollectionUriMutateTranslator + assert!(resp[0]["events"] + .as_array() + .unwrap() + .iter() + .any(|e: &Value| { + e["type"] == "0x3::token_event_store::CollectionUriMutateEvent" + && e["sequence_number"] == "0" + && e["data"]["creator_addr"] == creator_addr.to_hex_literal() + })); + + // Test CollectionMaximumMutateTranslator + assert!(resp[0]["events"] + .as_array() + .unwrap() + .iter() + .any(|e: &Value| { + e["type"] == "0x3::token_event_store::CollectionMaxiumMutateEvent" + && e["sequence_number"] == "0" + && e["data"]["creator_addr"] == creator_addr.to_hex_literal() + })); + + // Test UriMutationTranslator + assert!(resp[0]["events"] + .as_array() + .unwrap() + .iter() + .any(|e: &Value| { + e["type"] == "0x3::token_event_store::UriMutationEvent" + && e["sequence_number"] == "0" + && e["data"]["creator"] == creator_addr.to_hex_literal() + })); + + // Test DefaultPropertyMutateTranslator + assert!(resp[0]["events"] + .as_array() + .unwrap() + .iter() + .any(|e: &Value| { + e["type"] == "0x3::token_event_store::DefaultPropertyMutateEvent" + && e["sequence_number"] == "0" + && e["data"]["creator"] == creator_addr.to_hex_literal() + })); + + // Test DescriptionMutateTranslator + assert!(resp[0]["events"] + .as_array() + .unwrap() + .iter() + .any(|e: &Value| { + e["type"] == "0x3::token_event_store::DescriptionMutateEvent" + && e["sequence_number"] == "0" + && e["data"]["creator"] == creator_addr.to_hex_literal() + })); + + // Test RoyaltyMutateTranslator + assert!(resp[0]["events"] + .as_array() + .unwrap() + .iter() + .any(|e: &Value| { + e["type"] == "0x3::token_event_store::RoyaltyMutateEvent" + && e["sequence_number"] == "0" + && e["data"]["creator"] == creator_addr.to_hex_literal() + })); + + // Test MaximumMutateTranslator + assert!(resp[0]["events"] + .as_array() + .unwrap() + .iter() + .any(|e: &Value| { + e["type"] == "0x3::token_event_store::MaxiumMutateEvent" + && e["sequence_number"] == "0" + && e["data"]["creator"] == creator_addr.to_hex_literal() + })); + + // Test OptInTransferTranslator + assert!(resp[0]["events"] + .as_array() + .unwrap() + .iter() + .any(|e: &Value| { + e["type"] == "0x3::token_event_store::OptInTransferEvent" + && e["sequence_number"] == "0" + && e["data"]["opt_in"] == Value::Bool(true) + })); +} diff --git a/api/src/tests/mod.rs b/api/src/tests/mod.rs index 340721b1ce200..43468220043b8 100644 --- a/api/src/tests/mod.rs +++ b/api/src/tests/mod.rs @@ -5,6 +5,7 @@ mod accounts_test; mod blocks_test; mod converter_test; +mod event_v2_translation_test; mod events_test; mod index_test; mod invalid_post_request_test; @@ -36,7 +37,7 @@ fn new_test_context_with_config(test_name: String, node_config: NodeConfig) -> T fn new_test_context_with_db_sharding_and_internal_indexer(test_name: String) -> TestContext { let mut node_config = NodeConfig::default(); node_config.storage.rocksdb_configs.enable_storage_sharding = true; - node_config.indexer_db_config = InternalIndexerDBConfig::new(true, true, true, 10); + node_config.indexer_db_config = InternalIndexerDBConfig::new(true, true, true, 0, true, 10); let test_context = super_new_test_context(test_name, node_config, false, None); let _ = test_context .get_indexer_reader() @@ -51,6 +52,6 @@ fn new_test_context_with_sharding_and_delayed_internal_indexer( ) -> TestContext { let mut node_config = NodeConfig::default(); node_config.storage.rocksdb_configs.enable_storage_sharding = true; - node_config.indexer_db_config = InternalIndexerDBConfig::new(true, true, true, 1); + node_config.indexer_db_config = InternalIndexerDBConfig::new(true, true, true, 0, true, 1); super_new_test_context(test_name, node_config, false, end_version) } diff --git a/api/src/tests/move/pack_token_objects/Move.toml b/api/src/tests/move/pack_token_objects/Move.toml new file mode 100644 index 0000000000000..dc432ee0a11ad --- /dev/null +++ b/api/src/tests/move/pack_token_objects/Move.toml @@ -0,0 +1,10 @@ +[package] +name = "pack_token_objects" +version = "0.0.0" + +[dependencies] +AptosFramework = { local = "../../../../../aptos-move/framework/aptos-framework" } +AptosTokenObjects = { local = "../../../../../aptos-move/framework/aptos-token-objects" } + +[addresses] +addr = "_" diff --git a/api/src/tests/move/pack_token_objects/sources/token_objects.move b/api/src/tests/move/pack_token_objects/sources/token_objects.move new file mode 100644 index 0000000000000..5e20f844f3282 --- /dev/null +++ b/api/src/tests/move/pack_token_objects/sources/token_objects.move @@ -0,0 +1,415 @@ +module addr::token_objects { + use std::error; + use std::option; + use std::string::{Self, String}; + use std::signer; + + use aptos_framework::object::{Self, Object}; + use aptos_token_objects::collection; + use aptos_token_objects::token; + use aptos_token_objects::property_map; + use aptos_framework::event; + use aptos_std::string_utils::{to_string}; + + /// The token does not exist + const ETOKEN_DOES_NOT_EXIST: u64 = 1; + /// The provided signer is not the creator + const ENOT_CREATOR: u64 = 2; + /// Attempted to mutate an immutable field + const EFIELD_NOT_MUTABLE: u64 = 3; + /// Attempted to burn a non-burnable token + const ETOKEN_NOT_BURNABLE: u64 = 4; + /// Attempted to mutate a property map that is not mutable + const EPROPERTIES_NOT_MUTABLE: u64 = 5; + // The collection does not exist + const ECOLLECTION_DOES_NOT_EXIST: u64 = 6; + + /// The ambassador token collection name + const COLLECTION_NAME: vector = b"Ambassador Collection Name"; + /// The ambassador token collection description + const COLLECTION_DESCRIPTION: vector = b"Ambassador Collection Description"; + /// The ambassador token collection URI + const COLLECTION_URI: vector = b"Ambassador Collection URI"; + + /// The ambassador rank + const RANK_GOLD: vector = b"Gold"; + const RANK_SILVER: vector = b"Silver"; + const RANK_BRONZE: vector = b"Bronze"; + + #[resource_group_member(group = aptos_framework::object::ObjectGroup)] + /// The ambassador token + struct AmbassadorToken has key { + /// Used to mutate the token uri + mutator_ref: token::MutatorRef, + /// Used to burn. + burn_ref: token::BurnRef, + /// Used to mutate properties + property_mutator_ref: property_map::MutatorRef, + /// the base URI of the token + base_uri: String, + } + + #[resource_group_member(group = aptos_framework::object::ObjectGroup)] + /// The ambassador level + struct AmbassadorLevel has key { + ambassador_level: u64, + } + + #[event] + /// The ambassador level update event + struct LevelUpdate has drop, store { + token: Object, + old_level: u64, + new_level: u64, + } + + #[view] + /// Returns the ambassador level of the token + public fun ambassador_level(token: Object): u64 acquires AmbassadorLevel { + let ambassador_level = borrow_global(object::object_address(&token)); + ambassador_level.ambassador_level + } + + #[view] + /// Returns the ambassador rank of the token + public fun ambassador_rank(token: Object): String { + property_map::read_string(&token, &string::utf8(b"Rank")) + } + + #[view] + /// Returns the ambassador level of the token of the address + public fun ambassador_level_from_address(addr: address): u64 acquires AmbassadorLevel { + let token = object::address_to_object(addr); + ambassador_level(token) + } + + #[view] + /// Returns the ambassador rank of the token of the address + public fun ambassador_rank_from_address(addr: address): String { + let token = object::address_to_object(addr); + ambassador_rank(token) + } + + /// Creates the ambassador collection. This function creates a collection with unlimited supply using + /// the module constants for description, name, and URI, defined above. The collection will not have + /// any royalty configuration because the tokens in this collection will not be transferred or sold. + fun create_ambassador_collection(creator: &signer) { + // Constructs the strings from the bytes. + let description = string::utf8(COLLECTION_DESCRIPTION); + let name = string::utf8(COLLECTION_NAME); + let uri = string::utf8(COLLECTION_URI); + + // Creates the collection with unlimited supply and without establishing any royalty configuration. + + // let constructor_ref = collection::create_unlimited_collection( + let constructor_ref = collection::create_unlimited_collection( + creator, + description, + name, + option::none(), + uri, + ); + + let mutator_ref = collection::generate_mutator_ref(&constructor_ref); + collection::set_uri(&mutator_ref, string::utf8(b"Ambassador Collection URI 2")); + } + + /// Mints an ambassador token. This function mints a new ambassador token and transfers it to the + /// `soul_bound_to` address. The token is minted with level 0 and rank Bronze. + public entry fun mint_ambassador_token( + creator: &signer, + description: String, + name: String, + base_uri: String, + soul_bound_to: address, + ) { + mint_ambassador_token_impl(creator, description, name, base_uri, soul_bound_to, false); + } + + /// Mints an ambassador token. This function mints a new ambassador token and transfers it to the + /// `soul_bound_to` address. The token is minted with level 0 and rank Bronze. + public entry fun mint_numbered_ambassador_token( + creator: &signer, + description: String, + name: String, + base_uri: String, + soul_bound_to: address, + ) { + mint_ambassador_token_impl(creator, description, name, base_uri, soul_bound_to, true); + } + + /// Function used for benchmarking. + /// Uses multisig to mint to user, with creator permissions. + /// Uses users address as unique name of the soulbound token. + public entry fun mint_ambassador_token_by_user( + user: &signer, + creator: &signer, + description: String, + uri: String, + ) { + let user_addr = signer::address_of(user); + mint_ambassador_token(creator, description, to_string
(&user_addr), uri, user_addr); + } + + /// Function used for benchmarking. + /// Uses multisig to mint to user, with creator permissions. + public entry fun mint_numbered_ambassador_token_by_user( + user: &signer, + creator: &signer, + description: String, + name: String, + uri: String, + ) { + mint_numbered_ambassador_token(creator, description, name, uri, signer::address_of(user)); + } + + /// Mints an ambassador token. This function mints a new ambassador token and transfers it to the + /// `soul_bound_to` address. The token is minted with level 0 and rank Bronze. + fun mint_ambassador_token_impl( + creator: &signer, + description: String, + name: String, + base_uri: String, + soul_bound_to: address, + numbered: bool, + ) { + // The collection name is used to locate the collection object and to create a new token object. + let collection = string::utf8(COLLECTION_NAME); + // Creates the ambassador token, and get the constructor ref of the token. The constructor ref + // is used to generate the refs of the token. + let uri = base_uri; + string::append(&mut uri, string::utf8(RANK_BRONZE)); + let constructor_ref = if (numbered) { + token::create_numbered_token( + creator, + collection, + description, + name, + string::utf8(b""), + option::none(), + uri, + ) + } else { + token::create_named_token( + creator, + collection, + description, + name, + option::none(), + uri, + ) + }; + + // Generates the object signer and the refs. The object signer is used to publish a resource + // (e.g., AmbassadorLevel) under the token object address. The refs are used to manage the token. + let object_signer = object::generate_signer(&constructor_ref); + let transfer_ref = object::generate_transfer_ref(&constructor_ref); + let mutator_ref = token::generate_mutator_ref(&constructor_ref); + let burn_ref = token::generate_burn_ref(&constructor_ref); + let property_mutator_ref = property_map::generate_mutator_ref(&constructor_ref); + + // Transfers the token to the `soul_bound_to` address + let linear_transfer_ref = object::generate_linear_transfer_ref(&transfer_ref); + object::transfer_with_ref(linear_transfer_ref, soul_bound_to); + + // Disables ungated transfer, thus making the token soulbound and non-transferable + object::disable_ungated_transfer(&transfer_ref); + + // Initializes the ambassador level as 0 + move_to(&object_signer, AmbassadorLevel { ambassador_level: 0 }); + + // Initialize the property map and the ambassador rank as Bronze + let properties = property_map::prepare_input(vector[], vector[], vector[]); + property_map::init(&constructor_ref, properties); + property_map::add_typed( + &property_mutator_ref, + string::utf8(b"Rank"), + string::utf8(RANK_BRONZE) + ); + + // Publishes the AmbassadorToken resource with the refs. + let ambassador_token = AmbassadorToken { + mutator_ref, + burn_ref, + property_mutator_ref, + base_uri + }; + move_to(&object_signer, ambassador_token); + } + + /// Burns an ambassador token. This function burns the ambassador token and destroys the + /// AmbassadorToken resource, AmbassadorLevel resource, the event handle, and the property map. + public entry fun burn(creator: &signer, token: Object) acquires AmbassadorToken, AmbassadorLevel { + authorize_creator(creator, &token); + let ambassador_token = move_from(object::object_address(&token)); + let AmbassadorToken { + mutator_ref: _, + burn_ref, + property_mutator_ref, + base_uri: _ + } = ambassador_token; + + let AmbassadorLevel { + ambassador_level: _ + } = move_from(object::object_address(&token)); + + property_map::burn(property_mutator_ref); + token::burn(burn_ref); + } + + /// Function used for benchmarking. + /// Uses multisig to mint to user, with creator permissions. + /// Uses users address as unique name of the soulbound token. + /// Burns token that was minted by mint_ambassador_token_by_user + public entry fun burn_named_by_user(user: &signer, creator: &signer) acquires AmbassadorToken, AmbassadorLevel { + let collection_name = string::utf8(COLLECTION_NAME); + let token_address = token::create_token_address( + &signer::address_of(creator), + &collection_name, + &to_string
(&signer::address_of(user)), + ); + let token = object::address_to_object(token_address); + burn(creator, token); + } + + /// Sets the ambassador level of the token. Only the creator of the token can set the level. When the level + /// is updated, the `LevelUpdate` is emitted. The ambassador rank is updated based on the new level. + public entry fun set_ambassador_level( + creator: &signer, + token: Object, + new_ambassador_level: u64 + ) acquires AmbassadorLevel, AmbassadorToken { + // Asserts that `creator` is the creator of the token. + authorize_creator(creator, &token); + + let token_address = object::object_address(&token); + let ambassador_level = borrow_global_mut(token_address); + // Emits the `LevelUpdate`. + event::emit( + LevelUpdate { + token, + old_level: ambassador_level.ambassador_level, + new_level: new_ambassador_level, + } + ); + // Updates the ambassador level. + ambassador_level.ambassador_level = new_ambassador_level; + // Updates the ambassador rank based on the new level. + update_ambassador_rank(token, new_ambassador_level); + } + + /// Updates the ambassador rank of the token based on the new level + fun update_ambassador_rank( + token: Object, + new_ambassador_level: u64 + ) acquires AmbassadorToken { + // `new_rank` is determined based on the new level. + let new_rank = if (new_ambassador_level < 10) { + RANK_BRONZE + } else if (new_ambassador_level < 20) { + RANK_SILVER + } else { + RANK_GOLD + }; + + let token_address = object::object_address(&token); + let ambassador_token = borrow_global(token_address); + // Gets `property_mutator_ref` to update the rank in the property map. + let property_mutator_ref = &ambassador_token.property_mutator_ref; + // Updates the rank in the property map. + property_map::update_typed(property_mutator_ref, &string::utf8(b"Rank"), string::utf8(new_rank)); + // Updates the token URI based on the new rank. + let uri = ambassador_token.base_uri; + string::append(&mut uri, string::utf8(new_rank)); + token::set_uri(&ambassador_token.mutator_ref, uri); + } + + /// Authorizes the creator of the token. Asserts that the token exists and the creator of the token + /// is `creator`. + inline fun authorize_creator(creator: &signer, token: &Object) { + let token_address = object::object_address(token); + assert!( + exists(token_address), + error::not_found(ETOKEN_DOES_NOT_EXIST), + ); + assert!( + token::creator(*token) == signer::address_of(creator), + error::permission_denied(ENOT_CREATOR), + ); + } + + public entry fun run(creator: &signer, user_addr: address) acquires AmbassadorToken, AmbassadorLevel { + // ------------------------------------------ + // Creator creates the Ambassador Collection. + // ------------------------------------------ + create_ambassador_collection(creator); + + // ------------------------------------------- + // Creator mints a Ambassador token for User1. + // ------------------------------------------- + let token_name = string::utf8(b"Ambassador Token #1"); + let token_description = string::utf8(b"Ambassador Token #1 Description"); + let token_uri = string::utf8(b"Ambassador Token #1 URI/"); + // Creates the Ambassador token for User1. + mint_ambassador_token( + creator, + token_description, + token_name, + token_uri, + user_addr, + ); + let collection_name = string::utf8(COLLECTION_NAME); + let token_address = token::create_token_address( + &signer::address_of(creator), + &collection_name, + &token_name + ); + let token = object::address_to_object(token_address); + // Asserts that the owner of the token is User1. + assert!(object::owner(token) == user_addr, 1); + + // ----------------------- + // Creator sets the level. + // ----------------------- + // Asserts that the initial level of the token is 0. + assert!(ambassador_level(token) == 0, 2); + // Asserts that the initial rank of the token is "Bronze". + assert!(ambassador_rank(token) == string::utf8(RANK_BRONZE), 3); + assert!(token::uri(token) == string::utf8(b"Ambassador Token #1 URI/Bronze"), 4); + // `creator` sets the level to 15. + set_ambassador_level(creator, token, 15); + // Asserts that the level is updated to 15. + assert!(ambassador_level(token) == 15, 4); + // Asserts that the rank is updated to "Silver" which is the expected rank for level 15. + assert!(token::uri(token) == string::utf8(b"Ambassador Token #1 URI/Silver"), 5); + + // // ------------------------ + // // Creator burns the token. + // // ------------------------ + // let token_addr = object::object_address(&token); + // // Asserts that the token exists before burning. + // assert!(exists(token_addr), 6); + // // Burns the token. + // burn(creator, token); + // // Asserts that the token does not exist after burning. + // assert!(!exists(token_addr), 7); + } + + #[test(creator = @0x123, user1 = @0x456)] + fun test_mint_burn_by_user(creator: &signer, user1: &signer) acquires AmbassadorToken, AmbassadorLevel { + // ------------------------------------------ + // Creator creates the Ambassador Collection. + // ------------------------------------------ + create_ambassador_collection(creator); + + let token_description = string::utf8(b"Ambassador Token #1 Description"); + let token_uri = string::utf8(b"Ambassador Token #1 URI/"); + mint_ambassador_token_by_user( + user1, + creator, + token_description, + token_uri + ); + burn_named_by_user(user1, creator); + } +} diff --git a/api/src/tests/move/pack_token_v1/Move.toml b/api/src/tests/move/pack_token_v1/Move.toml new file mode 100644 index 0000000000000..c459b5fa469bc --- /dev/null +++ b/api/src/tests/move/pack_token_v1/Move.toml @@ -0,0 +1,11 @@ +[package] +name = "pack_token_v1" +version = "0.0.0" + +[dependencies] +MoveStdlib = { local = "../../../../../aptos-move/framework/move-stdlib" } +AptosFramework = { local = "../../../../../aptos-move/framework/aptos-framework" } +AptosToken = { local = "../../../../../aptos-move/framework/aptos-token" } + +[addresses] +addr = "_" diff --git a/api/src/tests/move/pack_token_v1/sources/token_v1.move b/api/src/tests/move/pack_token_v1/sources/token_v1.move new file mode 100644 index 0000000000000..b1c70cd8e782e --- /dev/null +++ b/api/src/tests/move/pack_token_v1/sources/token_v1.move @@ -0,0 +1,123 @@ +module addr::token_v1 { + use std::string::{Self, String}; + use std::signer; + use std::bcs; + use aptos_token::token; + use aptos_token::property_map; + use aptos_token::token_transfers; + + /// The ambassador token collection name + const COLLECTION_NAME: vector = b"Ambassador Collection Name"; + /// The ambassador token collection description + const COLLECTION_DESCRIPTION: vector = b"Ambassador Collection Description"; + /// The ambassador token collection URI + const COLLECTION_URI: vector = b"Ambassador Collection URI"; + + const TOKEN_NAME: vector = b"Token 1"; + + public entry fun run(creator: &signer) { + token::create_collection( + creator, + string::utf8(COLLECTION_NAME), + string::utf8(COLLECTION_DESCRIPTION), + string::utf8(COLLECTION_URI), + 100, + vector[true, true, true], + ); + let default_keys = vector[string::utf8(b"attack"), string::utf8(b"num_of_use"), string::utf8(b"TOKEN_BURNABLE_BY_OWNER")]; + let default_vals = vector>[bcs::to_bytes(&10), bcs::to_bytes(&5), bcs::to_bytes(&true)]; + let default_types = vector[string::utf8(b"u64"), string::utf8(b"u64"), string::utf8(b"bool")]; + let mutate_setting = vector[true, true, true, true, true]; + + let amount = 10; + let token_max = 100; + + token::create_token_script( + creator, + string::utf8(COLLECTION_NAME), + string::utf8(TOKEN_NAME), + string::utf8(b"Hello, Token"), + amount, + token_max, + string::utf8(b"https://aptos.dev"), + signer::address_of(creator), + 100, + 0, + mutate_setting, + default_keys, + default_vals, + default_types, + ); + let token_id = token::create_token_id_raw( + signer::address_of(creator), + string::utf8(COLLECTION_NAME), + string::utf8(TOKEN_NAME), + 0 + ); + let new_keys = vector[ + string::utf8(b"attack"), string::utf8(b"num_of_use") + ]; + let new_vals = vector>[ + bcs::to_bytes(&1), bcs::to_bytes(&1) + ]; + let new_types = vector[ + string::utf8(b"u64"), string::utf8(b"u64") + ]; + let new_token_id = token::mutate_one_token( + creator, + signer::address_of(creator), + token_id, + new_keys, + new_vals, + new_types, + ); + let updated_pm = token::get_property_map(signer::address_of(creator), new_token_id); + property_map::update_property_value( + &mut updated_pm, + &string::utf8(b"attack"), + property_map::create_property_value(&2), + ); + + let creator_addr = signer::address_of(creator); + let token_data_id = token::create_token_data_id(signer::address_of(creator), string::utf8(COLLECTION_NAME), string::utf8(TOKEN_NAME)); + token::mutate_tokendata_uri(creator, token_data_id, string::utf8(b"new_uri")); + token::mutate_tokendata_property(creator, token_data_id, new_keys, + new_vals, + new_types); + token::mutate_tokendata_description(creator, token_data_id, string::utf8(b"new_description")); + let royalty = token::create_royalty(50, 100, creator_addr); + token::mutate_tokendata_royalty(creator, token_data_id, royalty); + token::mutate_tokendata_maximum(creator, token_data_id, 1001); + + token::mutate_collection_description(creator, string::utf8(COLLECTION_NAME), string::utf8(b"new_collection_description")); + token::mutate_collection_uri(creator, string::utf8(COLLECTION_NAME), string::utf8(b"new_collection_uri")); + token::mutate_collection_maximum(creator, string::utf8(COLLECTION_NAME), 2002); + + let token_0 = token::withdraw_token(creator, token_id, 1); + token::deposit_token(creator, token_0); + + token::burn( + creator, + signer::address_of(creator), + string::utf8(COLLECTION_NAME), + string::utf8(TOKEN_NAME), + 0, + 1 + ); + + token_transfers::offer(creator, creator_addr, token_id, 1); + token_transfers::claim(creator, creator_addr, token_id); + + token_transfers::offer(creator, creator_addr, token_id, 1); + token_transfers::cancel_offer(creator, creator_addr, token_id); + + token::opt_in_direct_transfer(creator, true); + } + + #[test(creator = @0xAF, owner = @0xBB)] + fun test(creator: &signer) { + use 0x1::account; + account::create_account_for_test(signer::address_of(creator)); + run(creator); + } +} diff --git a/api/src/transactions.rs b/api/src/transactions.rs index 56495de0ad2c6..03f0f73e73ced 100644 --- a/api/src/transactions.rs +++ b/api/src/transactions.rs @@ -1439,11 +1439,16 @@ impl TransactionsApi { output.gas_used(), exe_status, ); + let mut events = output.events().to_vec(); + let _ = self + .context + .translate_v2_to_v1_events_for_simulation(&mut events); + let simulated_txn = TransactionOnChainData { version, transaction: txn, info, - events: output.events().to_vec(), + events, accumulator_root_hash: zero_hash, changes: output.write_set().clone(), }; diff --git a/api/test-context/src/test_context.rs b/api/test-context/src/test_context.rs index 99ff148314c0c..f03354eb89ac4 100644 --- a/api/test-context/src/test_context.rs +++ b/api/test-context/src/test_context.rs @@ -373,6 +373,56 @@ impl TestContext { ) } + pub async fn enable_feature(&mut self, feature: u64) { + // This function executes the following script as the root account: + // script { + // fun main(root: &signer, feature: u64) { + // let aptos_framework = aptos_framework::aptos_governance::get_signer_testnet_only(root, @0x1); + // std::features::change_feature_flags_for_next_epoch(&aptos_framework, vector[feature], vector[]); + // aptos_framework::aptos_governance::reconfigure(&aptos_framework); + // std::features::on_new_epoch(&aptos_framework); + // } + // } + let mut root = self.root_account().await; + self.api_execute_script( + &mut root, + "a11ceb0b0700000a06010004030418051c1707336f08a2012006c201260000000100020301000101030502000100040602000101050602000102060c03010c0002060c05010303060c0a030a0301060c106170746f735f676f7665726e616e6365086665617475726573176765745f7369676e65725f746573746e65745f6f6e6c79236368616e67655f666561747572655f666c6167735f666f725f6e6578745f65706f63680b7265636f6e6669677572650c6f6e5f6e65775f65706f63680000000000000000000000000000000000000000000000000000000000000001052000000000000000000000000000000000000000000000000000000000000000010a0301000000010e0b00070011000c020e020b0140040100000000000000070111010e0211020e02110302", + json!([]), + json!([feature.to_string()]), + ).await; + self.wait_for_internal_indexer_caught_up().await; + } + + pub async fn disable_feature(&mut self, feature: u64) { + // This function executes the following script as the root account: + // script { + // fun main(root: &signer, feature: u64) { + // let aptos_framework = aptos_framework::aptos_governance::get_signer_testnet_only(root, @0x1); + // std::features::change_feature_flags_for_next_epoch(&aptos_framework, vector[], vector[feature]); + // aptos_framework::aptos_governance::reconfigure(&aptos_framework); + // std::features::on_new_epoch(&aptos_framework); + // } + // } + let mut root = self.root_account().await; + self.api_execute_script( + &mut root, + "a11ceb0b0700000a06010004030418051c1707336f08a2012006c201260000000100020301000101030502000100040602000101050602000102060c03010c0002060c05010303060c0a030a0301060c106170746f735f676f7665726e616e6365086665617475726573176765745f7369676e65725f746573746e65745f6f6e6c79236368616e67655f666561747572655f666c6167735f666f725f6e6578745f65706f63680b7265636f6e6669677572650c6f6e5f6e65775f65706f63680000000000000000000000000000000000000000000000000000000000000001052000000000000000000000000000000000000000000000000000000000000000010a0301000000010e0b00070011000c020e0207010b014004010000000000000011010e0211020e02110302", + json!([]), + json!([feature.to_string()]), + ).await; + self.wait_for_internal_indexer_caught_up().await; + } + + pub async fn is_feature_enabled(&self, feature: u64) -> bool { + let request = json!({ + "function":"0x1::features::is_enabled", + "arguments": vec![feature.to_string()], + "type_arguments": Vec::::new(), + }); + let resp = self.post("/view", request).await; + resp[0].as_bool().unwrap() + } + pub fn latest_state_view(&self) -> DbStateView { self.context .state_view_at_version(self.get_latest_ledger_info().version()) @@ -401,6 +451,46 @@ impl TestContext { account } + pub async fn api_create_account(&mut self) -> LocalAccount { + let root = &mut self.root_account().await; + let account = self.gen_account(); + self.api_execute_aptos_account_transfer(root, account.address(), TRANSFER_AMOUNT) + .await; + account + } + + pub async fn api_execute_aptos_account_transfer( + &mut self, + sender: &mut LocalAccount, + receiver: AccountAddress, + amount: u64, + ) { + self.api_execute_entry_function( + sender, + "0x1::aptos_account::transfer", + json!([]), + json!([receiver.to_hex_literal(), amount.to_string()]), + ) + .await; + self.wait_for_internal_indexer_caught_up().await; + } + + pub async fn wait_for_internal_indexer_caught_up(&self) { + let (internal_indexer_ledger_info_opt, storage_ledger_info) = self + .context + .get_latest_internal_and_storage_ledger_info::() + .expect("cannot get ledger info"); + if let Some(mut internal_indexer_ledger_info) = internal_indexer_ledger_info_opt { + while internal_indexer_ledger_info.version() < storage_ledger_info.version() { + tokio::time::sleep(Duration::from_millis(10)).await; + internal_indexer_ledger_info = self + .context + .get_latest_internal_indexer_ledger_info::() + .expect("cannot get internal indexer version"); + } + } + } + pub async fn create_user_account(&self, account: &LocalAccount) -> SignedTransaction { let mut tc = self.root_account().await; self.create_user_account_by(&mut tc, account) @@ -867,6 +957,27 @@ impl TestContext { .await; } + pub async fn api_execute_script( + &mut self, + account: &mut LocalAccount, + bytecode: &str, + type_args: serde_json::Value, + args: serde_json::Value, + ) { + self.api_execute_txn( + account, + json!({ + "type": "script_payload", + "code": { + "bytecode": bytecode, + }, + "type_arguments": type_args, + "arguments": args + }), + ) + .await; + } + pub async fn api_execute_txn(&mut self, account: &mut LocalAccount, payload: Value) { self.api_execute_txn_expecting(account, payload, 202).await; } diff --git a/config/src/config/internal_indexer_db_config.rs b/config/src/config/internal_indexer_db_config.rs index 323d02c090b45..d88d3a5dd2ed1 100644 --- a/config/src/config/internal_indexer_db_config.rs +++ b/config/src/config/internal_indexer_db_config.rs @@ -12,6 +12,8 @@ use serde::{Deserialize, Serialize}; pub struct InternalIndexerDBConfig { pub enable_transaction: bool, pub enable_event: bool, + pub enable_event_v2_translation: bool, + pub event_v2_translation_ignores_below_version: u64, pub enable_statekeys: bool, pub batch_size: usize, } @@ -20,12 +22,16 @@ impl InternalIndexerDBConfig { pub fn new( enable_transaction: bool, enable_event: bool, + enable_event_v2_translation: bool, + event_v2_translation_ignores_below_version: u64, enable_statekeys: bool, batch_size: usize, ) -> Self { Self { enable_transaction, enable_event, + enable_event_v2_translation, + event_v2_translation_ignores_below_version, enable_statekeys, batch_size, } @@ -39,6 +45,14 @@ impl InternalIndexerDBConfig { self.enable_event } + pub fn enable_event_v2_translation(&self) -> bool { + self.enable_event_v2_translation + } + + pub fn event_v2_translation_ignores_below_version(&self) -> u64 { + self.event_v2_translation_ignores_below_version + } + pub fn enable_statekeys(&self) -> bool { self.enable_statekeys } @@ -57,6 +71,8 @@ impl Default for InternalIndexerDBConfig { Self { enable_transaction: false, enable_event: false, + enable_event_v2_translation: false, + event_v2_translation_ignores_below_version: 0, enable_statekeys: false, batch_size: 10_000, } diff --git a/crates/aptos-rosetta/src/types/objects.rs b/crates/aptos-rosetta/src/types/objects.rs index e1764b6b3b309..2a4cdc575cb21 100644 --- a/crates/aptos-rosetta/src/types/objects.rs +++ b/crates/aptos-rosetta/src/types/objects.rs @@ -2175,8 +2175,8 @@ fn get_amount_from_event_v2( ) -> Vec { filter_v2_events(type_tag, events, |event| { if let Ok(event) = bcs::from_bytes::(event.event_data()) { - if event.account == account_address && &event.coin_type == coin_type { - Some(event.amount) + if event.account() == &account_address && event.coin_type() == coin_type { + Some(event.amount()) } else { None } diff --git a/ecosystem/indexer-grpc/indexer-grpc-table-info/src/internal_indexer_db_service.rs b/ecosystem/indexer-grpc/indexer-grpc-table-info/src/internal_indexer_db_service.rs index c795a724e9324..ec76faa6393ef 100644 --- a/ecosystem/indexer-grpc/indexer-grpc-table-info/src/internal_indexer_db_service.rs +++ b/ecosystem/indexer-grpc/indexer-grpc-table-info/src/internal_indexer_db_service.rs @@ -50,7 +50,9 @@ impl InternalIndexerDBService { open_internal_indexer_db(db_path_buf.as_path(), &rocksdb_config) .expect("Failed to open internal indexer db"), ); - let internal_indexer_db_config = InternalIndexerDBConfig::new(true, true, true, 10_000); + + let internal_indexer_db_config = + InternalIndexerDBConfig::new(true, true, true, 0, true, 10_000); Some(InternalIndexerDB::new(arc_db, internal_indexer_db_config)) } @@ -136,6 +138,29 @@ impl InternalIndexerDBService { } } + if node_config.indexer_db_config.enable_event_v2_translation() { + let event_v2_translation_start_version = self + .db_indexer + .indexer_db + .get_event_v2_translation_version()? + .map_or(0, |v| v + 1); + if node_config + .indexer_db_config + .event_v2_translation_ignores_below_version() + <= start_version + && start_version != event_v2_translation_start_version + { + panic!( + "Cannot start event v2 translation indexer because the progress doesn't match. \ + start_version: {}, event_v2_translation_start_version: {}", + start_version, event_v2_translation_start_version + ); + } + if !node_config.indexer_db_config.enable_event() { + panic!("Cannot start event v2 translation indexer because event indexer is not enabled."); + } + } + Ok(start_version) } diff --git a/storage/aptosdb/src/event_store/mod.rs b/storage/aptosdb/src/event_store/mod.rs index 1ff4d31c330d4..e909ab782a4f7 100644 --- a/storage/aptosdb/src/event_store/mod.rs +++ b/storage/aptosdb/src/event_store/mod.rs @@ -19,13 +19,14 @@ use aptos_crypto::{ }; use aptos_db_indexer_schemas::schema::{ event_by_key::EventByKeySchema, event_by_version::EventByVersionSchema, + translated_v1_event::TranslatedV1EventSchema, }; use aptos_schemadb::{iterator::SchemaIterator, schema::ValueCodec, ReadOptions, SchemaBatch, DB}; use aptos_storage_interface::{db_ensure as ensure, db_other_bail, AptosDbError, Result}; use aptos_types::{ account_address::AccountAddress, account_config::{new_block_event_key, NewBlockEvent}, - contract_event::ContractEvent, + contract_event::{ContractEvent, ContractEventV1}, event::EventKey, proof::position::Position, transaction::Version, diff --git a/storage/indexer/src/db_indexer.rs b/storage/indexer/src/db_indexer.rs index ac3d18709a068..a7b510f5daa3e 100644 --- a/storage/indexer/src/db_indexer.rs +++ b/storage/indexer/src/db_indexer.rs @@ -1,27 +1,33 @@ // Copyright (c) Aptos Foundation // SPDX-License-Identifier: Apache-2.0 -use crate::{metrics::TIMER, utils::PrefixedStateValueIterator}; +use crate::{ + event_v2_translator::EventV2TranslationEngine, metrics::TIMER, + utils::PrefixedStateValueIterator, +}; use aptos_config::config::internal_indexer_db_config::InternalIndexerDBConfig; use aptos_db_indexer_schemas::{ metadata::{MetadataKey, MetadataValue, StateSnapshotProgress}, schema::{ event_by_key::EventByKeySchema, event_by_version::EventByVersionSchema, + event_sequence_number::EventSequenceNumberSchema, indexer_metadata::InternalIndexerMetadataSchema, state_keys::StateKeysSchema, transaction_by_account::TransactionByAccountSchema, + translated_v1_event::TranslatedV1EventSchema, }, utils::{ error_if_too_many_requested, get_first_seq_num_and_limit, AccountTransactionVersionIter, MAX_REQUEST_LIMIT, }, }; +use aptos_logger::warn; use aptos_schemadb::{SchemaBatch, DB}; use aptos_storage_interface::{ db_ensure as ensure, db_other_bail as bail, AptosDbError, DbReader, Result, }; use aptos_types::{ account_address::AccountAddress, - contract_event::{ContractEvent, EventWithVersion}, + contract_event::{ContractEvent, ContractEventV1, ContractEventV2, EventWithVersion}, event::EventKey, indexer::indexer_db_reader::Order, state_store::{ @@ -33,6 +39,7 @@ use aptos_types::{ }; use std::{ cmp::min, + collections::HashSet, sync::{ mpsc::{self, Receiver, Sender}, Arc, @@ -69,7 +76,7 @@ impl DBCommitter { #[derive(Clone, Debug)] pub struct InternalIndexerDB { - db: Arc, + pub db: Arc, config: InternalIndexerDBConfig, } @@ -114,10 +121,18 @@ impl InternalIndexerDB { self.get_version(&MetadataKey::TransactionVersion) } + pub fn get_event_v2_translation_version(&self) -> Result> { + self.get_version(&MetadataKey::EventV2TranslationVersion) + } + pub fn event_enabled(&self) -> bool { self.config.enable_event } + pub fn event_v2_translation_enabled(&self) -> bool { + self.config.enable_event_v2_translation + } + pub fn transaction_enabled(&self) -> bool { self.config.enable_transaction } @@ -273,6 +288,16 @@ impl InternalIndexerDB { .get::(key)? .map(|v| v.expect_version())) } + + pub fn get_translated_v1_event_by_version_and_index( + &self, + version: Version, + index: u64, + ) -> Result { + self.db + .get::(&(version, index))? + .ok_or_else(|| AptosDbError::NotFound(format!("Event {} of Txn {}", index, version))) + } } pub struct DBIndexer { @@ -280,6 +305,7 @@ pub struct DBIndexer { pub main_db_reader: Arc, sender: Sender>, committer_handle: Option>, + pub event_v2_translation_engine: EventV2TranslationEngine, } impl Drop for DBIndexer { @@ -300,6 +326,7 @@ impl DBIndexer { let (sender, reciver) = mpsc::channel(); let db = indexer_db.get_inner_db_ref().to_owned(); + let internal_indexer_db = db.clone(); let committer_handle = thread::spawn(move || { let committer = DBCommitter::new(db, reciver); committer.run(); @@ -307,9 +334,13 @@ impl DBIndexer { Self { indexer_db, - main_db_reader: db_reader, + main_db_reader: db_reader.clone(), sender, committer_handle: Some(committer_handle), + event_v2_translation_engine: EventV2TranslationEngine::new( + db_reader, + internal_indexer_db, + ), } } @@ -367,6 +398,7 @@ impl DBIndexer { // This promises num_transactions should be readable from main db let mut db_iter = self.get_main_db_iter(version, num_transactions)?; let batch = SchemaBatch::new(); + let mut event_keys: HashSet = HashSet::new(); db_iter.try_for_each(|res| { let (txn, events, writeset) = res?; if let Some(txn) = txn.try_as_signed_user_txn() { @@ -379,7 +411,7 @@ impl DBIndexer { } if self.indexer_db.event_enabled() { - events.iter().enumerate().for_each(|(idx, event)| { + events.iter().enumerate().try_for_each(|(idx, event)| { if let ContractEvent::V1(v1) = event { batch .put::( @@ -394,7 +426,45 @@ impl DBIndexer { ) .expect("Failed to put events by version to a batch"); } - }); + if self.indexer_db.event_v2_translation_enabled() { + if let ContractEvent::V2(v2) = event { + if let Some(translated_v1_event) = + self.translate_event_v2_to_v1(v2).map_err(|e| { + anyhow::anyhow!( + "Failed to translate event: {:?}. Error: {}", + v2, + e + ) + })? + { + let key = *translated_v1_event.key(); + let sequence_number = translated_v1_event.sequence_number(); + self.event_v2_translation_engine + .cache_sequence_number(&key, sequence_number); + event_keys.insert(key); + batch + .put::( + &(key, sequence_number), + &(version, idx as u64), + ) + .expect("Failed to put events by key to a batch"); + batch + .put::( + &(key, version, sequence_number), + &(idx as u64), + ) + .expect("Failed to put events by version to a batch"); + batch + .put::( + &(version, idx as u64), + &translated_v1_event, + ) + .expect("Failed to put translated v1 events to a batch"); + } + } + } + Ok::<(), AptosDbError>(()) + })?; } if self.indexer_db.statekeys_enabled() { @@ -413,6 +483,25 @@ impl DBIndexer { assert_eq!(num_transactions, version - start_version); + if self.indexer_db.event_v2_translation_enabled() { + batch.put::( + &MetadataKey::EventV2TranslationVersion, + &MetadataValue::Version(version - 1), + )?; + + for event_key in event_keys { + batch + .put::( + &event_key, + &self + .event_v2_translation_engine + .get_cached_sequence_number(&event_key) + .unwrap_or(0), + ) + .expect("Failed to put events by key to a batch"); + } + } + if self.indexer_db.transaction_enabled() { batch.put::( &MetadataKey::TransactionVersion, @@ -441,6 +530,35 @@ impl DBIndexer { Ok(version) } + pub fn translate_event_v2_to_v1( + &self, + v2: &ContractEventV2, + ) -> Result> { + let _timer = TIMER + .with_label_values(&["translate_event_v2_to_v1"]) + .start_timer(); + if let Some(translator) = self + .event_v2_translation_engine + .translators + .get(v2.type_tag()) + { + let result = translator.translate_event_v2_to_v1(v2, &self.event_v2_translation_engine); + match result { + Ok(v1) => Ok(Some(v1)), + Err(e) => { + warn!( + "Failed to translate event: {:?}. Error: {}", + v2, + e.to_string() + ); + Ok(None) + }, + } + } else { + Ok(None) + } + } + pub fn get_account_transactions( &self, address: AccountAddress, @@ -550,9 +668,16 @@ impl DBIndexer { let mut events_with_version = event_indices .into_iter() .map(|(seq, ver, idx)| { - let event = self + let event = match self .main_db_reader - .get_event_by_version_and_index(ver, idx)?; + .get_event_by_version_and_index(ver, idx)? + { + event @ ContractEvent::V1(_) => event, + ContractEvent::V2(_) => ContractEvent::V1( + self.indexer_db + .get_translated_v1_event_by_version_and_index(ver, idx)?, + ), + }; let v0 = match &event { ContractEvent::V1(event) => event, ContractEvent::V2(_) => bail!("Unexpected module event"), @@ -563,6 +688,7 @@ impl DBIndexer { seq, v0.sequence_number() ); + Ok(EventWithVersion::new(ver, event)) }) .collect::>>()?; diff --git a/storage/indexer/src/event_v2_translator.rs b/storage/indexer/src/event_v2_translator.rs new file mode 100644 index 0000000000000..029183096ec94 --- /dev/null +++ b/storage/indexer/src/event_v2_translator.rs @@ -0,0 +1,1327 @@ +// Copyright (c) Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use aptos_db_indexer_schemas::schema::event_sequence_number::EventSequenceNumberSchema; +use aptos_schemadb::DB; +use aptos_storage_interface::{ + state_store::state_view::db_state_view::LatestDbStateCheckpointView, AptosDbError, DbReader, + Result, +}; +use aptos_types::{ + account_config::{ + AccountResource, Burn, BurnEvent, BurnToken, BurnTokenEvent, CancelOffer, Claim, + CoinDeposit, CoinRegister, CoinRegisterEvent, CoinStoreResource, CoinWithdraw, + CollectionDescriptionMutate, CollectionDescriptionMutateEvent, CollectionMaximumMutate, + CollectionMaximumMutateEvent, CollectionMutation, CollectionMutationEvent, + CollectionResource, CollectionUriMutate, CollectionUriMutateEvent, CollectionsResource, + CreateCollection, CreateCollectionEvent, CreateTokenDataEvent, DefaultPropertyMutate, + DefaultPropertyMutateEvent, DepositEvent, DescriptionMutate, DescriptionMutateEvent, + FixedSupplyResource, KeyRotation, KeyRotationEvent, MaximumMutate, MaximumMutateEvent, + Mint, MintEvent, MintToken, MintTokenEvent, MutatePropertyMap, MutateTokenPropertyMapEvent, + ObjectCoreResource, ObjectGroupResource, Offer, OptInTransfer, OptInTransferEvent, + PendingClaimsResource, RoyaltyMutate, RoyaltyMutateEvent, TokenCancelOfferEvent, + TokenClaimEvent, TokenDataCreation, TokenDeposit, TokenDepositEvent, + TokenEventStoreV1Resource, TokenMutation, TokenMutationEvent, TokenOfferEvent, + TokenResource, TokenStoreResource, TokenWithdraw, TokenWithdrawEvent, Transfer, + TransferEvent, UnlimitedSupplyResource, UriMutation, UriMutationEvent, WithdrawEvent, + BURN_EVENT_TYPE, BURN_TOKEN_EVENT_TYPE, BURN_TOKEN_TYPE, BURN_TYPE, CANCEL_OFFER_TYPE, + CLAIM_TYPE, COIN_DEPOSIT_TYPE, COIN_REGISTER_EVENT_TYPE, COIN_REGISTER_TYPE, + COIN_WITHDRAW_TYPE, COLLECTION_DESCRIPTION_MUTATE_EVENT_TYPE, + COLLECTION_DESCRIPTION_MUTATE_TYPE, COLLECTION_MAXIMUM_MUTATE_EVENT_TYPE, + COLLECTION_MAXIMUM_MUTATE_TYPE, COLLECTION_MUTATION_EVENT_TYPE, COLLECTION_MUTATION_TYPE, + COLLECTION_URI_MUTATE_EVENT_TYPE, COLLECTION_URI_MUTATE_TYPE, CREATE_COLLECTION_EVENT_TYPE, + CREATE_COLLECTION_TYPE, CREATE_TOKEN_DATA_EVENT_TYPE, DEFAULT_PROPERTY_MUTATE_EVENT_TYPE, + DEFAULT_PROPERTY_MUTATE_TYPE, DEPOSIT_EVENT_TYPE, DESCRIPTION_MUTATE_EVENT_TYPE, + DESCRIPTION_MUTATE_TYPE, KEY_ROTATION_EVENT_TYPE, KEY_ROTATION_TYPE, + MAXIMUM_MUTATE_EVENT_TYPE, MAXIMUM_MUTATE_TYPE, MINT_EVENT_TYPE, MINT_TOKEN_EVENT_TYPE, + MINT_TOKEN_TYPE, MINT_TYPE, MUTATE_PROPERTY_MAP_TYPE, MUTATE_TOKEN_PROPERTY_MAP_EVENT_TYPE, + OFFER_TYPE, OPT_IN_TRANSFER_EVENT_TYPE, OPT_IN_TRANSFER_TYPE, ROYALTY_MUTATE_EVENT_TYPE, + ROYALTY_MUTATE_TYPE, TOKEN_CANCEL_OFFER_EVENT_TYPE, TOKEN_CLAIM_EVENT_TYPE, + TOKEN_DATA_CREATION_TYPE, TOKEN_DEPOSIT_EVENT_TYPE, TOKEN_DEPOSIT_TYPE, + TOKEN_MUTATION_EVENT_TYPE, TOKEN_MUTATION_TYPE, TOKEN_OFFER_EVENT_TYPE, + TOKEN_WITHDRAW_EVENT_TYPE, TOKEN_WITHDRAW_TYPE, TRANSFER_EVENT_TYPE, TRANSFER_TYPE, + URI_MUTATION_EVENT_TYPE, URI_MUTATION_TYPE, WITHDRAW_EVENT_TYPE, + }, + contract_event::{ContractEventV1, ContractEventV2}, + event::EventKey, + state_store::{state_key::StateKey, TStateView}, + DummyCoinType, +}; +use bytes::Bytes; +use dashmap::DashMap; +use move_core_types::{ + account_address::AccountAddress, + language_storage::{StructTag, TypeTag}, +}; +use std::{collections::HashMap, str::FromStr, sync::Arc}; + +pub trait EventV2Translator: Send + Sync { + fn translate_event_v2_to_v1( + &self, + v2: &ContractEventV2, + engine: &EventV2TranslationEngine, + ) -> Result; +} + +pub struct EventV2TranslationEngine { + pub main_db_reader: Arc, + pub internal_indexer_db: Arc, + // Map from event type to translator + pub translators: HashMap>, + event_sequence_number_cache: DashMap, +} + +impl EventV2TranslationEngine { + pub fn new(main_db_reader: Arc, internal_indexer_db: Arc) -> Self { + let mut translators: HashMap> = + HashMap::new(); + translators.insert(COIN_DEPOSIT_TYPE.clone(), Box::new(CoinDepositTranslator)); + translators.insert(COIN_WITHDRAW_TYPE.clone(), Box::new(CoinWithdrawTranslator)); + translators.insert(COIN_REGISTER_TYPE.clone(), Box::new(CoinRegisterTranslator)); + translators.insert(KEY_ROTATION_TYPE.clone(), Box::new(KeyRotationTranslator)); + translators.insert(TRANSFER_TYPE.clone(), Box::new(TransferTranslator)); + translators.insert( + TOKEN_MUTATION_TYPE.clone(), + Box::new(TokenMutationTranslator), + ); + translators.insert( + COLLECTION_MUTATION_TYPE.clone(), + Box::new(CollectionMutationTranslator), + ); + translators.insert(MINT_TYPE.clone(), Box::new(MintTranslator)); + translators.insert(BURN_TYPE.clone(), Box::new(BurnTranslator)); + translators.insert(TOKEN_DEPOSIT_TYPE.clone(), Box::new(TokenDepositTranslator)); + translators.insert( + TOKEN_WITHDRAW_TYPE.clone(), + Box::new(TokenWithdrawTranslator), + ); + translators.insert(BURN_TOKEN_TYPE.clone(), Box::new(BurnTokenTranslator)); + translators.insert( + MUTATE_PROPERTY_MAP_TYPE.clone(), + Box::new(MutatePropertyMapTranslator), + ); + translators.insert(MINT_TOKEN_TYPE.clone(), Box::new(MintTokenTranslator)); + translators.insert( + CREATE_COLLECTION_TYPE.clone(), + Box::new(CreateCollectionTranslator), + ); + translators.insert( + TOKEN_DATA_CREATION_TYPE.clone(), + Box::new(TokenDataCreationTranslator), + ); + translators.insert(OFFER_TYPE.clone(), Box::new(OfferTranslator)); + translators.insert(CANCEL_OFFER_TYPE.clone(), Box::new(CancelOfferTranslator)); + translators.insert(CLAIM_TYPE.clone(), Box::new(ClaimTranslator)); + translators.insert( + COLLECTION_DESCRIPTION_MUTATE_TYPE.clone(), + Box::new(CollectionDescriptionMutateTranslator), + ); + translators.insert( + COLLECTION_URI_MUTATE_TYPE.clone(), + Box::new(CollectionUriMutateTranslator), + ); + translators.insert( + COLLECTION_MAXIMUM_MUTATE_TYPE.clone(), + Box::new(CollectionMaximumMutateTranslator), + ); + translators.insert(URI_MUTATION_TYPE.clone(), Box::new(UriMutationTranslator)); + translators.insert( + DEFAULT_PROPERTY_MUTATE_TYPE.clone(), + Box::new(DefaultPropertyMutateTranslator), + ); + translators.insert( + DESCRIPTION_MUTATE_TYPE.clone(), + Box::new(DescriptionMutateTranslator), + ); + translators.insert( + ROYALTY_MUTATE_TYPE.clone(), + Box::new(RoyaltyMutateTranslator), + ); + translators.insert( + MAXIMUM_MUTATE_TYPE.clone(), + Box::new(MaximumMutateTranslator), + ); + translators.insert( + OPT_IN_TRANSFER_TYPE.clone(), + Box::new(OptInTransferTranslator), + ); + Self { + main_db_reader, + internal_indexer_db, + translators, + event_sequence_number_cache: DashMap::new(), + } + } + + // When the node starts with a non-empty EventSequenceNumberSchema table, the in-memory cache + // `event_sequence_number_cache` is empty. In the future, we decide to backup and restore the + // event sequence number data to support fast sync, we may need to load the cache from the DB + // when the node starts using this function `load_cache_from_db`. + pub fn load_cache_from_db(&self) -> Result<()> { + let mut iter = self + .internal_indexer_db + .iter::()?; + iter.seek_to_first(); + while let Some((event_key, sequence_number)) = iter.next().transpose()? { + self.event_sequence_number_cache + .insert(event_key, sequence_number); + } + Ok(()) + } + + pub fn cache_sequence_number(&self, event_key: &EventKey, sequence_number: u64) { + self.event_sequence_number_cache + .insert(*event_key, sequence_number); + } + + pub fn get_cached_sequence_number(&self, event_key: &EventKey) -> Option { + self.event_sequence_number_cache + .get(event_key) + .map(|seq| *seq) + } + + pub fn get_next_sequence_number(&self, event_key: &EventKey, default: u64) -> Result { + if let Some(seq) = self.get_cached_sequence_number(event_key) { + Ok(seq + 1) + } else { + let seq = self + .internal_indexer_db + .get::(event_key)? + .map_or(default, |seq| seq + 1); + Ok(seq) + } + } + + pub fn get_state_value_bytes_for_resource( + &self, + address: &AccountAddress, + struct_tag: &StructTag, + ) -> Result> { + let state_view = self + .main_db_reader + .latest_state_checkpoint_view() + .expect("Failed to get state view"); + let state_key = StateKey::resource(address, struct_tag)?; + let maybe_state_value = state_view.get_state_value(&state_key)?; + Ok(maybe_state_value.map(|state_value| state_value.bytes().clone())) + } + + pub fn get_state_value_bytes_for_object_group_resource( + &self, + address: &AccountAddress, + struct_tag: &StructTag, + ) -> Result> { + let state_view = self + .main_db_reader + .latest_state_checkpoint_view() + .expect("Failed to get state view"); + let group_tag_str = "0x1::object::ObjectGroup".to_string(); + let group_tag = StructTag::from_str(&group_tag_str)?; + let state_key = StateKey::resource_group(address, &group_tag); + let maybe_state_value = state_view.get_state_value(&state_key)?; + let state_value = maybe_state_value + .ok_or_else(|| anyhow::format_err!("ObjectGroup resource not found"))?; + let object_group_resource: ObjectGroupResource = bcs::from_bytes(state_value.bytes())?; + Ok(object_group_resource + .group + .get(struct_tag) + .map(|bytes| Bytes::copy_from_slice(bytes))) + } +} + +struct CoinDepositTranslator; +impl EventV2Translator for CoinDepositTranslator { + fn translate_event_v2_to_v1( + &self, + v2: &ContractEventV2, + engine: &EventV2TranslationEngine, + ) -> Result { + let coin_deposit = CoinDeposit::try_from_bytes(v2.event_data())?; + let struct_tag_str = format!("0x1::coin::CoinStore<{}>", coin_deposit.coin_type()); + let struct_tag = StructTag::from_str(&struct_tag_str)?; + let (key, sequence_number) = if let Some(state_value_bytes) = + engine.get_state_value_bytes_for_resource(coin_deposit.account(), &struct_tag)? + { + // We can use `DummyCoinType` as it does not affect the correctness of deserialization. + let coin_store_resource: CoinStoreResource = + bcs::from_bytes(&state_value_bytes)?; + let key = *coin_store_resource.deposit_events().key(); + let sequence_number = engine + .get_next_sequence_number(&key, coin_store_resource.deposit_events().count())?; + (key, sequence_number) + } else { + (EventKey::new(2, *coin_deposit.account()), 0) + }; + let deposit_event = DepositEvent::new(coin_deposit.amount()); + Ok(ContractEventV1::new( + key, + sequence_number, + DEPOSIT_EVENT_TYPE.clone(), + bcs::to_bytes(&deposit_event)?, + )) + } +} + +struct CoinWithdrawTranslator; +impl EventV2Translator for CoinWithdrawTranslator { + fn translate_event_v2_to_v1( + &self, + v2: &ContractEventV2, + engine: &EventV2TranslationEngine, + ) -> Result { + let coin_withdraw = CoinWithdraw::try_from_bytes(v2.event_data())?; + let struct_tag_str = format!("0x1::coin::CoinStore<{}>", coin_withdraw.coin_type()); + let struct_tag = StructTag::from_str(&struct_tag_str)?; + let (key, sequence_number) = if let Some(state_value_bytes) = + engine.get_state_value_bytes_for_resource(coin_withdraw.account(), &struct_tag)? + { + // We can use `DummyCoinType` as it does not affect the correctness of deserialization. + let coin_store_resource: CoinStoreResource = + bcs::from_bytes(&state_value_bytes)?; + let key = *coin_store_resource.withdraw_events().key(); + let sequence_number = engine + .get_next_sequence_number(&key, coin_store_resource.withdraw_events().count())?; + (key, sequence_number) + } else { + (EventKey::new(3, *coin_withdraw.account()), 0) + }; + let withdraw_event = WithdrawEvent::new(coin_withdraw.amount()); + Ok(ContractEventV1::new( + key, + sequence_number, + WITHDRAW_EVENT_TYPE.clone(), + bcs::to_bytes(&withdraw_event)?, + )) + } +} + +struct CoinRegisterTranslator; +impl EventV2Translator for CoinRegisterTranslator { + fn translate_event_v2_to_v1( + &self, + v2: &ContractEventV2, + engine: &EventV2TranslationEngine, + ) -> Result { + let coin_register = CoinRegister::try_from_bytes(v2.event_data())?; + let struct_tag_str = "0x1::account::Account".to_string(); + let struct_tag = StructTag::from_str(&struct_tag_str)?; + let (key, sequence_number) = if let Some(state_value_bytes) = + engine.get_state_value_bytes_for_resource(coin_register.account(), &struct_tag)? + { + let account_resource: AccountResource = bcs::from_bytes(&state_value_bytes)?; + let key = *account_resource.coin_register_events().key(); + let sequence_number = engine + .get_next_sequence_number(&key, account_resource.coin_register_events().count())?; + (key, sequence_number) + } else { + (EventKey::new(0, *coin_register.account()), 0) + }; + let coin_register_event = CoinRegisterEvent::new(coin_register.type_info().clone()); + Ok(ContractEventV1::new( + key, + sequence_number, + COIN_REGISTER_EVENT_TYPE.clone(), + bcs::to_bytes(&coin_register_event)?, + )) + } +} + +struct KeyRotationTranslator; +impl EventV2Translator for KeyRotationTranslator { + fn translate_event_v2_to_v1( + &self, + v2: &ContractEventV2, + engine: &EventV2TranslationEngine, + ) -> Result { + let key_rotation = KeyRotation::try_from_bytes(v2.event_data())?; + let struct_tag_str = "0x1::account::Account".to_string(); + let struct_tag = StructTag::from_str(&struct_tag_str)?; + let (key, sequence_number) = if let Some(state_value_bytes) = + engine.get_state_value_bytes_for_resource(key_rotation.account(), &struct_tag)? + { + let account_resource: AccountResource = bcs::from_bytes(&state_value_bytes)?; + let key = *account_resource.key_rotation_events().key(); + let sequence_number = engine + .get_next_sequence_number(&key, account_resource.key_rotation_events().count())?; + (key, sequence_number) + } else { + (EventKey::new(1, *key_rotation.account()), 0) + }; + let key_rotation_event = KeyRotationEvent::new( + key_rotation.old_authentication_key().clone(), + key_rotation.new_authentication_key().clone(), + ); + Ok(ContractEventV1::new( + key, + sequence_number, + KEY_ROTATION_EVENT_TYPE.clone(), + bcs::to_bytes(&key_rotation_event)?, + )) + } +} + +struct TransferTranslator; +impl EventV2Translator for TransferTranslator { + fn translate_event_v2_to_v1( + &self, + v2: &ContractEventV2, + engine: &EventV2TranslationEngine, + ) -> Result { + let transfer = Transfer::try_from_bytes(v2.event_data())?; + let struct_tag_str = "0x1::object::ObjectCore".to_string(); + let struct_tag = StructTag::from_str(&struct_tag_str)?; + let (key, sequence_number) = if let Some(state_value_bytes) = engine + .get_state_value_bytes_for_object_group_resource(transfer.object(), &struct_tag)? + { + let object_core_resource: ObjectCoreResource = bcs::from_bytes(&state_value_bytes)?; + let key = *object_core_resource.transfer_events().key(); + let sequence_number = engine + .get_next_sequence_number(&key, object_core_resource.transfer_events().count())?; + (key, sequence_number) + } else { + // The INIT_GUID_CREATION_NUM is 0x4000000000000. + (EventKey::new(0x4000000000000, *transfer.object()), 0) + }; + let transfer_event = + TransferEvent::new(*transfer.object(), *transfer.from(), *transfer.to()); + Ok(ContractEventV1::new( + key, + sequence_number, + TRANSFER_EVENT_TYPE.clone(), + bcs::to_bytes(&transfer_event)?, + )) + } +} + +struct TokenMutationTranslator; +impl EventV2Translator for TokenMutationTranslator { + fn translate_event_v2_to_v1( + &self, + v2: &ContractEventV2, + engine: &EventV2TranslationEngine, + ) -> Result { + let token_mutation = TokenMutation::try_from_bytes(v2.event_data())?; + let struct_tag_str = "0x4::token::Token".to_string(); + let struct_tag = StructTag::from_str(&struct_tag_str)?; + let (key, sequence_number) = if let Some(state_value_bytes) = engine + .get_state_value_bytes_for_object_group_resource( + token_mutation.token_address(), + &struct_tag, + )? { + let token_resource: TokenResource = bcs::from_bytes(&state_value_bytes)?; + let key = *token_resource.mutation_events().key(); + let sequence_number = + engine.get_next_sequence_number(&key, token_resource.mutation_events().count())?; + (key, sequence_number) + } else { + // If the token resource is not found, we skip the event translation to avoid panic + // because the creation number cannot be decided. The token may have been burned. + return Err(AptosDbError::from(anyhow::format_err!( + "Token resource not found" + ))); + }; + let token_mutation_event = TokenMutationEvent::new( + token_mutation.mutated_field_name().clone(), + token_mutation.old_value().clone(), + token_mutation.new_value().clone(), + ); + Ok(ContractEventV1::new( + key, + sequence_number, + TOKEN_MUTATION_EVENT_TYPE.clone(), + bcs::to_bytes(&token_mutation_event)?, + )) + } +} + +struct CollectionMutationTranslator; +impl EventV2Translator for CollectionMutationTranslator { + fn translate_event_v2_to_v1( + &self, + v2: &ContractEventV2, + engine: &EventV2TranslationEngine, + ) -> Result { + let collection_mutation = CollectionMutation::try_from_bytes(v2.event_data())?; + let struct_tag_str = "0x4::collection::Collection".to_string(); + let struct_tag = StructTag::from_str(&struct_tag_str)?; + let (key, sequence_number) = if let Some(state_value_bytes) = engine + .get_state_value_bytes_for_object_group_resource( + collection_mutation.collection().inner(), + &struct_tag, + )? { + let collection_resource: CollectionResource = bcs::from_bytes(&state_value_bytes)?; + let key = *collection_resource.mutation_events().key(); + let sequence_number = engine + .get_next_sequence_number(&key, collection_resource.mutation_events().count())?; + (key, sequence_number) + } else { + // If the token resource is not found, we skip the event translation to avoid panic + // because the creation number cannot be decided. + return Err(AptosDbError::from(anyhow::format_err!( + "Collection resource not found" + ))); + }; + let collection_mutation_event = + CollectionMutationEvent::new(collection_mutation.mutated_field_name().clone()); + Ok(ContractEventV1::new( + key, + sequence_number, + COLLECTION_MUTATION_EVENT_TYPE.clone(), + bcs::to_bytes(&collection_mutation_event)?, + )) + } +} + +struct MintTranslator; +impl EventV2Translator for MintTranslator { + fn translate_event_v2_to_v1( + &self, + v2: &ContractEventV2, + engine: &EventV2TranslationEngine, + ) -> Result { + let mint = Mint::try_from_bytes(v2.event_data())?; + let fixed_supply_struct_tag = StructTag::from_str("0x4::collection::FixedSupply")?; + let unlimited_supply_struct_tag = StructTag::from_str("0x4::collection::UnlimitedSupply")?; + let (key, sequence_number) = if let Some(state_value_bytes) = engine + .get_state_value_bytes_for_object_group_resource( + mint.collection(), + &fixed_supply_struct_tag, + )? { + let fixed_supply_resource: FixedSupplyResource = bcs::from_bytes(&state_value_bytes)?; + let key = *fixed_supply_resource.mint_events().key(); + let sequence_number = engine + .get_next_sequence_number(&key, fixed_supply_resource.mint_events().count())?; + (key, sequence_number) + } else if let Some(state_value_bytes) = engine + .get_state_value_bytes_for_object_group_resource( + mint.collection(), + &unlimited_supply_struct_tag, + )? + { + let unlimited_supply_resource: UnlimitedSupplyResource = + bcs::from_bytes(&state_value_bytes)?; + let key = *unlimited_supply_resource.mint_events().key(); + let sequence_number = engine + .get_next_sequence_number(&key, unlimited_supply_resource.mint_events().count())?; + (key, sequence_number) + } else { + // If the collection resource is not found, we skip the event translation to avoid panic + // because the creation number cannot be decided. The collection may have ConcurrentSupply. + return Err(AptosDbError::from(anyhow::format_err!( + "FixedSupply or UnlimitedSupply resource not found" + ))); + }; + let mint_event = MintEvent::new(mint.index().value, *mint.token()); + Ok(ContractEventV1::new( + key, + sequence_number, + MINT_EVENT_TYPE.clone(), + bcs::to_bytes(&mint_event)?, + )) + } +} + +struct BurnTranslator; +impl EventV2Translator for BurnTranslator { + fn translate_event_v2_to_v1( + &self, + v2: &ContractEventV2, + engine: &EventV2TranslationEngine, + ) -> Result { + let burn = Burn::try_from_bytes(v2.event_data())?; + let fixed_supply_struct_tag = StructTag::from_str("0x4::collection::FixedSupply")?; + let unlimited_supply_struct_tag = StructTag::from_str("0x4::collection::UnlimitedSupply")?; + let (key, sequence_number) = if let Some(state_value_bytes) = engine + .get_state_value_bytes_for_object_group_resource( + burn.collection(), + &fixed_supply_struct_tag, + )? { + let fixed_supply_resource: FixedSupplyResource = bcs::from_bytes(&state_value_bytes)?; + let key = *fixed_supply_resource.burn_events().key(); + let sequence_number = engine + .get_next_sequence_number(&key, fixed_supply_resource.burn_events().count())?; + (key, sequence_number) + } else if let Some(state_value_bytes) = engine + .get_state_value_bytes_for_object_group_resource( + burn.collection(), + &unlimited_supply_struct_tag, + )? + { + let unlimited_supply_resource: UnlimitedSupplyResource = + bcs::from_bytes(&state_value_bytes)?; + let key = *unlimited_supply_resource.burn_events().key(); + let sequence_number = engine + .get_next_sequence_number(&key, unlimited_supply_resource.burn_events().count())?; + (key, sequence_number) + } else { + // If the collection resource is not found, we skip the event translation to avoid panic + // because the creation number cannot be decided. The collection may have ConcurrentSupply. + return Err(AptosDbError::from(anyhow::format_err!( + "FixedSupply or UnlimitedSupply resource not found" + ))); + }; + let burn_event = BurnEvent::new(*burn.index(), *burn.token()); + Ok(ContractEventV1::new( + key, + sequence_number, + BURN_EVENT_TYPE.clone(), + bcs::to_bytes(&burn_event)?, + )) + } +} + +struct TokenDepositTranslator; +impl EventV2Translator for TokenDepositTranslator { + fn translate_event_v2_to_v1( + &self, + v2: &ContractEventV2, + engine: &EventV2TranslationEngine, + ) -> Result { + let deposit = TokenDeposit::try_from_bytes(v2.event_data())?; + let struct_tag = StructTag::from_str("0x3::token::TokenStore")?; + let (key, sequence_number) = if let Some(state_value_bytes) = + engine.get_state_value_bytes_for_resource(deposit.account(), &struct_tag)? + { + let token_store_resource: TokenStoreResource = bcs::from_bytes(&state_value_bytes)?; + let key = *token_store_resource.deposit_events().key(); + let sequence_number = engine + .get_next_sequence_number(&key, token_store_resource.deposit_events().count())?; + (key, sequence_number) + } else { + // If the token store resource is not found, we skip the event translation to avoid panic + // because the creation number cannot be decided. + return Err(AptosDbError::from(anyhow::format_err!( + "Token store resource not found" + ))); + }; + let deposit_event = TokenDepositEvent::new(deposit.id().clone(), deposit.amount()); + Ok(ContractEventV1::new( + key, + sequence_number, + TOKEN_DEPOSIT_EVENT_TYPE.clone(), + bcs::to_bytes(&deposit_event)?, + )) + } +} + +struct TokenWithdrawTranslator; +impl EventV2Translator for TokenWithdrawTranslator { + fn translate_event_v2_to_v1( + &self, + v2: &ContractEventV2, + engine: &EventV2TranslationEngine, + ) -> Result { + let withdraw = TokenWithdraw::try_from_bytes(v2.event_data())?; + let struct_tag = StructTag::from_str("0x3::token::TokenStore")?; + let (key, sequence_number) = if let Some(state_value_bytes) = + engine.get_state_value_bytes_for_resource(withdraw.account(), &struct_tag)? + { + let token_store_resource: TokenStoreResource = bcs::from_bytes(&state_value_bytes)?; + let key = *token_store_resource.withdraw_events().key(); + let sequence_number = engine + .get_next_sequence_number(&key, token_store_resource.withdraw_events().count())?; + (key, sequence_number) + } else { + // If the token store resource is not found, we skip the event translation to avoid panic + // because the creation number cannot be decided. + return Err(AptosDbError::from(anyhow::format_err!( + "Token store resource not found" + ))); + }; + let withdraw_event = TokenWithdrawEvent::new(withdraw.id().clone(), withdraw.amount()); + Ok(ContractEventV1::new( + key, + sequence_number, + TOKEN_WITHDRAW_EVENT_TYPE.clone(), + bcs::to_bytes(&withdraw_event)?, + )) + } +} + +struct BurnTokenTranslator; +impl EventV2Translator for BurnTokenTranslator { + fn translate_event_v2_to_v1( + &self, + v2: &ContractEventV2, + engine: &EventV2TranslationEngine, + ) -> Result { + let burn = BurnToken::try_from_bytes(v2.event_data())?; + let struct_tag = StructTag::from_str("0x3::token::TokenStore")?; + let (key, sequence_number) = if let Some(state_value_bytes) = + engine.get_state_value_bytes_for_resource(burn.account(), &struct_tag)? + { + let token_store_resource: TokenStoreResource = bcs::from_bytes(&state_value_bytes)?; + let key = *token_store_resource.burn_events().key(); + let sequence_number = engine + .get_next_sequence_number(&key, token_store_resource.burn_events().count())?; + (key, sequence_number) + } else { + // If the token store resource is not found, we skip the event translation to avoid panic + // because the creation number cannot be decided. + return Err(AptosDbError::from(anyhow::format_err!( + "Token store resource not found" + ))); + }; + let burn_event = BurnTokenEvent::new(burn.id().clone(), burn.amount()); + Ok(ContractEventV1::new( + key, + sequence_number, + BURN_TOKEN_EVENT_TYPE.clone(), + bcs::to_bytes(&burn_event)?, + )) + } +} + +struct MutatePropertyMapTranslator; +impl EventV2Translator for MutatePropertyMapTranslator { + fn translate_event_v2_to_v1( + &self, + v2: &ContractEventV2, + engine: &EventV2TranslationEngine, + ) -> Result { + let mutate = MutatePropertyMap::try_from_bytes(v2.event_data())?; + let struct_tag = StructTag::from_str("0x3::token::TokenStore")?; + let (key, sequence_number) = if let Some(state_value_bytes) = + engine.get_state_value_bytes_for_resource(mutate.account(), &struct_tag)? + { + let token_store_resource: TokenStoreResource = bcs::from_bytes(&state_value_bytes)?; + let key = *token_store_resource.mutate_token_property_events().key(); + let sequence_number = engine.get_next_sequence_number( + &key, + token_store_resource.mutate_token_property_events().count(), + )?; + (key, sequence_number) + } else { + // If the token store resource is not found, we skip the event translation to avoid panic + // because the creation number cannot be decided. + return Err(AptosDbError::from(anyhow::format_err!( + "Token store resource not found" + ))); + }; + let mutate_event = MutateTokenPropertyMapEvent::new( + mutate.old_id().clone(), + mutate.new_id().clone(), + mutate.keys().clone(), + mutate.values().clone(), + mutate.types().clone(), + ); + + Ok(ContractEventV1::new( + key, + sequence_number, + MUTATE_TOKEN_PROPERTY_MAP_EVENT_TYPE.clone(), + bcs::to_bytes(&mutate_event)?, + )) + } +} + +struct MintTokenTranslator; +impl EventV2Translator for MintTokenTranslator { + fn translate_event_v2_to_v1( + &self, + v2: &ContractEventV2, + engine: &EventV2TranslationEngine, + ) -> Result { + let mint = MintToken::try_from_bytes(v2.event_data())?; + let struct_tag = StructTag::from_str("0x3::token::Collections")?; + let (key, sequence_number) = if let Some(state_value_bytes) = + engine.get_state_value_bytes_for_resource(mint.creator(), &struct_tag)? + { + let token_store_resource: CollectionsResource = bcs::from_bytes(&state_value_bytes)?; + let key = *token_store_resource.mint_token_events().key(); + let sequence_number = engine + .get_next_sequence_number(&key, token_store_resource.mint_token_events().count())?; + (key, sequence_number) + } else { + // If the collections store resource is not found, we skip the event translation to + // avoid panic because the creation number cannot be decided. + return Err(AptosDbError::from(anyhow::format_err!( + "Collections resource not found" + ))); + }; + let mint_event = MintTokenEvent::new(mint.id().clone(), mint.amount()); + + Ok(ContractEventV1::new( + key, + sequence_number, + MINT_TOKEN_EVENT_TYPE.clone(), + bcs::to_bytes(&mint_event)?, + )) + } +} + +struct CreateCollectionTranslator; +impl EventV2Translator for CreateCollectionTranslator { + fn translate_event_v2_to_v1( + &self, + v2: &ContractEventV2, + engine: &EventV2TranslationEngine, + ) -> Result { + let create = CreateCollection::try_from_bytes(v2.event_data())?; + let struct_tag = StructTag::from_str("0x3::token::Collections")?; + let (key, sequence_number) = if let Some(state_value_bytes) = + engine.get_state_value_bytes_for_resource(create.creator(), &struct_tag)? + { + let collections_resource: CollectionsResource = bcs::from_bytes(&state_value_bytes)?; + let key = *collections_resource.create_collection_events().key(); + let sequence_number = engine.get_next_sequence_number( + &key, + collections_resource.create_collection_events().count(), + )?; + (key, sequence_number) + } else { + // If the collections resource is not found, we skip the event translation to + // avoid panic because the creation number cannot be decided. + return Err(AptosDbError::from(anyhow::format_err!( + "Collections resource not found" + ))); + }; + let create_event = CreateCollectionEvent::new( + *create.creator(), + create.collection_name().clone(), + create.uri().clone(), + create.description().clone(), + create.maximum(), + ); + Ok(ContractEventV1::new( + key, + sequence_number, + CREATE_COLLECTION_EVENT_TYPE.clone(), + bcs::to_bytes(&create_event)?, + )) + } +} + +struct TokenDataCreationTranslator; +impl EventV2Translator for TokenDataCreationTranslator { + fn translate_event_v2_to_v1( + &self, + v2: &ContractEventV2, + engine: &EventV2TranslationEngine, + ) -> Result { + let create = TokenDataCreation::try_from_bytes(v2.event_data())?; + let struct_tag = StructTag::from_str("0x3::token::Collections")?; + let (key, sequence_number) = if let Some(state_value_bytes) = + engine.get_state_value_bytes_for_resource(create.creator(), &struct_tag)? + { + let collections_resource: CollectionsResource = bcs::from_bytes(&state_value_bytes)?; + let key = *collections_resource.create_token_data_events().key(); + let sequence_number = engine.get_next_sequence_number( + &key, + collections_resource.create_token_data_events().count(), + )?; + (key, sequence_number) + } else { + // If the collections resource is not found, we skip the event translation to + // avoid panic because the creation number cannot be decided. + return Err(AptosDbError::from(anyhow::format_err!( + "Collections resource not found" + ))); + }; + let create_event = CreateTokenDataEvent::new( + create.id().clone(), + create.description().clone(), + create.maximum(), + create.uri().clone(), + *create.royalty_payee_address(), + create.royalty_points_denominator(), + create.royalty_points_numerator(), + create.name().clone(), + create.mutability_config().clone(), + create.property_keys().clone(), + create.property_values().clone(), + create.property_types().clone(), + ); + Ok(ContractEventV1::new( + key, + sequence_number, + CREATE_TOKEN_DATA_EVENT_TYPE.clone(), + bcs::to_bytes(&create_event)?, + )) + } +} + +struct OfferTranslator; +impl EventV2Translator for OfferTranslator { + fn translate_event_v2_to_v1( + &self, + v2: &ContractEventV2, + engine: &EventV2TranslationEngine, + ) -> Result { + let offer = Offer::try_from_bytes(v2.event_data())?; + let struct_tag = StructTag::from_str("0x3::token_transfers::PendingClaims")?; + let (key, sequence_number) = if let Some(state_value_bytes) = + engine.get_state_value_bytes_for_resource(offer.account(), &struct_tag)? + { + let object_resource: PendingClaimsResource = bcs::from_bytes(&state_value_bytes)?; + let key = *object_resource.offer_events().key(); + let sequence_number = + engine.get_next_sequence_number(&key, object_resource.offer_events().count())?; + (key, sequence_number) + } else { + // If the PendingClaims resource is not found, we skip the event translation to + // avoid panic because the creation number cannot be decided. + return Err(AptosDbError::from(anyhow::format_err!( + "PendingClaims resource not found" + ))); + }; + let offer_event = TokenOfferEvent::new( + *offer.to_address(), + offer.token_id().clone(), + offer.amount(), + ); + Ok(ContractEventV1::new( + key, + sequence_number, + TOKEN_OFFER_EVENT_TYPE.clone(), + bcs::to_bytes(&offer_event)?, + )) + } +} + +struct CancelOfferTranslator; +impl EventV2Translator for CancelOfferTranslator { + fn translate_event_v2_to_v1( + &self, + v2: &ContractEventV2, + engine: &EventV2TranslationEngine, + ) -> Result { + let cancel_offer = CancelOffer::try_from_bytes(v2.event_data())?; + let struct_tag = StructTag::from_str("0x3::token_transfers::PendingClaims")?; + let (key, sequence_number) = if let Some(state_value_bytes) = + engine.get_state_value_bytes_for_resource(cancel_offer.account(), &struct_tag)? + { + let object_resource: PendingClaimsResource = bcs::from_bytes(&state_value_bytes)?; + let key = *object_resource.cancel_offer_events().key(); + let sequence_number = engine + .get_next_sequence_number(&key, object_resource.cancel_offer_events().count())?; + (key, sequence_number) + } else { + // If the PendingClaims resource is not found, we skip the event translation to + // avoid panic because the creation number cannot be decided. + return Err(AptosDbError::from(anyhow::format_err!( + "PendingClaims resource not found" + ))); + }; + let cancel_offer_event = TokenCancelOfferEvent::new( + *cancel_offer.to_address(), + cancel_offer.token_id().clone(), + cancel_offer.amount(), + ); + Ok(ContractEventV1::new( + key, + sequence_number, + TOKEN_CANCEL_OFFER_EVENT_TYPE.clone(), + bcs::to_bytes(&cancel_offer_event)?, + )) + } +} + +struct ClaimTranslator; +impl EventV2Translator for ClaimTranslator { + fn translate_event_v2_to_v1( + &self, + v2: &ContractEventV2, + engine: &EventV2TranslationEngine, + ) -> Result { + let claim = Claim::try_from_bytes(v2.event_data())?; + let struct_tag = StructTag::from_str("0x3::token_transfers::PendingClaims")?; + let (key, sequence_number) = if let Some(state_value_bytes) = + engine.get_state_value_bytes_for_resource(claim.account(), &struct_tag)? + { + let object_resource: PendingClaimsResource = bcs::from_bytes(&state_value_bytes)?; + let key = *object_resource.claim_events().key(); + let sequence_number = + engine.get_next_sequence_number(&key, object_resource.claim_events().count())?; + (key, sequence_number) + } else { + // If the PendingClaims resource is not found, we skip the event translation to + // avoid panic because the creation number cannot be decided. + return Err(AptosDbError::from(anyhow::format_err!( + "PendingClaims resource not found" + ))); + }; + let claim_event = TokenClaimEvent::new( + *claim.to_address(), + claim.token_id().clone(), + claim.amount(), + ); + Ok(ContractEventV1::new( + key, + sequence_number, + TOKEN_CLAIM_EVENT_TYPE.clone(), + bcs::to_bytes(&claim_event)?, + )) + } +} + +struct CollectionDescriptionMutateTranslator; +impl EventV2Translator for CollectionDescriptionMutateTranslator { + fn translate_event_v2_to_v1( + &self, + v2: &ContractEventV2, + engine: &EventV2TranslationEngine, + ) -> Result { + let collection_description_mutate = + CollectionDescriptionMutate::try_from_bytes(v2.event_data())?; + let struct_tag = StructTag::from_str("0x3::token_event_store::TokenEventStoreV1")?; + let (key, sequence_number) = if let Some(state_value_bytes) = engine + .get_state_value_bytes_for_resource( + collection_description_mutate.creator_addr(), + &struct_tag, + )? { + let object_resource: TokenEventStoreV1Resource = bcs::from_bytes(&state_value_bytes)?; + let key = *object_resource.collection_description_mutate_events().key(); + let sequence_number = engine.get_next_sequence_number( + &key, + object_resource + .collection_description_mutate_events() + .count(), + )?; + (key, sequence_number) + } else { + // If the TokenEventStoreV1 resource is not found, we skip the event translation to + // avoid panic because the creation number cannot be decided. + return Err(AptosDbError::from(anyhow::format_err!( + "TokenEventStoreV1 resource not found" + ))); + }; + let collection_mutation_event = CollectionDescriptionMutateEvent::new( + *collection_description_mutate.creator_addr(), + collection_description_mutate.collection_name().clone(), + collection_description_mutate.old_description().clone(), + collection_description_mutate.new_description().clone(), + ); + Ok(ContractEventV1::new( + key, + sequence_number, + COLLECTION_DESCRIPTION_MUTATE_EVENT_TYPE.clone(), + bcs::to_bytes(&collection_mutation_event)?, + )) + } +} + +struct CollectionUriMutateTranslator; +impl EventV2Translator for CollectionUriMutateTranslator { + fn translate_event_v2_to_v1( + &self, + v2: &ContractEventV2, + engine: &EventV2TranslationEngine, + ) -> Result { + let collection_uri_mutate = CollectionUriMutate::try_from_bytes(v2.event_data())?; + let struct_tag = StructTag::from_str("0x3::token_event_store::TokenEventStoreV1")?; + let (key, sequence_number) = if let Some(state_value_bytes) = engine + .get_state_value_bytes_for_resource(collection_uri_mutate.creator_addr(), &struct_tag)? + { + let object_resource: TokenEventStoreV1Resource = bcs::from_bytes(&state_value_bytes)?; + let key = *object_resource.collection_uri_mutate_events().key(); + let sequence_number = engine.get_next_sequence_number( + &key, + object_resource.collection_uri_mutate_events().count(), + )?; + (key, sequence_number) + } else { + // If the TokenEventStoreV1 resource is not found, we skip the event translation to + // avoid panic because the creation number cannot be decided. + return Err(AptosDbError::from(anyhow::format_err!( + "TokenEventStoreV1 resource not found" + ))); + }; + let collection_mutation_event = CollectionUriMutateEvent::new( + *collection_uri_mutate.creator_addr(), + collection_uri_mutate.collection_name().clone(), + collection_uri_mutate.old_uri().clone(), + collection_uri_mutate.new_uri().clone(), + ); + Ok(ContractEventV1::new( + key, + sequence_number, + COLLECTION_URI_MUTATE_EVENT_TYPE.clone(), + bcs::to_bytes(&collection_mutation_event)?, + )) + } +} + +struct CollectionMaximumMutateTranslator; +impl EventV2Translator for CollectionMaximumMutateTranslator { + fn translate_event_v2_to_v1( + &self, + v2: &ContractEventV2, + engine: &EventV2TranslationEngine, + ) -> Result { + let collection_max_mutate = CollectionMaximumMutate::try_from_bytes(v2.event_data())?; + let struct_tag = StructTag::from_str("0x3::token_event_store::TokenEventStoreV1")?; + let (key, sequence_number) = if let Some(state_value_bytes) = engine + .get_state_value_bytes_for_resource(collection_max_mutate.creator_addr(), &struct_tag)? + { + let object_resource: TokenEventStoreV1Resource = bcs::from_bytes(&state_value_bytes)?; + let key = *object_resource.collection_maximum_mutate_events().key(); + let sequence_number = engine.get_next_sequence_number( + &key, + object_resource.collection_maximum_mutate_events().count(), + )?; + (key, sequence_number) + } else { + // If the TokenEventStoreV1 resource is not found, we skip the event translation to + // avoid panic because the creation number cannot be decided. + return Err(AptosDbError::from(anyhow::format_err!( + "TokenEventStoreV1 resource not found" + ))); + }; + let collection_mutation_event = CollectionMaximumMutateEvent::new( + *collection_max_mutate.creator_addr(), + collection_max_mutate.collection_name().clone(), + *collection_max_mutate.old_maximum(), + *collection_max_mutate.new_maximum(), + ); + Ok(ContractEventV1::new( + key, + sequence_number, + COLLECTION_MAXIMUM_MUTATE_EVENT_TYPE.clone(), + bcs::to_bytes(&collection_mutation_event)?, + )) + } +} + +struct UriMutationTranslator; +impl EventV2Translator for UriMutationTranslator { + fn translate_event_v2_to_v1( + &self, + v2: &ContractEventV2, + engine: &EventV2TranslationEngine, + ) -> Result { + let uri_mutation = UriMutation::try_from_bytes(v2.event_data())?; + let struct_tag = StructTag::from_str("0x3::token_event_store::TokenEventStoreV1")?; + let (key, sequence_number) = if let Some(state_value_bytes) = + engine.get_state_value_bytes_for_resource(uri_mutation.creator(), &struct_tag)? + { + let object_resource: TokenEventStoreV1Resource = bcs::from_bytes(&state_value_bytes)?; + let key = *object_resource.uri_mutate_events().key(); + let sequence_number = engine + .get_next_sequence_number(&key, object_resource.uri_mutate_events().count())?; + (key, sequence_number) + } else { + // If the TokenEventStoreV1 resource is not found, we skip the event translation to + // avoid panic because the creation number cannot be decided. + return Err(AptosDbError::from(anyhow::format_err!( + "TokenEventStoreV1 resource not found" + ))); + }; + let uri_mutation_event = UriMutationEvent::new( + *uri_mutation.creator(), + uri_mutation.collection().clone(), + uri_mutation.token().clone(), + uri_mutation.old_uri().clone(), + uri_mutation.new_uri().clone(), + ); + Ok(ContractEventV1::new( + key, + sequence_number, + URI_MUTATION_EVENT_TYPE.clone(), + bcs::to_bytes(&uri_mutation_event)?, + )) + } +} + +struct DefaultPropertyMutateTranslator; +impl EventV2Translator for DefaultPropertyMutateTranslator { + fn translate_event_v2_to_v1( + &self, + v2: &ContractEventV2, + engine: &EventV2TranslationEngine, + ) -> Result { + let default_property_mutate = DefaultPropertyMutate::try_from_bytes(v2.event_data())?; + let struct_tag = StructTag::from_str("0x3::token_event_store::TokenEventStoreV1")?; + let (key, sequence_number) = if let Some(state_value_bytes) = engine + .get_state_value_bytes_for_resource(default_property_mutate.creator(), &struct_tag)? + { + let object_resource: TokenEventStoreV1Resource = bcs::from_bytes(&state_value_bytes)?; + let key = *object_resource.default_property_mutate_events().key(); + let sequence_number = engine.get_next_sequence_number( + &key, + object_resource.default_property_mutate_events().count(), + )?; + (key, sequence_number) + } else { + // If the TokenEventStoreV1 resource is not found, we skip the event translation to + // avoid panic because the creation number cannot be decided. + return Err(AptosDbError::from(anyhow::format_err!( + "TokenEventStoreV1 resource not found" + ))); + }; + let default_property_mutate_event = DefaultPropertyMutateEvent::new( + *default_property_mutate.creator(), + default_property_mutate.collection().clone(), + default_property_mutate.token().clone(), + default_property_mutate.keys().clone(), + default_property_mutate.old_values().clone(), + default_property_mutate.new_values().clone(), + ); + Ok(ContractEventV1::new( + key, + sequence_number, + DEFAULT_PROPERTY_MUTATE_EVENT_TYPE.clone(), + bcs::to_bytes(&default_property_mutate_event)?, + )) + } +} + +struct DescriptionMutateTranslator; +impl EventV2Translator for DescriptionMutateTranslator { + fn translate_event_v2_to_v1( + &self, + v2: &ContractEventV2, + engine: &EventV2TranslationEngine, + ) -> Result { + let description_mutation = DescriptionMutate::try_from_bytes(v2.event_data())?; + let struct_tag = StructTag::from_str("0x3::token_event_store::TokenEventStoreV1")?; + let (key, sequence_number) = if let Some(state_value_bytes) = engine + .get_state_value_bytes_for_resource(description_mutation.creator(), &struct_tag)? + { + let object_resource: TokenEventStoreV1Resource = bcs::from_bytes(&state_value_bytes)?; + let key = *object_resource.description_mutate_events().key(); + let sequence_number = engine.get_next_sequence_number( + &key, + object_resource.description_mutate_events().count(), + )?; + (key, sequence_number) + } else { + // If the TokenEventStoreV1 resource is not found, we skip the event translation to + // avoid panic because the creation number cannot be decided. + return Err(AptosDbError::from(anyhow::format_err!( + "TokenEventStoreV1 resource not found" + ))); + }; + let description_mutation_event = DescriptionMutateEvent::new( + *description_mutation.creator(), + description_mutation.collection().clone(), + description_mutation.token().clone(), + description_mutation.old_description().clone(), + description_mutation.new_description().clone(), + ); + Ok(ContractEventV1::new( + key, + sequence_number, + DESCRIPTION_MUTATE_EVENT_TYPE.clone(), + bcs::to_bytes(&description_mutation_event)?, + )) + } +} + +struct RoyaltyMutateTranslator; +impl EventV2Translator for RoyaltyMutateTranslator { + fn translate_event_v2_to_v1( + &self, + v2: &ContractEventV2, + engine: &EventV2TranslationEngine, + ) -> Result { + let royalty_mutation = RoyaltyMutate::try_from_bytes(v2.event_data())?; + let struct_tag = StructTag::from_str("0x3::token_event_store::TokenEventStoreV1")?; + let (key, sequence_number) = if let Some(state_value_bytes) = + engine.get_state_value_bytes_for_resource(royalty_mutation.creator(), &struct_tag)? + { + let object_resource: TokenEventStoreV1Resource = bcs::from_bytes(&state_value_bytes)?; + let key = *object_resource.royalty_mutate_events().key(); + let sequence_number = engine + .get_next_sequence_number(&key, object_resource.royalty_mutate_events().count())?; + (key, sequence_number) + } else { + // If the TokenEventStoreV1 resource is not found, we skip the event translation to + // avoid panic because the creation number cannot be decided. + return Err(AptosDbError::from(anyhow::format_err!( + "TokenEventStoreV1 resource not found" + ))); + }; + let royalty_mutation_event = RoyaltyMutateEvent::new( + *royalty_mutation.creator(), + royalty_mutation.collection().clone(), + royalty_mutation.token().clone(), + *royalty_mutation.old_royalty_numerator(), + *royalty_mutation.old_royalty_denominator(), + *royalty_mutation.old_royalty_payee_addr(), + *royalty_mutation.new_royalty_numerator(), + *royalty_mutation.new_royalty_denominator(), + *royalty_mutation.new_royalty_payee_addr(), + ); + Ok(ContractEventV1::new( + key, + sequence_number, + ROYALTY_MUTATE_EVENT_TYPE.clone(), + bcs::to_bytes(&royalty_mutation_event)?, + )) + } +} + +struct MaximumMutateTranslator; +impl EventV2Translator for MaximumMutateTranslator { + fn translate_event_v2_to_v1( + &self, + v2: &ContractEventV2, + engine: &EventV2TranslationEngine, + ) -> Result { + let maximum_mutation = MaximumMutate::try_from_bytes(v2.event_data())?; + let struct_tag = StructTag::from_str("0x3::token_event_store::TokenEventStoreV1")?; + let (key, sequence_number) = if let Some(state_value_bytes) = + engine.get_state_value_bytes_for_resource(maximum_mutation.creator(), &struct_tag)? + { + let object_resource: TokenEventStoreV1Resource = bcs::from_bytes(&state_value_bytes)?; + let key = *object_resource.maximum_mutate_events().key(); + let sequence_number = engine + .get_next_sequence_number(&key, object_resource.maximum_mutate_events().count())?; + (key, sequence_number) + } else { + // If the TokenEventStoreV1 resource is not found, we skip the event translation to + // avoid panic because the creation number cannot be decided. + return Err(AptosDbError::from(anyhow::format_err!( + "TokenEventStoreV1 resource not found" + ))); + }; + let maximum_mutation_event = MaximumMutateEvent::new( + *maximum_mutation.creator(), + maximum_mutation.collection().clone(), + maximum_mutation.token().clone(), + *maximum_mutation.old_maximum(), + *maximum_mutation.new_maximum(), + ); + Ok(ContractEventV1::new( + key, + sequence_number, + MAXIMUM_MUTATE_EVENT_TYPE.clone(), + bcs::to_bytes(&maximum_mutation_event)?, + )) + } +} + +struct OptInTransferTranslator; +impl EventV2Translator for OptInTransferTranslator { + fn translate_event_v2_to_v1( + &self, + v2: &ContractEventV2, + engine: &EventV2TranslationEngine, + ) -> Result { + let opt_in_transfer = OptInTransfer::try_from_bytes(v2.event_data())?; + let struct_tag = StructTag::from_str("0x3::token_event_store::TokenEventStoreV1")?; + let (key, sequence_number) = if let Some(state_value_bytes) = engine + .get_state_value_bytes_for_resource(opt_in_transfer.account_address(), &struct_tag)? + { + let object_resource: TokenEventStoreV1Resource = bcs::from_bytes(&state_value_bytes)?; + let key = *object_resource.opt_in_events().key(); + let sequence_number = + engine.get_next_sequence_number(&key, object_resource.opt_in_events().count())?; + (key, sequence_number) + } else { + // If the TokenEventStoreV1 resource is not found, we skip the event translation to + // avoid panic because the creation number cannot be decided. + return Err(AptosDbError::from(anyhow::format_err!( + "TokenEventStoreV1 resource not found" + ))); + }; + let opt_in_transfer_event = OptInTransferEvent::new(*opt_in_transfer.opt_in()); + Ok(ContractEventV1::new( + key, + sequence_number, + OPT_IN_TRANSFER_EVENT_TYPE.clone(), + bcs::to_bytes(&opt_in_transfer_event)?, + )) + } +} diff --git a/storage/indexer/src/indexer_reader.rs b/storage/indexer/src/indexer_reader.rs index f82b1ba6aad8a..8143b9dd88cbd 100644 --- a/storage/indexer/src/indexer_reader.rs +++ b/storage/indexer/src/indexer_reader.rs @@ -5,7 +5,7 @@ use crate::{db_indexer::DBIndexer, db_v2::IndexerAsyncV2}; use anyhow::anyhow; use aptos_types::{ account_address::AccountAddress, - contract_event::EventWithVersion, + contract_event::{ContractEventV1, ContractEventV2, EventWithVersion}, event::EventKey, indexer::indexer_db_reader::{IndexerReader, Order}, state_store::{ @@ -164,4 +164,35 @@ impl IndexerReader for IndexerReaders { } anyhow::bail!("DB indexer reader is not available") } + + fn get_translated_v1_event_by_version_and_index( + &self, + version: Version, + index: u64, + ) -> anyhow::Result { + if let Some(db_indexer_reader) = &self.db_indexer_reader { + if db_indexer_reader.indexer_db.event_v2_translation_enabled() { + return Ok(db_indexer_reader + .indexer_db + .get_translated_v1_event_by_version_and_index(version, index)?); + } else { + anyhow::bail!("Event translation is not enabled") + } + } + anyhow::bail!("DB indexer reader is not available") + } + + fn translate_event_v2_to_v1( + &self, + v2: &ContractEventV2, + ) -> anyhow::Result> { + if let Some(db_indexer_reader) = &self.db_indexer_reader { + if db_indexer_reader.indexer_db.event_v2_translation_enabled() { + return Ok(db_indexer_reader.translate_event_v2_to_v1(v2)?); + } else { + anyhow::bail!("Event translation is not enabled") + } + } + anyhow::bail!("DB indexer reader is not available") + } } diff --git a/storage/indexer/src/lib.rs b/storage/indexer/src/lib.rs index 34331dd702c31..2929953d787a9 100644 --- a/storage/indexer/src/lib.rs +++ b/storage/indexer/src/lib.rs @@ -6,6 +6,7 @@ mod db; pub mod db_indexer; pub mod db_ops; pub mod db_v2; +pub mod event_v2_translator; pub mod indexer_reader; mod metrics; mod utils; diff --git a/storage/indexer_schemas/src/metadata.rs b/storage/indexer_schemas/src/metadata.rs index 940f724da79d0..0168eb34470b8 100644 --- a/storage/indexer_schemas/src/metadata.rs +++ b/storage/indexer_schemas/src/metadata.rs @@ -38,6 +38,7 @@ pub enum MetadataKey { EventVersion, StateVersion, TransactionVersion, + EventV2TranslationVersion, } #[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)] diff --git a/storage/indexer_schemas/src/schema/event_sequence_number/mod.rs b/storage/indexer_schemas/src/schema/event_sequence_number/mod.rs new file mode 100644 index 0000000000000..5f50a75c46aed --- /dev/null +++ b/storage/indexer_schemas/src/schema/event_sequence_number/mod.rs @@ -0,0 +1,53 @@ +// Copyright © Aptos Foundation +// Parts of the project are originally copyright © Meta Platforms, Inc. +// SPDX-License-Identifier: Apache-2.0 + +//! This module defines physical storage schema for event sequence numbers for associated event keys, +//! specifically for translated v1 events. +//! +//! ```text +//! |<--key---->|<-value->| +//! | event_key | seq_num | +//! ``` + +use crate::schema::EVENT_SEQUENCE_NUMBER_CF_NAME; +use anyhow::Result; +use aptos_schemadb::{ + define_pub_schema, + schema::{KeyCodec, ValueCodec}, +}; +use aptos_types::event::EventKey; + +define_pub_schema!( + EventSequenceNumberSchema, + Key, + Value, + EVENT_SEQUENCE_NUMBER_CF_NAME +); + +type SeqNum = u64; +type Key = EventKey; +type Value = SeqNum; + +impl KeyCodec for Key { + fn encode_key(&self) -> Result> { + Ok(bcs::to_bytes(self)?) + } + + fn decode_key(data: &[u8]) -> Result { + Ok(bcs::from_bytes(data)?) + } +} + +impl ValueCodec for Value { + fn encode_value(&self) -> Result> { + Ok(bcs::to_bytes(self)?) + } + + fn decode_value(data: &[u8]) -> Result { + Ok(bcs::from_bytes(data)?) + } +} + +#[cfg(test)] +mod test; diff --git a/storage/indexer_schemas/src/schema/event_sequence_number/test.rs b/storage/indexer_schemas/src/schema/event_sequence_number/test.rs new file mode 100644 index 0000000000000..dc078e160ff87 --- /dev/null +++ b/storage/indexer_schemas/src/schema/event_sequence_number/test.rs @@ -0,0 +1,19 @@ +// Copyright © Aptos Foundation +// Parts of the project are originally copyright © Meta Platforms, Inc. +// SPDX-License-Identifier: Apache-2.0 + +use super::*; +use aptos_schemadb::{schema::fuzzing::assert_encode_decode, test_no_panic_decoding}; +use proptest::prelude::*; + +proptest! { + #[test] + fn test_encode_decode( + event_key in any::(), + seq_num in any::(), + ) { + assert_encode_decode::(&event_key, &seq_num); + } +} + +test_no_panic_decoding!(EventSequenceNumberSchema); diff --git a/storage/indexer_schemas/src/schema/mod.rs b/storage/indexer_schemas/src/schema/mod.rs index 0f4dfd4c7bcd6..31c7e6c25267e 100644 --- a/storage/indexer_schemas/src/schema/mod.rs +++ b/storage/indexer_schemas/src/schema/mod.rs @@ -8,10 +8,14 @@ pub mod event_by_key; pub mod event_by_version; +pub mod event_sequence_number; pub mod indexer_metadata; pub mod state_keys; pub mod table_info; pub mod transaction_by_account; +pub mod translated_v1_event; + +use anyhow::ensure; use aptos_schemadb::ColumnFamilyName; pub const DEFAULT_COLUMN_FAMILY_NAME: ColumnFamilyName = "default"; @@ -22,6 +26,8 @@ pub const EVENT_BY_KEY_CF_NAME: ColumnFamilyName = "event_by_key"; pub const EVENT_BY_VERSION_CF_NAME: ColumnFamilyName = "event_by_version"; pub const TRANSACTION_BY_ACCOUNT_CF_NAME: ColumnFamilyName = "transaction_by_account"; pub const STATE_KEYS_CF_NAME: ColumnFamilyName = "state_keys"; +pub const TRANSLATED_V1_EVENT_CF_NAME: ColumnFamilyName = "translated_v1_event"; +pub const EVENT_SEQUENCE_NUMBER_CF_NAME: ColumnFamilyName = "event_sequence_number"; pub fn column_families() -> Vec { vec![ @@ -39,5 +45,17 @@ pub fn internal_indexer_column_families() -> Vec { EVENT_BY_VERSION_CF_NAME, TRANSACTION_BY_ACCOUNT_CF_NAME, STATE_KEYS_CF_NAME, + TRANSLATED_V1_EVENT_CF_NAME, + EVENT_SEQUENCE_NUMBER_CF_NAME, ] } + +fn ensure_slice_len_eq(data: &[u8], len: usize) -> anyhow::Result<()> { + ensure!( + data.len() == len, + "Unexpected data len {}, expected {}.", + data.len(), + len, + ); + Ok(()) +} diff --git a/storage/indexer_schemas/src/schema/translated_v1_event/mod.rs b/storage/indexer_schemas/src/schema/translated_v1_event/mod.rs new file mode 100644 index 0000000000000..9f196482389d8 --- /dev/null +++ b/storage/indexer_schemas/src/schema/translated_v1_event/mod.rs @@ -0,0 +1,66 @@ +// Copyright © Aptos Foundation +// Parts of the project are originally copyright © Meta Platforms, Inc. +// SPDX-License-Identifier: Apache-2.0 + +//! This module defines physical storage schema for the contract events. +//! +//! A translated v1 event is keyed by the version of the transaction it belongs to and the index of +//! the original v2 event among all events yielded by the same transaction. +//! ```text +//! |<-------key----->|<---value--->| +//! | version | index | event bytes | +//! ``` + +use crate::schema::{ensure_slice_len_eq, TRANSLATED_V1_EVENT_CF_NAME}; +use anyhow::Result; +use aptos_schemadb::{ + define_pub_schema, + schema::{KeyCodec, ValueCodec}, +}; +use aptos_types::{contract_event::ContractEventV1, transaction::Version}; +use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; +use std::mem::size_of; + +define_pub_schema!( + TranslatedV1EventSchema, + Key, + ContractEventV1, + TRANSLATED_V1_EVENT_CF_NAME +); + +type Index = u64; +type Key = (Version, Index); + +impl KeyCodec for Key { + fn encode_key(&self) -> Result> { + let (version, index) = *self; + + let mut encoded_key = Vec::with_capacity(size_of::() + size_of::()); + encoded_key.write_u64::(version)?; + encoded_key.write_u64::(index)?; + Ok(encoded_key) + } + + fn decode_key(data: &[u8]) -> Result { + ensure_slice_len_eq(data, size_of::())?; + + let version_size = size_of::(); + + let version = (&data[..version_size]).read_u64::()?; + let index = (&data[version_size..]).read_u64::()?; + Ok((version, index)) + } +} + +impl ValueCodec for ContractEventV1 { + fn encode_value(&self) -> Result> { + bcs::to_bytes(self).map_err(Into::into) + } + + fn decode_value(data: &[u8]) -> Result { + bcs::from_bytes(data).map_err(Into::into) + } +} + +#[cfg(test)] +mod test; diff --git a/storage/indexer_schemas/src/schema/translated_v1_event/test.rs b/storage/indexer_schemas/src/schema/translated_v1_event/test.rs new file mode 100644 index 0000000000000..d28c191121c04 --- /dev/null +++ b/storage/indexer_schemas/src/schema/translated_v1_event/test.rs @@ -0,0 +1,20 @@ +// Copyright © Aptos Foundation +// Parts of the project are originally copyright © Meta Platforms, Inc. +// SPDX-License-Identifier: Apache-2.0 + +use super::*; +use aptos_schemadb::{schema::fuzzing::assert_encode_decode, test_no_panic_decoding}; +use proptest::prelude::*; + +proptest! { + #[test] + fn test_encode_decode( + version in any::(), + index in any::(), + event in any::(), + ) { + assert_encode_decode::(&(version, index), &event); + } +} + +test_no_panic_decoding!(TranslatedV1EventSchema); diff --git a/third_party/move/move-core/types/src/language_storage.rs b/third_party/move/move-core/types/src/language_storage.rs index a957675bd9606..821b2e22c43d0 100644 --- a/third_party/move/move-core/types/src/language_storage.rs +++ b/third_party/move/move-core/types/src/language_storage.rs @@ -21,6 +21,8 @@ pub const RESOURCE_TAG: u8 = 1; /// Hex address: 0x1 pub const CORE_CODE_ADDRESS: AccountAddress = AccountAddress::ONE; +pub const TOKEN_ADDRESS: AccountAddress = AccountAddress::THREE; +pub const TOKEN_OBJECTS_ADDRESS: AccountAddress = AccountAddress::FOUR; #[derive(Serialize, Deserialize, Debug, PartialEq, Hash, Eq, Clone, PartialOrd, Ord)] #[cfg_attr( diff --git a/types/src/account_config/events/burn.rs b/types/src/account_config/events/burn.rs new file mode 100644 index 0000000000000..c6ba78604d877 --- /dev/null +++ b/types/src/account_config/events/burn.rs @@ -0,0 +1,73 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use crate::move_utils::move_event_v2::MoveEventV2Type; +use move_core_types::{ + account_address::AccountAddress, + ident_str, + identifier::IdentStr, + language_storage::{StructTag, TypeTag, TOKEN_OBJECTS_ADDRESS}, + move_resource::MoveStructType, +}; +use once_cell::sync::Lazy; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] +pub struct Burn { + collection: AccountAddress, + index: u64, + token: AccountAddress, + previous_owner: AccountAddress, +} + +impl Burn { + pub fn new( + collection: AccountAddress, + index: u64, + token: AccountAddress, + previous_owner: AccountAddress, + ) -> Self { + Self { + collection, + index, + token, + previous_owner, + } + } + + pub fn try_from_bytes(bytes: &[u8]) -> anyhow::Result { + bcs::from_bytes(bytes).map_err(Into::into) + } + + pub fn collection(&self) -> &AccountAddress { + &self.collection + } + + pub fn index(&self) -> &u64 { + &self.index + } + + pub fn token(&self) -> &AccountAddress { + &self.token + } + + pub fn previous_owner(&self) -> &AccountAddress { + &self.previous_owner + } +} + +impl MoveStructType for Burn { + const MODULE_NAME: &'static IdentStr = ident_str!("collection"); + const STRUCT_NAME: &'static IdentStr = ident_str!("Burn"); +} + +impl MoveEventV2Type for Burn {} + +pub static BURN_TYPE: Lazy = Lazy::new(|| { + TypeTag::Struct(Box::new(StructTag { + address: TOKEN_OBJECTS_ADDRESS, + module: ident_str!("collection").to_owned(), + name: ident_str!("Burn").to_owned(), + type_args: vec![], + })) +}); diff --git a/types/src/account_config/events/burn_event.rs b/types/src/account_config/events/burn_event.rs new file mode 100644 index 0000000000000..e6ce676ead0be --- /dev/null +++ b/types/src/account_config/events/burn_event.rs @@ -0,0 +1,53 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use crate::move_utils::move_event_v1::MoveEventV1Type; +use move_core_types::{ + account_address::AccountAddress, + ident_str, + identifier::IdentStr, + language_storage::{StructTag, TypeTag, TOKEN_OBJECTS_ADDRESS}, + move_resource::MoveStructType, +}; +use once_cell::sync::Lazy; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] +pub struct BurnEvent { + index: u64, + token: AccountAddress, +} + +impl BurnEvent { + pub fn new(index: u64, token: AccountAddress) -> Self { + Self { index, token } + } + + pub fn try_from_bytes(bytes: &[u8]) -> anyhow::Result { + bcs::from_bytes(bytes).map_err(Into::into) + } + + pub fn index(&self) -> &u64 { + &self.index + } + + pub fn token(&self) -> &AccountAddress { + &self.token + } +} + +impl MoveStructType for BurnEvent { + const MODULE_NAME: &'static IdentStr = ident_str!("collection"); + const STRUCT_NAME: &'static IdentStr = ident_str!("BurnEvent"); +} + +impl MoveEventV1Type for BurnEvent {} + +pub static BURN_EVENT_TYPE: Lazy = Lazy::new(|| { + TypeTag::Struct(Box::new(StructTag { + address: TOKEN_OBJECTS_ADDRESS, + module: ident_str!("collection").to_owned(), + name: ident_str!("BurnEvent").to_owned(), + type_args: vec![], + })) +}); diff --git a/types/src/account_config/events/burn_token.rs b/types/src/account_config/events/burn_token.rs new file mode 100644 index 0000000000000..1c0a4e01d84e3 --- /dev/null +++ b/types/src/account_config/events/burn_token.rs @@ -0,0 +1,63 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use crate::{account_config::TokenId, move_utils::move_event_v2::MoveEventV2Type}; +use anyhow::Result; +use move_core_types::{ + account_address::AccountAddress, + ident_str, + identifier::IdentStr, + language_storage::{StructTag, TypeTag, TOKEN_ADDRESS}, + move_resource::MoveStructType, +}; +use once_cell::sync::Lazy; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Deserialize, Serialize)] +pub struct BurnToken { + account: AccountAddress, + id: TokenId, + amount: u64, +} + +impl BurnToken { + pub fn new(account: AccountAddress, id: TokenId, amount: u64) -> Self { + Self { + account, + id, + amount, + } + } + + pub fn try_from_bytes(bytes: &[u8]) -> Result { + bcs::from_bytes(bytes).map_err(Into::into) + } + + pub fn account(&self) -> &AccountAddress { + &self.account + } + + pub fn id(&self) -> &TokenId { + &self.id + } + + pub fn amount(&self) -> u64 { + self.amount + } +} + +impl MoveStructType for BurnToken { + const MODULE_NAME: &'static IdentStr = ident_str!("token"); + const STRUCT_NAME: &'static IdentStr = ident_str!("Burn"); +} + +impl MoveEventV2Type for BurnToken {} + +pub static BURN_TOKEN_TYPE: Lazy = Lazy::new(|| { + TypeTag::Struct(Box::new(StructTag { + address: TOKEN_ADDRESS, + module: ident_str!("token").to_owned(), + name: ident_str!("Burn").to_owned(), + type_args: vec![], + })) +}); diff --git a/types/src/account_config/events/burn_token_event.rs b/types/src/account_config/events/burn_token_event.rs new file mode 100644 index 0000000000000..bee2068800e32 --- /dev/null +++ b/types/src/account_config/events/burn_token_event.rs @@ -0,0 +1,53 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use crate::{account_config::TokenId, move_utils::move_event_v1::MoveEventV1Type}; +use anyhow::Result; +use move_core_types::{ + ident_str, + identifier::IdentStr, + language_storage::{StructTag, TypeTag, TOKEN_ADDRESS}, + move_resource::MoveStructType, +}; +use once_cell::sync::Lazy; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Deserialize, Serialize)] +pub struct BurnTokenEvent { + id: TokenId, + amount: u64, +} + +impl BurnTokenEvent { + pub fn new(id: TokenId, amount: u64) -> Self { + Self { id, amount } + } + + pub fn try_from_bytes(bytes: &[u8]) -> Result { + bcs::from_bytes(bytes).map_err(Into::into) + } + + pub fn id(&self) -> &TokenId { + &self.id + } + + pub fn amount(&self) -> u64 { + self.amount + } +} + +impl MoveStructType for BurnTokenEvent { + const MODULE_NAME: &'static IdentStr = ident_str!("token"); + const STRUCT_NAME: &'static IdentStr = ident_str!("BurnTokenEvent"); +} + +impl MoveEventV1Type for BurnTokenEvent {} + +pub static BURN_TOKEN_EVENT_TYPE: Lazy = Lazy::new(|| { + TypeTag::Struct(Box::new(StructTag { + address: TOKEN_ADDRESS, + module: ident_str!("token").to_owned(), + name: ident_str!("BurnTokenEvent").to_owned(), + type_args: vec![], + })) +}); diff --git a/types/src/account_config/events/cancel_offer.rs b/types/src/account_config/events/cancel_offer.rs new file mode 100644 index 0000000000000..0af298e251b6f --- /dev/null +++ b/types/src/account_config/events/cancel_offer.rs @@ -0,0 +1,74 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use crate::{account_config::TokenId, move_utils::move_event_v2::MoveEventV2Type}; +use anyhow::Result; +use move_core_types::{ + account_address::AccountAddress, + ident_str, + identifier::IdentStr, + language_storage::{StructTag, TypeTag, TOKEN_ADDRESS}, + move_resource::MoveStructType, +}; +use once_cell::sync::Lazy; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Deserialize, Serialize)] +pub struct CancelOffer { + account: AccountAddress, + to_address: AccountAddress, + token_id: TokenId, + amount: u64, +} + +impl CancelOffer { + pub fn new( + account: AccountAddress, + to_address: AccountAddress, + token_id: TokenId, + amount: u64, + ) -> Self { + Self { + account, + to_address, + token_id, + amount, + } + } + + pub fn try_from_bytes(bytes: &[u8]) -> Result { + bcs::from_bytes(bytes).map_err(Into::into) + } + + pub fn account(&self) -> &AccountAddress { + &self.account + } + + pub fn to_address(&self) -> &AccountAddress { + &self.to_address + } + + pub fn token_id(&self) -> &TokenId { + &self.token_id + } + + pub fn amount(&self) -> u64 { + self.amount + } +} + +impl MoveStructType for CancelOffer { + const MODULE_NAME: &'static IdentStr = ident_str!("token_transfers"); + const STRUCT_NAME: &'static IdentStr = ident_str!("CancelOffer"); +} + +impl MoveEventV2Type for CancelOffer {} + +pub static CANCEL_OFFER_TYPE: Lazy = Lazy::new(|| { + TypeTag::Struct(Box::new(StructTag { + address: TOKEN_ADDRESS, + module: ident_str!("token_transfers").to_owned(), + name: ident_str!("CancelOffer").to_owned(), + type_args: vec![], + })) +}); diff --git a/types/src/account_config/events/claim.rs b/types/src/account_config/events/claim.rs new file mode 100644 index 0000000000000..57846d2bcc8b9 --- /dev/null +++ b/types/src/account_config/events/claim.rs @@ -0,0 +1,74 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use crate::{account_config::TokenId, move_utils::move_event_v2::MoveEventV2Type}; +use anyhow::Result; +use move_core_types::{ + account_address::AccountAddress, + ident_str, + identifier::IdentStr, + language_storage::{StructTag, TypeTag, TOKEN_ADDRESS}, + move_resource::MoveStructType, +}; +use once_cell::sync::Lazy; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Deserialize, Serialize)] +pub struct Claim { + account: AccountAddress, + to_address: AccountAddress, + token_id: TokenId, + amount: u64, +} + +impl Claim { + pub fn new( + account: AccountAddress, + to_address: AccountAddress, + token_id: TokenId, + amount: u64, + ) -> Self { + Self { + account, + to_address, + token_id, + amount, + } + } + + pub fn try_from_bytes(bytes: &[u8]) -> Result { + bcs::from_bytes(bytes).map_err(Into::into) + } + + pub fn account(&self) -> &AccountAddress { + &self.account + } + + pub fn to_address(&self) -> &AccountAddress { + &self.to_address + } + + pub fn token_id(&self) -> &TokenId { + &self.token_id + } + + pub fn amount(&self) -> u64 { + self.amount + } +} + +impl MoveStructType for Claim { + const MODULE_NAME: &'static IdentStr = ident_str!("token_transfers"); + const STRUCT_NAME: &'static IdentStr = ident_str!("Claim"); +} + +impl MoveEventV2Type for Claim {} + +pub static CLAIM_TYPE: Lazy = Lazy::new(|| { + TypeTag::Struct(Box::new(StructTag { + address: TOKEN_ADDRESS, + module: ident_str!("token_transfers").to_owned(), + name: ident_str!("Claim").to_owned(), + type_args: vec![], + })) +}); diff --git a/types/src/account_config/events/coin.rs b/types/src/account_config/events/coin.rs deleted file mode 100644 index 1a0cf5844e7e5..0000000000000 --- a/types/src/account_config/events/coin.rs +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright © Aptos Foundation -// SPDX-License-Identifier: Apache-2.0 - -use crate::{ - account_config::TypeInfoResource, - move_utils::{move_event_v1::MoveEventV1Type, move_event_v2::MoveEventV2Type}, -}; -use anyhow::Result; -use move_core_types::{ - account_address::AccountAddress, ident_str, identifier::IdentStr, move_resource::MoveStructType, -}; -use serde::{Deserialize, Serialize}; - -/// Struct that represents a SentPaymentEvent. -#[derive(Debug, Serialize, Deserialize)] -pub struct WithdrawEvent { - pub amount: u64, -} - -impl WithdrawEvent { - pub fn try_from_bytes(bytes: &[u8]) -> Result { - bcs::from_bytes(bytes).map_err(Into::into) - } - - /// Get the amount sent or received - pub fn amount(&self) -> u64 { - self.amount - } -} - -impl MoveStructType for WithdrawEvent { - const MODULE_NAME: &'static IdentStr = ident_str!("coin"); - const STRUCT_NAME: &'static IdentStr = ident_str!("WithdrawEvent"); -} - -impl MoveEventV1Type for WithdrawEvent {} - -#[derive(Debug, Serialize, Deserialize)] -pub struct CoinWithdraw { - pub coin_type: String, - pub account: AccountAddress, - pub amount: u64, -} - -impl CoinWithdraw { - pub fn try_from_bytes(bytes: &[u8]) -> Result { - bcs::from_bytes(bytes).map_err(Into::into) - } -} - -impl MoveStructType for CoinWithdraw { - const MODULE_NAME: &'static IdentStr = ident_str!("coin"); - const STRUCT_NAME: &'static IdentStr = ident_str!("CoinWithdraw"); -} - -impl MoveEventV2Type for CoinWithdraw {} - -/// Struct that represents a DepositPaymentEvent. -#[derive(Debug, Serialize, Deserialize)] -pub struct DepositEvent { - pub amount: u64, -} - -impl DepositEvent { - pub fn try_from_bytes(bytes: &[u8]) -> Result { - bcs::from_bytes(bytes).map_err(Into::into) - } - - /// Get the amount sent or received - pub fn amount(&self) -> u64 { - self.amount - } -} - -impl MoveStructType for DepositEvent { - const MODULE_NAME: &'static IdentStr = ident_str!("coin"); - const STRUCT_NAME: &'static IdentStr = ident_str!("DepositEvent"); -} - -impl MoveEventV1Type for DepositEvent {} - -#[derive(Debug, Serialize, Deserialize)] -pub struct CoinDeposit { - pub coin_type: String, - pub account: AccountAddress, - pub amount: u64, -} - -impl CoinDeposit { - pub fn try_from_bytes(bytes: &[u8]) -> Result { - bcs::from_bytes(bytes).map_err(Into::into) - } -} - -impl MoveStructType for CoinDeposit { - const MODULE_NAME: &'static IdentStr = ident_str!("coin"); - const STRUCT_NAME: &'static IdentStr = ident_str!("CoinDeposit"); -} - -impl MoveEventV2Type for CoinDeposit {} - -#[derive(Debug, Serialize, Deserialize)] -pub struct CoinRegister { - pub account: AccountAddress, - pub type_info: TypeInfoResource, -} - -impl MoveStructType for CoinRegister { - const MODULE_NAME: &'static IdentStr = ident_str!("account"); - const STRUCT_NAME: &'static IdentStr = ident_str!("CoinRegister"); -} - -impl MoveEventV2Type for CoinRegister {} diff --git a/types/src/account_config/events/coin_deposit.rs b/types/src/account_config/events/coin_deposit.rs new file mode 100644 index 0000000000000..230d1ed27e7a6 --- /dev/null +++ b/types/src/account_config/events/coin_deposit.rs @@ -0,0 +1,62 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use crate::move_utils::move_event_v2::MoveEventV2Type; +use move_core_types::{ + account_address::AccountAddress, + ident_str, + identifier::IdentStr, + language_storage::{StructTag, TypeTag, CORE_CODE_ADDRESS}, + move_resource::MoveStructType, +}; +use once_cell::sync::Lazy; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] +pub struct CoinDeposit { + pub coin_type: String, + pub account: AccountAddress, + pub amount: u64, +} + +impl CoinDeposit { + pub fn new(coin_type: String, account: AccountAddress, amount: u64) -> Self { + Self { + coin_type, + account, + amount, + } + } + + pub fn try_from_bytes(bytes: &[u8]) -> anyhow::Result { + bcs::from_bytes(bytes).map_err(Into::into) + } + + pub fn coin_type(&self) -> &str { + &self.coin_type + } + + pub fn account(&self) -> &AccountAddress { + &self.account + } + + pub fn amount(&self) -> u64 { + self.amount + } +} + +impl MoveStructType for CoinDeposit { + const MODULE_NAME: &'static IdentStr = ident_str!("coin"); + const STRUCT_NAME: &'static IdentStr = ident_str!("CoinDeposit"); +} + +impl MoveEventV2Type for CoinDeposit {} + +pub static COIN_DEPOSIT_TYPE: Lazy = Lazy::new(|| { + TypeTag::Struct(Box::new(StructTag { + address: CORE_CODE_ADDRESS, + module: ident_str!("coin").to_owned(), + name: ident_str!("CoinDeposit").to_owned(), + type_args: vec![], + })) +}); diff --git a/types/src/account_config/events/coin_register.rs b/types/src/account_config/events/coin_register.rs new file mode 100644 index 0000000000000..0e947aed35eab --- /dev/null +++ b/types/src/account_config/events/coin_register.rs @@ -0,0 +1,50 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use crate::{account_config::TypeInfoResource, move_utils::move_event_v2::MoveEventV2Type}; +use anyhow::Result; +use move_core_types::{ + account_address::AccountAddress, + ident_str, + identifier::IdentStr, + language_storage::{StructTag, TypeTag, CORE_CODE_ADDRESS}, + move_resource::MoveStructType, +}; +use once_cell::sync::Lazy; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize)] +pub struct CoinRegister { + pub account: AccountAddress, + pub type_info: TypeInfoResource, +} + +impl CoinRegister { + pub fn try_from_bytes(bytes: &[u8]) -> Result { + bcs::from_bytes(bytes).map_err(Into::into) + } + + pub fn account(&self) -> &AccountAddress { + &self.account + } + + pub fn type_info(&self) -> &TypeInfoResource { + &self.type_info + } +} + +impl MoveStructType for CoinRegister { + const MODULE_NAME: &'static IdentStr = ident_str!("account"); + const STRUCT_NAME: &'static IdentStr = ident_str!("CoinRegister"); +} + +impl MoveEventV2Type for CoinRegister {} + +pub static COIN_REGISTER_TYPE: Lazy = Lazy::new(|| { + TypeTag::Struct(Box::new(StructTag { + address: CORE_CODE_ADDRESS, + module: ident_str!("account").to_owned(), + name: ident_str!("CoinRegister").to_owned(), + type_args: vec![], + })) +}); diff --git a/types/src/account_config/events/coin_register_event.rs b/types/src/account_config/events/coin_register_event.rs new file mode 100644 index 0000000000000..08fa7a363abaa --- /dev/null +++ b/types/src/account_config/events/coin_register_event.rs @@ -0,0 +1,44 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use crate::{account_config::TypeInfoResource, move_utils::move_event_v1::MoveEventV1Type}; +use anyhow::Result; +use move_core_types::{ + ident_str, + identifier::IdentStr, + language_storage::{StructTag, TypeTag, CORE_CODE_ADDRESS}, + move_resource::MoveStructType, +}; +use once_cell::sync::Lazy; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize)] +pub struct CoinRegisterEvent { + type_info: TypeInfoResource, +} + +impl CoinRegisterEvent { + pub fn new(type_info: TypeInfoResource) -> Self { + Self { type_info } + } + + pub fn try_from_bytes(bytes: &[u8]) -> Result { + bcs::from_bytes(bytes).map_err(Into::into) + } +} + +impl MoveStructType for CoinRegisterEvent { + const MODULE_NAME: &'static IdentStr = ident_str!("account"); + const STRUCT_NAME: &'static IdentStr = ident_str!("CoinRegisterEvent"); +} + +impl MoveEventV1Type for CoinRegisterEvent {} + +pub static COIN_REGISTER_EVENT_TYPE: Lazy = Lazy::new(|| { + TypeTag::Struct(Box::new(StructTag { + address: CORE_CODE_ADDRESS, + module: ident_str!("account").to_owned(), + name: ident_str!("CoinRegisterEvent").to_owned(), + type_args: vec![], + })) +}); diff --git a/types/src/account_config/events/coin_withdraw.rs b/types/src/account_config/events/coin_withdraw.rs new file mode 100644 index 0000000000000..7edcd6438a68a --- /dev/null +++ b/types/src/account_config/events/coin_withdraw.rs @@ -0,0 +1,62 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use crate::move_utils::move_event_v2::MoveEventV2Type; +use move_core_types::{ + account_address::AccountAddress, + ident_str, + identifier::IdentStr, + language_storage::{StructTag, TypeTag, CORE_CODE_ADDRESS}, + move_resource::MoveStructType, +}; +use once_cell::sync::Lazy; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] +pub struct CoinWithdraw { + pub coin_type: String, + pub account: AccountAddress, + pub amount: u64, +} + +impl CoinWithdraw { + pub fn new(coin_type: String, account: AccountAddress, amount: u64) -> Self { + Self { + coin_type, + account, + amount, + } + } + + pub fn try_from_bytes(bytes: &[u8]) -> anyhow::Result { + bcs::from_bytes(bytes).map_err(Into::into) + } + + pub fn coin_type(&self) -> &str { + &self.coin_type + } + + pub fn account(&self) -> &AccountAddress { + &self.account + } + + pub fn amount(&self) -> u64 { + self.amount + } +} + +impl MoveStructType for CoinWithdraw { + const MODULE_NAME: &'static IdentStr = ident_str!("coin"); + const STRUCT_NAME: &'static IdentStr = ident_str!("CoinWithdraw"); +} + +impl MoveEventV2Type for CoinWithdraw {} + +pub static COIN_WITHDRAW_TYPE: Lazy = Lazy::new(|| { + TypeTag::Struct(Box::new(StructTag { + address: CORE_CODE_ADDRESS, + module: ident_str!("coin").to_owned(), + name: ident_str!("CoinWithdraw").to_owned(), + type_args: vec![], + })) +}); diff --git a/types/src/account_config/events/collection_description_mutate.rs b/types/src/account_config/events/collection_description_mutate.rs new file mode 100644 index 0000000000000..a727548d8b8f3 --- /dev/null +++ b/types/src/account_config/events/collection_description_mutate.rs @@ -0,0 +1,74 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use crate::move_utils::move_event_v2::MoveEventV2Type; +use anyhow::Result; +use move_core_types::{ + account_address::AccountAddress, + ident_str, + identifier::IdentStr, + language_storage::{StructTag, TypeTag, TOKEN_ADDRESS}, + move_resource::MoveStructType, +}; +use once_cell::sync::Lazy; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Deserialize, Serialize)] +pub struct CollectionDescriptionMutate { + creator_addr: AccountAddress, + collection_name: String, + old_description: String, + new_description: String, +} + +impl CollectionDescriptionMutate { + pub fn new( + creator_addr: AccountAddress, + collection_name: String, + old_description: String, + new_description: String, + ) -> Self { + Self { + creator_addr, + collection_name, + old_description, + new_description, + } + } + + pub fn try_from_bytes(bytes: &[u8]) -> Result { + bcs::from_bytes(bytes).map_err(Into::into) + } + + pub fn creator_addr(&self) -> &AccountAddress { + &self.creator_addr + } + + pub fn collection_name(&self) -> &String { + &self.collection_name + } + + pub fn old_description(&self) -> &String { + &self.old_description + } + + pub fn new_description(&self) -> &String { + &self.new_description + } +} + +impl MoveStructType for CollectionDescriptionMutate { + const MODULE_NAME: &'static IdentStr = ident_str!("token_event_store"); + const STRUCT_NAME: &'static IdentStr = ident_str!("CollectionDescriptionMutate"); +} + +impl MoveEventV2Type for CollectionDescriptionMutate {} + +pub static COLLECTION_DESCRIPTION_MUTATE_TYPE: Lazy = Lazy::new(|| { + TypeTag::Struct(Box::new(StructTag { + address: TOKEN_ADDRESS, + module: ident_str!("token_event_store").to_owned(), + name: ident_str!("CollectionDescriptionMutate").to_owned(), + type_args: vec![], + })) +}); diff --git a/types/src/account_config/events/collection_description_mutate_event.rs b/types/src/account_config/events/collection_description_mutate_event.rs new file mode 100644 index 0000000000000..9df55ce686361 --- /dev/null +++ b/types/src/account_config/events/collection_description_mutate_event.rs @@ -0,0 +1,74 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use crate::move_utils::move_event_v1::MoveEventV1Type; +use anyhow::Result; +use move_core_types::{ + account_address::AccountAddress, + ident_str, + identifier::IdentStr, + language_storage::{StructTag, TypeTag, TOKEN_ADDRESS}, + move_resource::MoveStructType, +}; +use once_cell::sync::Lazy; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Deserialize, Serialize)] +pub struct CollectionDescriptionMutateEvent { + creator_addr: AccountAddress, + collection_name: String, + old_description: String, + new_description: String, +} + +impl CollectionDescriptionMutateEvent { + pub fn new( + creator_addr: AccountAddress, + collection_name: String, + old_description: String, + new_description: String, + ) -> Self { + Self { + creator_addr, + collection_name, + old_description, + new_description, + } + } + + pub fn try_from_bytes(bytes: &[u8]) -> Result { + bcs::from_bytes(bytes).map_err(Into::into) + } + + pub fn creator_addr(&self) -> &AccountAddress { + &self.creator_addr + } + + pub fn collection_name(&self) -> &String { + &self.collection_name + } + + pub fn old_description(&self) -> &String { + &self.old_description + } + + pub fn new_description(&self) -> &String { + &self.new_description + } +} + +impl MoveStructType for CollectionDescriptionMutateEvent { + const MODULE_NAME: &'static IdentStr = ident_str!("token_event_store"); + const STRUCT_NAME: &'static IdentStr = ident_str!("CollectionDescriptionMutateEvent"); +} + +impl MoveEventV1Type for CollectionDescriptionMutateEvent {} + +pub static COLLECTION_DESCRIPTION_MUTATE_EVENT_TYPE: Lazy = Lazy::new(|| { + TypeTag::Struct(Box::new(StructTag { + address: TOKEN_ADDRESS, + module: ident_str!("token_event_store").to_owned(), + name: ident_str!("CollectionDescriptionMutateEvent").to_owned(), + type_args: vec![], + })) +}); diff --git a/types/src/account_config/events/collection_maximum_mutate.rs b/types/src/account_config/events/collection_maximum_mutate.rs new file mode 100644 index 0000000000000..a1242bf57528b --- /dev/null +++ b/types/src/account_config/events/collection_maximum_mutate.rs @@ -0,0 +1,74 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use crate::move_utils::move_event_v2::MoveEventV2Type; +use anyhow::Result; +use move_core_types::{ + account_address::AccountAddress, + ident_str, + identifier::IdentStr, + language_storage::{StructTag, TypeTag, TOKEN_ADDRESS}, + move_resource::MoveStructType, +}; +use once_cell::sync::Lazy; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Deserialize, Serialize)] +pub struct CollectionMaximumMutate { + creator_addr: AccountAddress, + collection_name: String, + old_maximum: u64, + new_maximum: u64, +} + +impl CollectionMaximumMutate { + pub fn new( + creator_addr: AccountAddress, + collection_name: String, + old_maximum: u64, + new_maximum: u64, + ) -> Self { + Self { + creator_addr, + collection_name, + old_maximum, + new_maximum, + } + } + + pub fn try_from_bytes(bytes: &[u8]) -> Result { + bcs::from_bytes(bytes).map_err(Into::into) + } + + pub fn creator_addr(&self) -> &AccountAddress { + &self.creator_addr + } + + pub fn collection_name(&self) -> &String { + &self.collection_name + } + + pub fn old_maximum(&self) -> &u64 { + &self.old_maximum + } + + pub fn new_maximum(&self) -> &u64 { + &self.new_maximum + } +} + +impl MoveStructType for CollectionMaximumMutate { + const MODULE_NAME: &'static IdentStr = ident_str!("token_event_store"); + const STRUCT_NAME: &'static IdentStr = ident_str!("CollectionMaximumMutate"); +} + +impl MoveEventV2Type for CollectionMaximumMutate {} + +pub static COLLECTION_MAXIMUM_MUTATE_TYPE: Lazy = Lazy::new(|| { + TypeTag::Struct(Box::new(StructTag { + address: TOKEN_ADDRESS, + module: ident_str!("token_event_store").to_owned(), + name: ident_str!("CollectionMaximumMutate").to_owned(), + type_args: vec![], + })) +}); diff --git a/types/src/account_config/events/collection_maximum_mutate_event.rs b/types/src/account_config/events/collection_maximum_mutate_event.rs new file mode 100644 index 0000000000000..6e9f289629bfe --- /dev/null +++ b/types/src/account_config/events/collection_maximum_mutate_event.rs @@ -0,0 +1,76 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use crate::move_utils::move_event_v1::MoveEventV1Type; +use anyhow::Result; +use move_core_types::{ + account_address::AccountAddress, + ident_str, + identifier::IdentStr, + language_storage::{StructTag, TypeTag, TOKEN_ADDRESS}, + move_resource::MoveStructType, +}; +use once_cell::sync::Lazy; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Deserialize, Serialize)] +pub struct CollectionMaximumMutateEvent { + creator_addr: AccountAddress, + collection_name: String, + old_maximum: u64, + new_maximum: u64, +} + +impl CollectionMaximumMutateEvent { + pub fn new( + creator_addr: AccountAddress, + collection_name: String, + old_maximum: u64, + new_maximum: u64, + ) -> Self { + Self { + creator_addr, + collection_name, + old_maximum, + new_maximum, + } + } + + pub fn try_from_bytes(bytes: &[u8]) -> Result { + bcs::from_bytes(bytes).map_err(Into::into) + } + + pub fn creator_addr(&self) -> &AccountAddress { + &self.creator_addr + } + + pub fn collection_name(&self) -> &String { + &self.collection_name + } + + pub fn old_maximum(&self) -> &u64 { + &self.old_maximum + } + + pub fn new_maximum(&self) -> &u64 { + &self.new_maximum + } +} + +impl MoveStructType for CollectionMaximumMutateEvent { + const MODULE_NAME: &'static IdentStr = ident_str!("token_event_store"); + // The struct name in the Move code contains a typo. + const STRUCT_NAME: &'static IdentStr = ident_str!("CollectionMaxiumMutateEvent"); +} + +impl MoveEventV1Type for CollectionMaximumMutateEvent {} + +pub static COLLECTION_MAXIMUM_MUTATE_EVENT_TYPE: Lazy = Lazy::new(|| { + TypeTag::Struct(Box::new(StructTag { + address: TOKEN_ADDRESS, + module: ident_str!("token_event_store").to_owned(), + // The struct name in the Move code contains a typo. + name: ident_str!("CollectionMaxiumMutateEvent").to_owned(), + type_args: vec![], + })) +}); diff --git a/types/src/account_config/events/collection_mutation.rs b/types/src/account_config/events/collection_mutation.rs new file mode 100644 index 0000000000000..57a5f7e254127 --- /dev/null +++ b/types/src/account_config/events/collection_mutation.rs @@ -0,0 +1,72 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use crate::{account_config::Object, move_utils::move_event_v2::MoveEventV2Type}; +use move_core_types::{ + ident_str, + identifier::IdentStr, + language_storage::{StructTag, TypeTag, TOKEN_OBJECTS_ADDRESS}, + move_resource::MoveStructType, +}; +use once_cell::sync::Lazy; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] +pub struct CollectionMutation { + mutated_field_name: String, + collection: Object, + old_value: String, + new_value: String, +} + +impl CollectionMutation { + pub fn new( + mutated_field_name: String, + collection: Object, + old_value: String, + new_value: String, + ) -> Self { + Self { + mutated_field_name, + collection, + old_value, + new_value, + } + } + + pub fn try_from_bytes(bytes: &[u8]) -> anyhow::Result { + bcs::from_bytes(bytes).map_err(Into::into) + } + + pub fn mutated_field_name(&self) -> &String { + &self.mutated_field_name + } + + pub fn collection(&self) -> &Object { + &self.collection + } + + pub fn old_value(&self) -> &String { + &self.old_value + } + + pub fn new_value(&self) -> &String { + &self.new_value + } +} + +impl MoveStructType for CollectionMutation { + const MODULE_NAME: &'static IdentStr = ident_str!("collection"); + const STRUCT_NAME: &'static IdentStr = ident_str!("Mutation"); +} + +impl MoveEventV2Type for CollectionMutation {} + +pub static COLLECTION_MUTATION_TYPE: Lazy = Lazy::new(|| { + TypeTag::Struct(Box::new(StructTag { + address: TOKEN_OBJECTS_ADDRESS, + module: ident_str!("collection").to_owned(), + name: ident_str!("Mutation").to_owned(), + type_args: vec![], + })) +}); diff --git a/types/src/account_config/events/collection_mutation_event.rs b/types/src/account_config/events/collection_mutation_event.rs new file mode 100644 index 0000000000000..cc50d1b49c906 --- /dev/null +++ b/types/src/account_config/events/collection_mutation_event.rs @@ -0,0 +1,47 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use crate::move_utils::move_event_v1::MoveEventV1Type; +use move_core_types::{ + ident_str, + identifier::IdentStr, + language_storage::{StructTag, TypeTag, TOKEN_OBJECTS_ADDRESS}, + move_resource::MoveStructType, +}; +use once_cell::sync::Lazy; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] +pub struct CollectionMutationEvent { + mutated_field_name: String, +} + +impl CollectionMutationEvent { + pub fn new(mutated_field_name: String) -> Self { + Self { mutated_field_name } + } + + pub fn try_from_bytes(bytes: &[u8]) -> anyhow::Result { + bcs::from_bytes(bytes).map_err(Into::into) + } + + pub fn mutated_field_name(&self) -> &String { + &self.mutated_field_name + } +} + +impl MoveStructType for CollectionMutationEvent { + const MODULE_NAME: &'static IdentStr = ident_str!("collection"); + const STRUCT_NAME: &'static IdentStr = ident_str!("MutationEvent"); +} + +impl MoveEventV1Type for CollectionMutationEvent {} + +pub static COLLECTION_MUTATION_EVENT_TYPE: Lazy = Lazy::new(|| { + TypeTag::Struct(Box::new(StructTag { + address: TOKEN_OBJECTS_ADDRESS, + module: ident_str!("collection").to_owned(), + name: ident_str!("MutationEvent").to_owned(), + type_args: vec![], + })) +}); diff --git a/types/src/account_config/events/collection_uri_mutate.rs b/types/src/account_config/events/collection_uri_mutate.rs new file mode 100644 index 0000000000000..f61342c940d63 --- /dev/null +++ b/types/src/account_config/events/collection_uri_mutate.rs @@ -0,0 +1,74 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use crate::move_utils::move_event_v2::MoveEventV2Type; +use anyhow::Result; +use move_core_types::{ + account_address::AccountAddress, + ident_str, + identifier::IdentStr, + language_storage::{StructTag, TypeTag, TOKEN_ADDRESS}, + move_resource::MoveStructType, +}; +use once_cell::sync::Lazy; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Deserialize, Serialize)] +pub struct CollectionUriMutate { + creator_addr: AccountAddress, + collection_name: String, + old_uri: String, + new_uri: String, +} + +impl CollectionUriMutate { + pub fn new( + creator_addr: AccountAddress, + collection_name: String, + old_uri: String, + new_uri: String, + ) -> Self { + Self { + creator_addr, + collection_name, + old_uri, + new_uri, + } + } + + pub fn try_from_bytes(bytes: &[u8]) -> Result { + bcs::from_bytes(bytes).map_err(Into::into) + } + + pub fn creator_addr(&self) -> &AccountAddress { + &self.creator_addr + } + + pub fn collection_name(&self) -> &String { + &self.collection_name + } + + pub fn old_uri(&self) -> &String { + &self.old_uri + } + + pub fn new_uri(&self) -> &String { + &self.new_uri + } +} + +impl MoveStructType for CollectionUriMutate { + const MODULE_NAME: &'static IdentStr = ident_str!("token_event_store"); + const STRUCT_NAME: &'static IdentStr = ident_str!("CollectionUriMutate"); +} + +impl MoveEventV2Type for CollectionUriMutate {} + +pub static COLLECTION_URI_MUTATE_TYPE: Lazy = Lazy::new(|| { + TypeTag::Struct(Box::new(StructTag { + address: TOKEN_ADDRESS, + module: ident_str!("token_event_store").to_owned(), + name: ident_str!("CollectionUriMutate").to_owned(), + type_args: vec![], + })) +}); diff --git a/types/src/account_config/events/collection_uri_mutate_event.rs b/types/src/account_config/events/collection_uri_mutate_event.rs new file mode 100644 index 0000000000000..1de06ce4946c6 --- /dev/null +++ b/types/src/account_config/events/collection_uri_mutate_event.rs @@ -0,0 +1,74 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use crate::move_utils::move_event_v1::MoveEventV1Type; +use anyhow::Result; +use move_core_types::{ + account_address::AccountAddress, + ident_str, + identifier::IdentStr, + language_storage::{StructTag, TypeTag, TOKEN_ADDRESS}, + move_resource::MoveStructType, +}; +use once_cell::sync::Lazy; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Deserialize, Serialize)] +pub struct CollectionUriMutateEvent { + creator_addr: AccountAddress, + collection_name: String, + old_uri: String, + new_uri: String, +} + +impl CollectionUriMutateEvent { + pub fn new( + creator_addr: AccountAddress, + collection_name: String, + old_uri: String, + new_uri: String, + ) -> Self { + Self { + creator_addr, + collection_name, + old_uri, + new_uri, + } + } + + pub fn try_from_bytes(bytes: &[u8]) -> Result { + bcs::from_bytes(bytes).map_err(Into::into) + } + + pub fn creator_addr(&self) -> &AccountAddress { + &self.creator_addr + } + + pub fn collection_name(&self) -> &String { + &self.collection_name + } + + pub fn old_uri(&self) -> &String { + &self.old_uri + } + + pub fn new_uri(&self) -> &String { + &self.new_uri + } +} + +impl MoveStructType for CollectionUriMutateEvent { + const MODULE_NAME: &'static IdentStr = ident_str!("token_event_store"); + const STRUCT_NAME: &'static IdentStr = ident_str!("CollectionUriMutateEvent"); +} + +impl MoveEventV1Type for CollectionUriMutateEvent {} + +pub static COLLECTION_URI_MUTATE_EVENT_TYPE: Lazy = Lazy::new(|| { + TypeTag::Struct(Box::new(StructTag { + address: TOKEN_ADDRESS, + module: ident_str!("token_event_store").to_owned(), + name: ident_str!("CollectionUriMutateEvent").to_owned(), + type_args: vec![], + })) +}); diff --git a/types/src/account_config/events/create_collection.rs b/types/src/account_config/events/create_collection.rs new file mode 100644 index 0000000000000..89ebe3e41da4d --- /dev/null +++ b/types/src/account_config/events/create_collection.rs @@ -0,0 +1,81 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use crate::move_utils::move_event_v2::MoveEventV2Type; +use anyhow::Result; +use move_core_types::{ + account_address::AccountAddress, + ident_str, + identifier::IdentStr, + language_storage::{StructTag, TypeTag, TOKEN_ADDRESS}, + move_resource::MoveStructType, +}; +use once_cell::sync::Lazy; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Deserialize, Serialize)] +pub struct CreateCollection { + creator: AccountAddress, + collection_name: String, + uri: String, + description: String, + maximum: u64, +} + +impl CreateCollection { + pub fn new( + creator: AccountAddress, + collection_name: String, + uri: String, + description: String, + maximum: u64, + ) -> Self { + Self { + creator, + collection_name, + uri, + description, + maximum, + } + } + + pub fn try_from_bytes(bytes: &[u8]) -> Result { + bcs::from_bytes(bytes).map_err(Into::into) + } + + pub fn creator(&self) -> &AccountAddress { + &self.creator + } + + pub fn collection_name(&self) -> &String { + &self.collection_name + } + + pub fn uri(&self) -> &String { + &self.uri + } + + pub fn description(&self) -> &String { + &self.description + } + + pub fn maximum(&self) -> u64 { + self.maximum + } +} + +impl MoveStructType for CreateCollection { + const MODULE_NAME: &'static IdentStr = ident_str!("token"); + const STRUCT_NAME: &'static IdentStr = ident_str!("CreateCollection"); +} + +impl MoveEventV2Type for CreateCollection {} + +pub static CREATE_COLLECTION_TYPE: Lazy = Lazy::new(|| { + TypeTag::Struct(Box::new(StructTag { + address: TOKEN_ADDRESS, + module: ident_str!("token").to_owned(), + name: ident_str!("CreateCollection").to_owned(), + type_args: vec![], + })) +}); diff --git a/types/src/account_config/events/create_collection_event.rs b/types/src/account_config/events/create_collection_event.rs new file mode 100644 index 0000000000000..a2bae7788cb57 --- /dev/null +++ b/types/src/account_config/events/create_collection_event.rs @@ -0,0 +1,81 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use crate::move_utils::move_event_v1::MoveEventV1Type; +use anyhow::Result; +use move_core_types::{ + account_address::AccountAddress, + ident_str, + identifier::IdentStr, + language_storage::{StructTag, TypeTag, TOKEN_ADDRESS}, + move_resource::MoveStructType, +}; +use once_cell::sync::Lazy; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Deserialize, Serialize)] +pub struct CreateCollectionEvent { + creator: AccountAddress, + collection_name: String, + uri: String, + description: String, + maximum: u64, +} + +impl CreateCollectionEvent { + pub fn new( + creator: AccountAddress, + collection_name: String, + uri: String, + description: String, + maximum: u64, + ) -> Self { + Self { + creator, + collection_name, + uri, + description, + maximum, + } + } + + pub fn try_from_bytes(bytes: &[u8]) -> Result { + bcs::from_bytes(bytes).map_err(Into::into) + } + + pub fn creator(&self) -> &AccountAddress { + &self.creator + } + + pub fn collection_name(&self) -> &String { + &self.collection_name + } + + pub fn uri(&self) -> &String { + &self.uri + } + + pub fn description(&self) -> &String { + &self.description + } + + pub fn maximum(&self) -> u64 { + self.maximum + } +} + +impl MoveStructType for CreateCollectionEvent { + const MODULE_NAME: &'static IdentStr = ident_str!("token"); + const STRUCT_NAME: &'static IdentStr = ident_str!("CreateCollectionEvent"); +} + +impl MoveEventV1Type for CreateCollectionEvent {} + +pub static CREATE_COLLECTION_EVENT_TYPE: Lazy = Lazy::new(|| { + TypeTag::Struct(Box::new(StructTag { + address: TOKEN_ADDRESS, + module: ident_str!("token").to_owned(), + name: ident_str!("CreateCollectionEvent").to_owned(), + type_args: vec![], + })) +}); diff --git a/types/src/account_config/events/create_token_data_event.rs b/types/src/account_config/events/create_token_data_event.rs new file mode 100644 index 0000000000000..2ed40791fd34c --- /dev/null +++ b/types/src/account_config/events/create_token_data_event.rs @@ -0,0 +1,133 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use crate::{ + account_config::{TokenDataId, TokenMutabilityConfig}, + move_utils::move_event_v1::MoveEventV1Type, +}; +use anyhow::Result; +use move_core_types::{ + account_address::AccountAddress, + ident_str, + identifier::IdentStr, + language_storage::{StructTag, TypeTag, TOKEN_ADDRESS}, + move_resource::MoveStructType, +}; +use once_cell::sync::Lazy; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Deserialize, Serialize)] +pub struct CreateTokenDataEvent { + id: TokenDataId, + description: String, + maximum: u64, + uri: String, + royalty_payee_address: AccountAddress, + royalty_points_denominator: u64, + royalty_points_numerator: u64, + name: String, + mutability_config: TokenMutabilityConfig, + property_keys: Vec, + property_values: Vec>, + property_types: Vec, +} + +impl CreateTokenDataEvent { + pub fn new( + id: TokenDataId, + description: String, + maximum: u64, + uri: String, + royalty_payee_address: AccountAddress, + royalty_points_denominator: u64, + royalty_points_numerator: u64, + name: String, + mutability_config: TokenMutabilityConfig, + property_keys: Vec, + property_values: Vec>, + property_types: Vec, + ) -> Self { + Self { + id, + description, + maximum, + uri, + royalty_payee_address, + royalty_points_denominator, + royalty_points_numerator, + name, + mutability_config, + property_keys, + property_values, + property_types, + } + } + + pub fn try_from_bytes(bytes: &[u8]) -> Result { + bcs::from_bytes(bytes).map_err(Into::into) + } + + pub fn id(&self) -> &TokenDataId { + &self.id + } + + pub fn description(&self) -> &String { + &self.description + } + + pub fn maximum(&self) -> u64 { + self.maximum + } + + pub fn uri(&self) -> &String { + &self.uri + } + + pub fn royalty_payee_address(&self) -> &AccountAddress { + &self.royalty_payee_address + } + + pub fn royalty_points_denominator(&self) -> u64 { + self.royalty_points_denominator + } + + pub fn royalty_points_numerator(&self) -> u64 { + self.royalty_points_numerator + } + + pub fn name(&self) -> &String { + &self.name + } + + pub fn mutability_config(&self) -> &TokenMutabilityConfig { + &self.mutability_config + } + + pub fn property_keys(&self) -> &Vec { + &self.property_keys + } + + pub fn property_values(&self) -> &Vec> { + &self.property_values + } + + pub fn property_types(&self) -> &Vec { + &self.property_types + } +} + +impl MoveStructType for CreateTokenDataEvent { + const MODULE_NAME: &'static IdentStr = ident_str!("token"); + const STRUCT_NAME: &'static IdentStr = ident_str!("CreateTokenDataEvent"); +} + +impl MoveEventV1Type for CreateTokenDataEvent {} + +pub static CREATE_TOKEN_DATA_EVENT_TYPE: Lazy = Lazy::new(|| { + TypeTag::Struct(Box::new(StructTag { + address: TOKEN_ADDRESS, + module: ident_str!("token").to_owned(), + name: ident_str!("CreateTokenDataEvent").to_owned(), + type_args: vec![], + })) +}); diff --git a/types/src/account_config/events/default_property_mutate.rs b/types/src/account_config/events/default_property_mutate.rs new file mode 100644 index 0000000000000..16bb46299a089 --- /dev/null +++ b/types/src/account_config/events/default_property_mutate.rs @@ -0,0 +1,99 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use crate::move_utils::move_event_v2::MoveEventV2Type; +use anyhow::Result; +use move_core_types::{ + account_address::AccountAddress, + ident_str, + identifier::IdentStr, + language_storage::{StructTag, TypeTag, TOKEN_ADDRESS}, + move_resource::MoveStructType, +}; +use once_cell::sync::Lazy; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Deserialize, Serialize)] +pub struct DefaultPropertyMutate { + creator: AccountAddress, + collection: String, + token: String, + keys: Vec, + old_values: Vec>, + new_values: Vec, +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct OptionType { + vec: Vec, +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct PropertyValue { + value: Vec, + typ: String, +} + +impl DefaultPropertyMutate { + pub fn new( + creator: AccountAddress, + collection: String, + token: String, + keys: Vec, + old_values: Vec>, + new_values: Vec, + ) -> Self { + Self { + creator, + collection, + token, + keys, + old_values, + new_values, + } + } + + pub fn try_from_bytes(bytes: &[u8]) -> Result { + bcs::from_bytes(bytes).map_err(Into::into) + } + + pub fn creator(&self) -> &AccountAddress { + &self.creator + } + + pub fn collection(&self) -> &String { + &self.collection + } + + pub fn token(&self) -> &String { + &self.token + } + + pub fn keys(&self) -> &Vec { + &self.keys + } + + pub fn old_values(&self) -> &Vec> { + &self.old_values + } + + pub fn new_values(&self) -> &Vec { + &self.new_values + } +} + +impl MoveStructType for DefaultPropertyMutate { + const MODULE_NAME: &'static IdentStr = ident_str!("token_event_store"); + const STRUCT_NAME: &'static IdentStr = ident_str!("DefaultPropertyMutate"); +} + +impl MoveEventV2Type for DefaultPropertyMutate {} + +pub static DEFAULT_PROPERTY_MUTATE_TYPE: Lazy = Lazy::new(|| { + TypeTag::Struct(Box::new(StructTag { + address: TOKEN_ADDRESS, + module: ident_str!("token_event_store").to_owned(), + name: ident_str!("DefaultPropertyMutate").to_owned(), + type_args: vec![], + })) +}); diff --git a/types/src/account_config/events/default_property_mutate_event.rs b/types/src/account_config/events/default_property_mutate_event.rs new file mode 100644 index 0000000000000..0e430bebad274 --- /dev/null +++ b/types/src/account_config/events/default_property_mutate_event.rs @@ -0,0 +1,91 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use crate::{ + account_config::{OptionType, PropertyValue}, + move_utils::move_event_v1::MoveEventV1Type, +}; +use anyhow::Result; +use move_core_types::{ + account_address::AccountAddress, + ident_str, + identifier::IdentStr, + language_storage::{StructTag, TypeTag, TOKEN_ADDRESS}, + move_resource::MoveStructType, +}; +use once_cell::sync::Lazy; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Deserialize, Serialize)] +pub struct DefaultPropertyMutateEvent { + creator: AccountAddress, + collection: String, + token: String, + keys: Vec, + old_values: Vec>, + new_values: Vec, +} + +impl DefaultPropertyMutateEvent { + pub fn new( + creator: AccountAddress, + collection: String, + token: String, + keys: Vec, + old_values: Vec>, + new_values: Vec, + ) -> Self { + Self { + creator, + collection, + token, + keys, + old_values, + new_values, + } + } + + pub fn try_from_bytes(bytes: &[u8]) -> Result { + bcs::from_bytes(bytes).map_err(Into::into) + } + + pub fn creator(&self) -> &AccountAddress { + &self.creator + } + + pub fn collection(&self) -> &String { + &self.collection + } + + pub fn token(&self) -> &String { + &self.token + } + + pub fn keys(&self) -> &Vec { + &self.keys + } + + pub fn old_values(&self) -> &Vec> { + &self.old_values + } + + pub fn new_values(&self) -> &Vec { + &self.new_values + } +} + +impl MoveStructType for DefaultPropertyMutateEvent { + const MODULE_NAME: &'static IdentStr = ident_str!("token_event_store"); + const STRUCT_NAME: &'static IdentStr = ident_str!("DefaultPropertyMutateEvent"); +} + +impl MoveEventV1Type for DefaultPropertyMutateEvent {} + +pub static DEFAULT_PROPERTY_MUTATE_EVENT_TYPE: Lazy = Lazy::new(|| { + TypeTag::Struct(Box::new(StructTag { + address: TOKEN_ADDRESS, + module: ident_str!("token_event_store").to_owned(), + name: ident_str!("DefaultPropertyMutateEvent").to_owned(), + type_args: vec![], + })) +}); diff --git a/types/src/account_config/events/deposit_event.rs b/types/src/account_config/events/deposit_event.rs new file mode 100644 index 0000000000000..925a534fc9c3e --- /dev/null +++ b/types/src/account_config/events/deposit_event.rs @@ -0,0 +1,49 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use crate::move_utils::move_event_v1::MoveEventV1Type; +use anyhow::Result; +use move_core_types::{ + ident_str, + identifier::IdentStr, + language_storage::{StructTag, TypeTag, CORE_CODE_ADDRESS}, + move_resource::MoveStructType, +}; +use once_cell::sync::Lazy; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize)] +pub struct DepositEvent { + amount: u64, +} + +impl DepositEvent { + pub fn new(amount: u64) -> Self { + Self { amount } + } + + pub fn try_from_bytes(bytes: &[u8]) -> Result { + bcs::from_bytes(bytes).map_err(Into::into) + } + + /// Get the amount sent or received + pub fn amount(&self) -> u64 { + self.amount + } +} + +impl MoveStructType for DepositEvent { + const MODULE_NAME: &'static IdentStr = ident_str!("coin"); + const STRUCT_NAME: &'static IdentStr = ident_str!("DepositEvent"); +} + +impl MoveEventV1Type for DepositEvent {} + +pub static DEPOSIT_EVENT_TYPE: Lazy = Lazy::new(|| { + TypeTag::Struct(Box::new(StructTag { + address: CORE_CODE_ADDRESS, + module: ident_str!("coin").to_owned(), + name: ident_str!("DepositEvent").to_owned(), + type_args: vec![], + })) +}); diff --git a/types/src/account_config/events/description_mutate.rs b/types/src/account_config/events/description_mutate.rs new file mode 100644 index 0000000000000..a618a4576e00a --- /dev/null +++ b/types/src/account_config/events/description_mutate.rs @@ -0,0 +1,81 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use crate::move_utils::move_event_v2::MoveEventV2Type; +use anyhow::Result; +use move_core_types::{ + account_address::AccountAddress, + ident_str, + identifier::IdentStr, + language_storage::{StructTag, TypeTag, TOKEN_ADDRESS}, + move_resource::MoveStructType, +}; +use once_cell::sync::Lazy; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Deserialize, Serialize)] +pub struct DescriptionMutate { + creator: AccountAddress, + collection: String, + token: String, + old_description: String, + new_description: String, +} + +impl DescriptionMutate { + pub fn new( + creator: AccountAddress, + collection: String, + token: String, + old_description: String, + new_description: String, + ) -> Self { + Self { + creator, + collection, + token, + old_description, + new_description, + } + } + + pub fn try_from_bytes(bytes: &[u8]) -> Result { + bcs::from_bytes(bytes).map_err(Into::into) + } + + pub fn creator(&self) -> &AccountAddress { + &self.creator + } + + pub fn collection(&self) -> &String { + &self.collection + } + + pub fn token(&self) -> &String { + &self.token + } + + pub fn old_description(&self) -> &String { + &self.old_description + } + + pub fn new_description(&self) -> &String { + &self.new_description + } +} + +impl MoveStructType for DescriptionMutate { + const MODULE_NAME: &'static IdentStr = ident_str!("token_event_store"); + const STRUCT_NAME: &'static IdentStr = ident_str!("DescriptionMutate"); +} + +impl MoveEventV2Type for DescriptionMutate {} + +pub static DESCRIPTION_MUTATE_TYPE: Lazy = Lazy::new(|| { + TypeTag::Struct(Box::new(StructTag { + address: TOKEN_ADDRESS, + module: ident_str!("token_event_store").to_owned(), + name: ident_str!("DescriptionMutate").to_owned(), + type_args: vec![], + })) +}); diff --git a/types/src/account_config/events/description_mutate_event.rs b/types/src/account_config/events/description_mutate_event.rs new file mode 100644 index 0000000000000..c984a0df37c00 --- /dev/null +++ b/types/src/account_config/events/description_mutate_event.rs @@ -0,0 +1,81 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use crate::move_utils::move_event_v1::MoveEventV1Type; +use anyhow::Result; +use move_core_types::{ + account_address::AccountAddress, + ident_str, + identifier::IdentStr, + language_storage::{StructTag, TypeTag, TOKEN_ADDRESS}, + move_resource::MoveStructType, +}; +use once_cell::sync::Lazy; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Deserialize, Serialize)] +pub struct DescriptionMutateEvent { + creator: AccountAddress, + collection: String, + token: String, + old_description: String, + new_description: String, +} + +impl DescriptionMutateEvent { + pub fn new( + creator: AccountAddress, + collection: String, + token: String, + old_description: String, + new_description: String, + ) -> Self { + Self { + creator, + collection, + token, + old_description, + new_description, + } + } + + pub fn try_from_bytes(bytes: &[u8]) -> Result { + bcs::from_bytes(bytes).map_err(Into::into) + } + + pub fn creator(&self) -> &AccountAddress { + &self.creator + } + + pub fn collection(&self) -> &String { + &self.collection + } + + pub fn token(&self) -> &String { + &self.token + } + + pub fn old_description(&self) -> &String { + &self.old_description + } + + pub fn new_description(&self) -> &String { + &self.new_description + } +} + +impl MoveStructType for DescriptionMutateEvent { + const MODULE_NAME: &'static IdentStr = ident_str!("token_event_store"); + const STRUCT_NAME: &'static IdentStr = ident_str!("DescriptionMutateEvent"); +} + +impl MoveEventV1Type for DescriptionMutateEvent {} + +pub static DESCRIPTION_MUTATE_EVENT_TYPE: Lazy = Lazy::new(|| { + TypeTag::Struct(Box::new(StructTag { + address: TOKEN_ADDRESS, + module: ident_str!("token_event_store").to_owned(), + name: ident_str!("DescriptionMutateEvent").to_owned(), + type_args: vec![], + })) +}); diff --git a/types/src/account_config/events/key_rotation.rs b/types/src/account_config/events/key_rotation.rs new file mode 100644 index 0000000000000..c2b24c4564e1e --- /dev/null +++ b/types/src/account_config/events/key_rotation.rs @@ -0,0 +1,55 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use crate::move_utils::move_event_v2::MoveEventV2Type; +use anyhow::Result; +use move_core_types::{ + account_address::AccountAddress, + ident_str, + identifier::IdentStr, + language_storage::{StructTag, TypeTag, CORE_CODE_ADDRESS}, + move_resource::MoveStructType, +}; +use once_cell::sync::Lazy; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize)] +pub struct KeyRotation { + account: AccountAddress, + old_authentication_key: Vec, + new_authentication_key: Vec, +} + +impl KeyRotation { + pub fn try_from_bytes(bytes: &[u8]) -> Result { + bcs::from_bytes(bytes).map_err(Into::into) + } + + pub fn account(&self) -> &AccountAddress { + &self.account + } + + pub fn old_authentication_key(&self) -> &Vec { + &self.old_authentication_key + } + + pub fn new_authentication_key(&self) -> &Vec { + &self.new_authentication_key + } +} + +impl MoveStructType for KeyRotation { + const MODULE_NAME: &'static IdentStr = ident_str!("account"); + const STRUCT_NAME: &'static IdentStr = ident_str!("KeyRotation"); +} + +impl MoveEventV2Type for KeyRotation {} + +pub static KEY_ROTATION_TYPE: Lazy = Lazy::new(|| { + TypeTag::Struct(Box::new(StructTag { + address: CORE_CODE_ADDRESS, + module: ident_str!("account").to_owned(), + name: ident_str!("KeyRotation").to_owned(), + type_args: vec![], + })) +}); diff --git a/types/src/account_config/events/key_rotation_event.rs b/types/src/account_config/events/key_rotation_event.rs new file mode 100644 index 0000000000000..f9c80ccee5ab2 --- /dev/null +++ b/types/src/account_config/events/key_rotation_event.rs @@ -0,0 +1,56 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use crate::move_utils::move_event_v1::MoveEventV1Type; +use anyhow::Result; +use move_core_types::{ + ident_str, + identifier::IdentStr, + language_storage::{StructTag, TypeTag, CORE_CODE_ADDRESS}, + move_resource::MoveStructType, +}; +use once_cell::sync::Lazy; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize)] +pub struct KeyRotationEvent { + old_authentication_key: Vec, + new_authentication_key: Vec, +} + +impl KeyRotationEvent { + pub fn new(old_authentication_key: Vec, new_authentication_key: Vec) -> Self { + Self { + old_authentication_key, + new_authentication_key, + } + } + + pub fn try_from_bytes(bytes: &[u8]) -> Result { + bcs::from_bytes(bytes).map_err(Into::into) + } + + pub fn old_authentication_key(&self) -> &Vec { + &self.old_authentication_key + } + + pub fn new_authentication_key(&self) -> &Vec { + &self.new_authentication_key + } +} + +impl MoveStructType for KeyRotationEvent { + const MODULE_NAME: &'static IdentStr = ident_str!("account"); + const STRUCT_NAME: &'static IdentStr = ident_str!("KeyRotationEvent"); +} + +impl MoveEventV1Type for KeyRotationEvent {} + +pub static KEY_ROTATION_EVENT_TYPE: Lazy = Lazy::new(|| { + TypeTag::Struct(Box::new(StructTag { + address: CORE_CODE_ADDRESS, + module: ident_str!("account").to_owned(), + name: ident_str!("KeyRotationEvent").to_owned(), + type_args: vec![], + })) +}); diff --git a/types/src/account_config/events/maximum_mutate.rs b/types/src/account_config/events/maximum_mutate.rs new file mode 100644 index 0000000000000..aba5ea32c8632 --- /dev/null +++ b/types/src/account_config/events/maximum_mutate.rs @@ -0,0 +1,81 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use crate::move_utils::move_event_v2::MoveEventV2Type; +use anyhow::Result; +use move_core_types::{ + account_address::AccountAddress, + ident_str, + identifier::IdentStr, + language_storage::{StructTag, TypeTag, TOKEN_ADDRESS}, + move_resource::MoveStructType, +}; +use once_cell::sync::Lazy; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Deserialize, Serialize)] +pub struct MaximumMutate { + creator: AccountAddress, + collection: String, + token: String, + old_maximum: u64, + new_maximum: u64, +} + +impl MaximumMutate { + pub fn new( + creator: AccountAddress, + collection: String, + token: String, + old_maximum: u64, + new_maximum: u64, + ) -> Self { + Self { + creator, + collection, + token, + old_maximum, + new_maximum, + } + } + + pub fn try_from_bytes(bytes: &[u8]) -> Result { + bcs::from_bytes(bytes).map_err(Into::into) + } + + pub fn creator(&self) -> &AccountAddress { + &self.creator + } + + pub fn collection(&self) -> &String { + &self.collection + } + + pub fn token(&self) -> &String { + &self.token + } + + pub fn old_maximum(&self) -> &u64 { + &self.old_maximum + } + + pub fn new_maximum(&self) -> &u64 { + &self.new_maximum + } +} + +impl MoveStructType for MaximumMutate { + const MODULE_NAME: &'static IdentStr = ident_str!("token_event_store"); + const STRUCT_NAME: &'static IdentStr = ident_str!("MaximumMutate"); +} + +impl MoveEventV2Type for MaximumMutate {} + +pub static MAXIMUM_MUTATE_TYPE: Lazy = Lazy::new(|| { + TypeTag::Struct(Box::new(StructTag { + address: TOKEN_ADDRESS, + module: ident_str!("token_event_store").to_owned(), + name: ident_str!("MaximumMutate").to_owned(), + type_args: vec![], + })) +}); diff --git a/types/src/account_config/events/maximum_mutate_event.rs b/types/src/account_config/events/maximum_mutate_event.rs new file mode 100644 index 0000000000000..5774e13a897b8 --- /dev/null +++ b/types/src/account_config/events/maximum_mutate_event.rs @@ -0,0 +1,83 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use crate::move_utils::move_event_v1::MoveEventV1Type; +use anyhow::Result; +use move_core_types::{ + account_address::AccountAddress, + ident_str, + identifier::IdentStr, + language_storage::{StructTag, TypeTag, TOKEN_ADDRESS}, + move_resource::MoveStructType, +}; +use once_cell::sync::Lazy; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Deserialize, Serialize)] +pub struct MaximumMutateEvent { + creator: AccountAddress, + collection: String, + token: String, + old_maximum: u64, + new_maximum: u64, +} + +impl MaximumMutateEvent { + pub fn new( + creator: AccountAddress, + collection: String, + token: String, + old_maximum: u64, + new_maximum: u64, + ) -> Self { + Self { + creator, + collection, + token, + old_maximum, + new_maximum, + } + } + + pub fn try_from_bytes(bytes: &[u8]) -> Result { + bcs::from_bytes(bytes).map_err(Into::into) + } + + pub fn creator(&self) -> &AccountAddress { + &self.creator + } + + pub fn collection(&self) -> &String { + &self.collection + } + + pub fn token(&self) -> &String { + &self.token + } + + pub fn old_maximum(&self) -> &u64 { + &self.old_maximum + } + + pub fn new_maximum(&self) -> &u64 { + &self.new_maximum + } +} + +impl MoveStructType for MaximumMutateEvent { + const MODULE_NAME: &'static IdentStr = ident_str!("token_event_store"); + // The struct name in the Move code contains a typo. + const STRUCT_NAME: &'static IdentStr = ident_str!("MaxiumMutateEvent"); +} + +impl MoveEventV1Type for MaximumMutateEvent {} + +pub static MAXIMUM_MUTATE_EVENT_TYPE: Lazy = Lazy::new(|| { + TypeTag::Struct(Box::new(StructTag { + address: TOKEN_ADDRESS, + module: ident_str!("token_event_store").to_owned(), + // The struct name in the Move code contains a typo. + name: ident_str!("MaxiumMutateEvent").to_owned(), + type_args: vec![], + })) +}); diff --git a/types/src/account_config/events/mint.rs b/types/src/account_config/events/mint.rs new file mode 100644 index 0000000000000..e8defcf73f28c --- /dev/null +++ b/types/src/account_config/events/mint.rs @@ -0,0 +1,69 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use crate::{ + account_config::aggregator::AggregatorSnapshotResource, + move_utils::move_event_v2::MoveEventV2Type, +}; +use move_core_types::{ + account_address::AccountAddress, + ident_str, + identifier::IdentStr, + language_storage::{StructTag, TypeTag, TOKEN_OBJECTS_ADDRESS}, + move_resource::MoveStructType, +}; +use once_cell::sync::Lazy; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize)] +pub struct Mint { + collection: AccountAddress, + index: AggregatorSnapshotResource, + token: AccountAddress, +} + +impl Mint { + pub fn new( + collection: AccountAddress, + index: AggregatorSnapshotResource, + token: AccountAddress, + ) -> Self { + Self { + collection, + index, + token, + } + } + + pub fn try_from_bytes(bytes: &[u8]) -> anyhow::Result { + bcs::from_bytes(bytes).map_err(Into::into) + } + + pub fn collection(&self) -> &AccountAddress { + &self.collection + } + + pub fn index(&self) -> &AggregatorSnapshotResource { + &self.index + } + + pub fn token(&self) -> &AccountAddress { + &self.token + } +} + +impl MoveStructType for Mint { + const MODULE_NAME: &'static IdentStr = ident_str!("collection"); + const STRUCT_NAME: &'static IdentStr = ident_str!("Mint"); +} + +impl MoveEventV2Type for Mint {} + +pub static MINT_TYPE: Lazy = Lazy::new(|| { + TypeTag::Struct(Box::new(StructTag { + address: TOKEN_OBJECTS_ADDRESS, + module: ident_str!("collection").to_owned(), + name: ident_str!("Mint").to_owned(), + type_args: vec![], + })) +}); diff --git a/types/src/account_config/events/mint_event.rs b/types/src/account_config/events/mint_event.rs new file mode 100644 index 0000000000000..b68209b30f562 --- /dev/null +++ b/types/src/account_config/events/mint_event.rs @@ -0,0 +1,53 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use crate::move_utils::move_event_v1::MoveEventV1Type; +use move_core_types::{ + account_address::AccountAddress, + ident_str, + identifier::IdentStr, + language_storage::{StructTag, TypeTag, TOKEN_OBJECTS_ADDRESS}, + move_resource::MoveStructType, +}; +use once_cell::sync::Lazy; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize)] +pub struct MintEvent { + index: u64, + token: AccountAddress, +} + +impl MintEvent { + pub fn new(index: u64, token: AccountAddress) -> Self { + Self { index, token } + } + + pub fn try_from_bytes(bytes: &[u8]) -> anyhow::Result { + bcs::from_bytes(bytes).map_err(Into::into) + } + + pub fn index(&self) -> &u64 { + &self.index + } + + pub fn token(&self) -> &AccountAddress { + &self.token + } +} + +impl MoveStructType for MintEvent { + const MODULE_NAME: &'static IdentStr = ident_str!("collection"); + const STRUCT_NAME: &'static IdentStr = ident_str!("MintEvent"); +} + +impl MoveEventV1Type for MintEvent {} + +pub static MINT_EVENT_TYPE: Lazy = Lazy::new(|| { + TypeTag::Struct(Box::new(StructTag { + address: TOKEN_OBJECTS_ADDRESS, + module: ident_str!("collection").to_owned(), + name: ident_str!("MintEvent").to_owned(), + type_args: vec![], + })) +}); diff --git a/types/src/account_config/events/mint_token.rs b/types/src/account_config/events/mint_token.rs new file mode 100644 index 0000000000000..835be186d5234 --- /dev/null +++ b/types/src/account_config/events/mint_token.rs @@ -0,0 +1,63 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use crate::{account_config::TokenDataId, move_utils::move_event_v2::MoveEventV2Type}; +use anyhow::Result; +use move_core_types::{ + account_address::AccountAddress, + ident_str, + identifier::IdentStr, + language_storage::{StructTag, TypeTag, TOKEN_ADDRESS}, + move_resource::MoveStructType, +}; +use once_cell::sync::Lazy; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Deserialize, Serialize)] +pub struct MintToken { + creator: AccountAddress, + id: TokenDataId, + amount: u64, +} + +impl MintToken { + pub fn new(creator: AccountAddress, id: TokenDataId, amount: u64) -> Self { + Self { + creator, + id, + amount, + } + } + + pub fn try_from_bytes(bytes: &[u8]) -> Result { + bcs::from_bytes(bytes).map_err(Into::into) + } + + pub fn creator(&self) -> &AccountAddress { + &self.creator + } + + pub fn id(&self) -> &TokenDataId { + &self.id + } + + pub fn amount(&self) -> u64 { + self.amount + } +} + +impl MoveStructType for MintToken { + const MODULE_NAME: &'static IdentStr = ident_str!("token"); + const STRUCT_NAME: &'static IdentStr = ident_str!("Mint"); +} + +impl MoveEventV2Type for MintToken {} + +pub static MINT_TOKEN_TYPE: Lazy = Lazy::new(|| { + TypeTag::Struct(Box::new(StructTag { + address: TOKEN_ADDRESS, + module: ident_str!("token").to_owned(), + name: ident_str!("Mint").to_owned(), + type_args: vec![], + })) +}); diff --git a/types/src/account_config/events/mint_token_event.rs b/types/src/account_config/events/mint_token_event.rs new file mode 100644 index 0000000000000..83dc126908eb0 --- /dev/null +++ b/types/src/account_config/events/mint_token_event.rs @@ -0,0 +1,53 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use crate::{account_config::TokenDataId, move_utils::move_event_v1::MoveEventV1Type}; +use anyhow::Result; +use move_core_types::{ + ident_str, + identifier::IdentStr, + language_storage::{StructTag, TypeTag, TOKEN_ADDRESS}, + move_resource::MoveStructType, +}; +use once_cell::sync::Lazy; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Deserialize, Serialize)] +pub struct MintTokenEvent { + id: TokenDataId, + amount: u64, +} + +impl MintTokenEvent { + pub fn new(id: TokenDataId, amount: u64) -> Self { + Self { id, amount } + } + + pub fn try_from_bytes(bytes: &[u8]) -> Result { + bcs::from_bytes(bytes).map_err(Into::into) + } + + pub fn id(&self) -> &TokenDataId { + &self.id + } + + pub fn amount(&self) -> u64 { + self.amount + } +} + +impl MoveStructType for MintTokenEvent { + const MODULE_NAME: &'static IdentStr = ident_str!("token"); + const STRUCT_NAME: &'static IdentStr = ident_str!("MintTokenEvent"); +} + +impl MoveEventV1Type for MintTokenEvent {} + +pub static MINT_TOKEN_EVENT_TYPE: Lazy = Lazy::new(|| { + TypeTag::Struct(Box::new(StructTag { + address: TOKEN_ADDRESS, + module: ident_str!("token").to_owned(), + name: ident_str!("MintTokenEvent").to_owned(), + type_args: vec![], + })) +}); diff --git a/types/src/account_config/events/mod.rs b/types/src/account_config/events/mod.rs index 83950b07a8774..d350297716b8b 100644 --- a/types/src/account_config/events/mod.rs +++ b/types/src/account_config/events/mod.rs @@ -2,15 +2,125 @@ // Parts of the project are originally copyright © Meta Platforms, Inc. // SPDX-License-Identifier: Apache-2.0 -pub mod coin; +pub mod burn; +pub mod burn_event; +pub mod burn_token; +pub mod burn_token_event; +pub mod cancel_offer; +pub mod claim; +pub mod coin_deposit; +pub mod coin_register; +pub mod coin_register_event; +pub mod coin_withdraw; +pub mod collection_description_mutate; +pub mod collection_description_mutate_event; +pub mod collection_maximum_mutate; +pub mod collection_maximum_mutate_event; +pub mod collection_mutation; +pub mod collection_mutation_event; +pub mod collection_uri_mutate; +pub mod collection_uri_mutate_event; +pub mod create_collection; +pub mod create_collection_event; +pub mod create_token_data_event; +pub mod default_property_mutate; +pub mod default_property_mutate_event; +pub mod deposit_event; +pub mod description_mutate; +pub mod description_mutate_event; pub mod fungible_asset; +pub mod key_rotation; +pub mod key_rotation_event; +pub mod maximum_mutate; +pub mod maximum_mutate_event; +pub mod mint; +pub mod mint_event; +pub mod mint_token; +pub mod mint_token_event; +pub mod mutate_property_map; +pub mod mutate_token_property_map_event; pub mod new_block; pub mod new_epoch; +pub mod offer; +pub mod opt_in_transfer; +pub mod opt_in_transfer_event; +pub mod royalty_mutate; +pub mod royalty_mutate_event; +pub mod token_cancel_offer_event; +pub mod token_claim_event; +pub mod token_data_creation; +pub mod token_deposit; +pub mod token_deposit_event; +pub mod token_mutation; +pub mod token_mutation_event; +pub mod token_offer_event; +pub mod token_withdraw; +pub mod token_withdraw_event; +pub mod transfer; +pub mod transfer_event; +pub mod uri_mutation; +pub mod uri_mutation_event; +pub mod withdraw_event; -pub use coin::*; +pub use burn::*; +pub use burn_event::*; +pub use burn_token::*; +pub use burn_token_event::*; +pub use cancel_offer::*; +pub use claim::*; +pub use coin_deposit::*; +pub use coin_register::*; +pub use coin_register_event::*; +pub use coin_withdraw::*; +pub use collection_description_mutate::*; +pub use collection_description_mutate_event::*; +pub use collection_maximum_mutate::*; +pub use collection_maximum_mutate_event::*; +pub use collection_mutation::*; +pub use collection_mutation_event::*; +pub use collection_uri_mutate::*; +pub use collection_uri_mutate_event::*; +pub use create_collection::*; +pub use create_collection_event::*; +pub use create_token_data_event::*; +pub use default_property_mutate::*; +pub use default_property_mutate_event::*; +pub use deposit_event::*; +pub use description_mutate::*; +pub use description_mutate_event::*; pub use fungible_asset::*; +pub use key_rotation::*; +pub use key_rotation_event::*; +pub use maximum_mutate::*; +pub use maximum_mutate_event::*; +pub use mint::*; +pub use mint_event::*; +pub use mint_token::*; +pub use mint_token_event::*; +pub use mutate_property_map::*; +pub use mutate_token_property_map_event::*; pub use new_block::*; pub use new_epoch::*; +pub use offer::*; +pub use opt_in_transfer::*; +pub use opt_in_transfer_event::*; +pub use royalty_mutate::*; +pub use royalty_mutate_event::*; +pub use token_cancel_offer_event::*; +pub use token_claim_event::*; +pub use token_data_creation::*; +pub use token_deposit::*; +pub use token_deposit_event::*; +pub use token_mutation::*; +pub use token_mutation_event::*; +pub use token_offer_event::*; +pub use token_withdraw::*; +pub use token_withdraw_event::*; +pub use transfer::*; +pub use transfer_event::*; +pub use uri_mutation::*; +pub use uri_mutation_event::*; +pub use withdraw_event::*; pub fn is_aptos_governance_create_proposal_event(event_type: &str) -> bool { event_type == "0x1::aptos_governance::CreateProposal" diff --git a/types/src/account_config/events/mutate_property_map.rs b/types/src/account_config/events/mutate_property_map.rs new file mode 100644 index 0000000000000..5abb900183a21 --- /dev/null +++ b/types/src/account_config/events/mutate_property_map.rs @@ -0,0 +1,88 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use crate::{account_config::TokenId, move_utils::move_event_v2::MoveEventV2Type}; +use anyhow::Result; +use move_core_types::{ + account_address::AccountAddress, + ident_str, + identifier::IdentStr, + language_storage::{StructTag, TypeTag, TOKEN_ADDRESS}, + move_resource::MoveStructType, +}; +use once_cell::sync::Lazy; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Deserialize, Serialize)] +pub struct MutatePropertyMap { + account: AccountAddress, + old_id: TokenId, + new_id: TokenId, + keys: Vec, + values: Vec>, + types: Vec, +} + +impl MutatePropertyMap { + pub fn new( + account: AccountAddress, + old_id: TokenId, + new_id: TokenId, + keys: Vec, + values: Vec>, + types: Vec, + ) -> Self { + Self { + account, + old_id, + new_id, + keys, + values, + types, + } + } + + pub fn try_from_bytes(bytes: &[u8]) -> Result { + bcs::from_bytes(bytes).map_err(Into::into) + } + + pub fn account(&self) -> &AccountAddress { + &self.account + } + + pub fn old_id(&self) -> &TokenId { + &self.old_id + } + + pub fn new_id(&self) -> &TokenId { + &self.new_id + } + + pub fn keys(&self) -> &Vec { + &self.keys + } + + pub fn values(&self) -> &Vec> { + &self.values + } + + pub fn types(&self) -> &Vec { + &self.types + } +} + +impl MoveStructType for MutatePropertyMap { + const MODULE_NAME: &'static IdentStr = ident_str!("token"); + const STRUCT_NAME: &'static IdentStr = ident_str!("MutatePropertyMap"); +} + +impl MoveEventV2Type for MutatePropertyMap {} + +pub static MUTATE_PROPERTY_MAP_TYPE: Lazy = Lazy::new(|| { + TypeTag::Struct(Box::new(StructTag { + address: TOKEN_ADDRESS, + module: ident_str!("token").to_owned(), + name: ident_str!("MutatePropertyMap").to_owned(), + type_args: vec![], + })) +}); diff --git a/types/src/account_config/events/mutate_token_property_map_event.rs b/types/src/account_config/events/mutate_token_property_map_event.rs new file mode 100644 index 0000000000000..e1d6134a477fc --- /dev/null +++ b/types/src/account_config/events/mutate_token_property_map_event.rs @@ -0,0 +1,80 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use crate::{account_config::TokenId, move_utils::move_event_v1::MoveEventV1Type}; +use anyhow::Result; +use move_core_types::{ + ident_str, + identifier::IdentStr, + language_storage::{StructTag, TypeTag, TOKEN_ADDRESS}, + move_resource::MoveStructType, +}; +use once_cell::sync::Lazy; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Deserialize, Serialize)] +pub struct MutateTokenPropertyMapEvent { + old_id: TokenId, + new_id: TokenId, + keys: Vec, + values: Vec>, + types: Vec, +} + +impl MutateTokenPropertyMapEvent { + pub fn new( + old_id: TokenId, + new_id: TokenId, + keys: Vec, + values: Vec>, + types: Vec, + ) -> Self { + Self { + old_id, + new_id, + keys, + values, + types, + } + } + + pub fn try_from_bytes(bytes: &[u8]) -> Result { + bcs::from_bytes(bytes).map_err(Into::into) + } + + pub fn old_id(&self) -> &TokenId { + &self.old_id + } + + pub fn new_id(&self) -> &TokenId { + &self.new_id + } + + pub fn keys(&self) -> &Vec { + &self.keys + } + + pub fn values(&self) -> &Vec> { + &self.values + } + + pub fn types(&self) -> &Vec { + &self.types + } +} + +impl MoveStructType for MutateTokenPropertyMapEvent { + const MODULE_NAME: &'static IdentStr = ident_str!("token"); + const STRUCT_NAME: &'static IdentStr = ident_str!("MutateTokenPropertyMapEvent"); +} + +impl MoveEventV1Type for MutateTokenPropertyMapEvent {} + +pub static MUTATE_TOKEN_PROPERTY_MAP_EVENT_TYPE: Lazy = Lazy::new(|| { + TypeTag::Struct(Box::new(StructTag { + address: TOKEN_ADDRESS, + module: ident_str!("token").to_owned(), + name: ident_str!("MutateTokenPropertyMapEvent").to_owned(), + type_args: vec![], + })) +}); diff --git a/types/src/account_config/events/offer.rs b/types/src/account_config/events/offer.rs new file mode 100644 index 0000000000000..7453a4507c582 --- /dev/null +++ b/types/src/account_config/events/offer.rs @@ -0,0 +1,74 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use crate::{account_config::TokenId, move_utils::move_event_v2::MoveEventV2Type}; +use anyhow::Result; +use move_core_types::{ + account_address::AccountAddress, + ident_str, + identifier::IdentStr, + language_storage::{StructTag, TypeTag, TOKEN_ADDRESS}, + move_resource::MoveStructType, +}; +use once_cell::sync::Lazy; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Deserialize, Serialize)] +pub struct Offer { + account: AccountAddress, + to_address: AccountAddress, + token_id: TokenId, + amount: u64, +} + +impl Offer { + pub fn new( + account: AccountAddress, + to_address: AccountAddress, + token_id: TokenId, + amount: u64, + ) -> Self { + Self { + account, + to_address, + token_id, + amount, + } + } + + pub fn try_from_bytes(bytes: &[u8]) -> Result { + bcs::from_bytes(bytes).map_err(Into::into) + } + + pub fn account(&self) -> &AccountAddress { + &self.account + } + + pub fn to_address(&self) -> &AccountAddress { + &self.to_address + } + + pub fn token_id(&self) -> &TokenId { + &self.token_id + } + + pub fn amount(&self) -> u64 { + self.amount + } +} + +impl MoveStructType for Offer { + const MODULE_NAME: &'static IdentStr = ident_str!("token_transfers"); + const STRUCT_NAME: &'static IdentStr = ident_str!("Offer"); +} + +impl MoveEventV2Type for Offer {} + +pub static OFFER_TYPE: Lazy = Lazy::new(|| { + TypeTag::Struct(Box::new(StructTag { + address: TOKEN_ADDRESS, + module: ident_str!("token_transfers").to_owned(), + name: ident_str!("Offer").to_owned(), + type_args: vec![], + })) +}); diff --git a/types/src/account_config/events/opt_in_transfer.rs b/types/src/account_config/events/opt_in_transfer.rs new file mode 100644 index 0000000000000..1c6bcd0834755 --- /dev/null +++ b/types/src/account_config/events/opt_in_transfer.rs @@ -0,0 +1,57 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use crate::move_utils::move_event_v2::MoveEventV2Type; +use anyhow::Result; +use move_core_types::{ + account_address::AccountAddress, + ident_str, + identifier::IdentStr, + language_storage::{StructTag, TypeTag, TOKEN_ADDRESS}, + move_resource::MoveStructType, +}; +use once_cell::sync::Lazy; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Deserialize, Serialize)] +pub struct OptInTransfer { + account_address: AccountAddress, + opt_in: bool, +} + +impl OptInTransfer { + pub fn new(account_address: AccountAddress, opt_in: bool) -> Self { + Self { + account_address, + opt_in, + } + } + + pub fn try_from_bytes(bytes: &[u8]) -> Result { + bcs::from_bytes(bytes).map_err(Into::into) + } + + pub fn account_address(&self) -> &AccountAddress { + &self.account_address + } + + pub fn opt_in(&self) -> &bool { + &self.opt_in + } +} + +impl MoveStructType for OptInTransfer { + const MODULE_NAME: &'static IdentStr = ident_str!("token_event_store"); + const STRUCT_NAME: &'static IdentStr = ident_str!("OptInTransfer"); +} + +impl MoveEventV2Type for OptInTransfer {} + +pub static OPT_IN_TRANSFER_TYPE: Lazy = Lazy::new(|| { + TypeTag::Struct(Box::new(StructTag { + address: TOKEN_ADDRESS, + module: ident_str!("token_event_store").to_owned(), + name: ident_str!("OptInTransfer").to_owned(), + type_args: vec![], + })) +}); diff --git a/types/src/account_config/events/opt_in_transfer_event.rs b/types/src/account_config/events/opt_in_transfer_event.rs new file mode 100644 index 0000000000000..06156b8eafc71 --- /dev/null +++ b/types/src/account_config/events/opt_in_transfer_event.rs @@ -0,0 +1,48 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use crate::move_utils::move_event_v1::MoveEventV1Type; +use anyhow::Result; +use move_core_types::{ + ident_str, + identifier::IdentStr, + language_storage::{StructTag, TypeTag, TOKEN_ADDRESS}, + move_resource::MoveStructType, +}; +use once_cell::sync::Lazy; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Deserialize, Serialize)] +pub struct OptInTransferEvent { + opt_in: bool, +} + +impl OptInTransferEvent { + pub fn new(opt_in: bool) -> Self { + Self { opt_in } + } + + pub fn try_from_bytes(bytes: &[u8]) -> Result { + bcs::from_bytes(bytes).map_err(Into::into) + } + + pub fn opt_in(&self) -> &bool { + &self.opt_in + } +} + +impl MoveStructType for OptInTransferEvent { + const MODULE_NAME: &'static IdentStr = ident_str!("token_event_store"); + const STRUCT_NAME: &'static IdentStr = ident_str!("OptInTransferEvent"); +} + +impl MoveEventV1Type for OptInTransferEvent {} + +pub static OPT_IN_TRANSFER_EVENT_TYPE: Lazy = Lazy::new(|| { + TypeTag::Struct(Box::new(StructTag { + address: TOKEN_ADDRESS, + module: ident_str!("token_event_store").to_owned(), + name: ident_str!("OptInTransferEvent").to_owned(), + type_args: vec![], + })) +}); diff --git a/types/src/account_config/events/royalty_mutate.rs b/types/src/account_config/events/royalty_mutate.rs new file mode 100644 index 0000000000000..813abc5978e11 --- /dev/null +++ b/types/src/account_config/events/royalty_mutate.rs @@ -0,0 +1,109 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use crate::move_utils::move_event_v2::MoveEventV2Type; +use anyhow::Result; +use move_core_types::{ + account_address::AccountAddress, + ident_str, + identifier::IdentStr, + language_storage::{StructTag, TypeTag, TOKEN_ADDRESS}, + move_resource::MoveStructType, +}; +use once_cell::sync::Lazy; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Deserialize, Serialize)] +pub struct RoyaltyMutate { + creator: AccountAddress, + collection: String, + token: String, + old_royalty_numerator: u64, + old_royalty_denominator: u64, + old_royalty_payee_addr: AccountAddress, + new_royalty_numerator: u64, + new_royalty_denominator: u64, + new_royalty_payee_addr: AccountAddress, +} + +impl RoyaltyMutate { + pub fn new( + creator: AccountAddress, + collection: String, + token: String, + old_royalty_numerator: u64, + old_royalty_denominator: u64, + old_royalty_payee_addr: AccountAddress, + new_royalty_numerator: u64, + new_royalty_denominator: u64, + new_royalty_payee_addr: AccountAddress, + ) -> Self { + Self { + creator, + collection, + token, + old_royalty_numerator, + old_royalty_denominator, + old_royalty_payee_addr, + new_royalty_numerator, + new_royalty_denominator, + new_royalty_payee_addr, + } + } + + pub fn try_from_bytes(bytes: &[u8]) -> Result { + bcs::from_bytes(bytes).map_err(Into::into) + } + + pub fn creator(&self) -> &AccountAddress { + &self.creator + } + + pub fn collection(&self) -> &String { + &self.collection + } + + pub fn token(&self) -> &String { + &self.token + } + + pub fn old_royalty_numerator(&self) -> &u64 { + &self.old_royalty_numerator + } + + pub fn old_royalty_denominator(&self) -> &u64 { + &self.old_royalty_denominator + } + + pub fn old_royalty_payee_addr(&self) -> &AccountAddress { + &self.old_royalty_payee_addr + } + + pub fn new_royalty_numerator(&self) -> &u64 { + &self.new_royalty_numerator + } + + pub fn new_royalty_denominator(&self) -> &u64 { + &self.new_royalty_denominator + } + + pub fn new_royalty_payee_addr(&self) -> &AccountAddress { + &self.new_royalty_payee_addr + } +} + +impl MoveStructType for RoyaltyMutate { + const MODULE_NAME: &'static IdentStr = ident_str!("token_event_store"); + const STRUCT_NAME: &'static IdentStr = ident_str!("RoyaltyMutate"); +} + +impl MoveEventV2Type for RoyaltyMutate {} + +pub static ROYALTY_MUTATE_TYPE: Lazy = Lazy::new(|| { + TypeTag::Struct(Box::new(StructTag { + address: TOKEN_ADDRESS, + module: ident_str!("token_event_store").to_owned(), + name: ident_str!("RoyaltyMutate").to_owned(), + type_args: vec![], + })) +}); diff --git a/types/src/account_config/events/royalty_mutate_event.rs b/types/src/account_config/events/royalty_mutate_event.rs new file mode 100644 index 0000000000000..b6d86f7b71f3c --- /dev/null +++ b/types/src/account_config/events/royalty_mutate_event.rs @@ -0,0 +1,109 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use crate::move_utils::move_event_v1::MoveEventV1Type; +use anyhow::Result; +use move_core_types::{ + account_address::AccountAddress, + ident_str, + identifier::IdentStr, + language_storage::{StructTag, TypeTag, TOKEN_ADDRESS}, + move_resource::MoveStructType, +}; +use once_cell::sync::Lazy; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Deserialize, Serialize)] +pub struct RoyaltyMutateEvent { + creator: AccountAddress, + collection: String, + token: String, + old_royalty_numerator: u64, + old_royalty_denominator: u64, + old_royalty_payee_addr: AccountAddress, + new_royalty_numerator: u64, + new_royalty_denominator: u64, + new_royalty_payee_addr: AccountAddress, +} + +impl RoyaltyMutateEvent { + pub fn new( + creator: AccountAddress, + collection: String, + token: String, + old_royalty_numerator: u64, + old_royalty_denominator: u64, + old_royalty_payee_addr: AccountAddress, + new_royalty_numerator: u64, + new_royalty_denominator: u64, + new_royalty_payee_addr: AccountAddress, + ) -> Self { + Self { + creator, + collection, + token, + old_royalty_numerator, + old_royalty_denominator, + old_royalty_payee_addr, + new_royalty_numerator, + new_royalty_denominator, + new_royalty_payee_addr, + } + } + + pub fn try_from_bytes(bytes: &[u8]) -> Result { + bcs::from_bytes(bytes).map_err(Into::into) + } + + pub fn creator(&self) -> &AccountAddress { + &self.creator + } + + pub fn collection(&self) -> &String { + &self.collection + } + + pub fn token(&self) -> &String { + &self.token + } + + pub fn old_royalty_numerator(&self) -> &u64 { + &self.old_royalty_numerator + } + + pub fn old_royalty_denominator(&self) -> &u64 { + &self.old_royalty_denominator + } + + pub fn old_royalty_payee_addr(&self) -> &AccountAddress { + &self.old_royalty_payee_addr + } + + pub fn new_royalty_numerator(&self) -> &u64 { + &self.new_royalty_numerator + } + + pub fn new_royalty_denominator(&self) -> &u64 { + &self.new_royalty_denominator + } + + pub fn new_royalty_payee_addr(&self) -> &AccountAddress { + &self.new_royalty_payee_addr + } +} + +impl MoveStructType for RoyaltyMutateEvent { + const MODULE_NAME: &'static IdentStr = ident_str!("token_event_store"); + const STRUCT_NAME: &'static IdentStr = ident_str!("RoyaltyMutateEvent"); +} + +impl MoveEventV1Type for RoyaltyMutateEvent {} + +pub static ROYALTY_MUTATE_EVENT_TYPE: Lazy = Lazy::new(|| { + TypeTag::Struct(Box::new(StructTag { + address: TOKEN_ADDRESS, + module: ident_str!("token_event_store").to_owned(), + name: ident_str!("RoyaltyMutateEvent").to_owned(), + type_args: vec![], + })) +}); diff --git a/types/src/account_config/events/token_cancel_offer_event.rs b/types/src/account_config/events/token_cancel_offer_event.rs new file mode 100644 index 0000000000000..b902cdf1893e8 --- /dev/null +++ b/types/src/account_config/events/token_cancel_offer_event.rs @@ -0,0 +1,63 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use crate::{account_config::TokenId, move_utils::move_event_v1::MoveEventV1Type}; +use anyhow::Result; +use move_core_types::{ + account_address::AccountAddress, + ident_str, + identifier::IdentStr, + language_storage::{StructTag, TypeTag, TOKEN_ADDRESS}, + move_resource::MoveStructType, +}; +use once_cell::sync::Lazy; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Deserialize, Serialize)] +pub struct TokenCancelOfferEvent { + to_address: AccountAddress, + token_id: TokenId, + amount: u64, +} + +impl TokenCancelOfferEvent { + pub fn new(to_address: AccountAddress, token_id: TokenId, amount: u64) -> Self { + Self { + to_address, + token_id, + amount, + } + } + + pub fn try_from_bytes(bytes: &[u8]) -> Result { + bcs::from_bytes(bytes).map_err(Into::into) + } + + pub fn to_address(&self) -> &AccountAddress { + &self.to_address + } + + pub fn token_id(&self) -> &TokenId { + &self.token_id + } + + pub fn amount(&self) -> u64 { + self.amount + } +} + +impl MoveStructType for TokenCancelOfferEvent { + const MODULE_NAME: &'static IdentStr = ident_str!("token_transfers"); + const STRUCT_NAME: &'static IdentStr = ident_str!("TokenCancelOfferEvent"); +} + +impl MoveEventV1Type for TokenCancelOfferEvent {} + +pub static TOKEN_CANCEL_OFFER_EVENT_TYPE: Lazy = Lazy::new(|| { + TypeTag::Struct(Box::new(StructTag { + address: TOKEN_ADDRESS, + module: ident_str!("token_transfers").to_owned(), + name: ident_str!("TokenCancelOfferEvent").to_owned(), + type_args: vec![], + })) +}); diff --git a/types/src/account_config/events/token_claim_event.rs b/types/src/account_config/events/token_claim_event.rs new file mode 100644 index 0000000000000..83ce8cf8ddc06 --- /dev/null +++ b/types/src/account_config/events/token_claim_event.rs @@ -0,0 +1,63 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use crate::{account_config::TokenId, move_utils::move_event_v1::MoveEventV1Type}; +use anyhow::Result; +use move_core_types::{ + account_address::AccountAddress, + ident_str, + identifier::IdentStr, + language_storage::{StructTag, TypeTag, TOKEN_ADDRESS}, + move_resource::MoveStructType, +}; +use once_cell::sync::Lazy; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Deserialize, Serialize)] +pub struct TokenClaimEvent { + to_address: AccountAddress, + token_id: TokenId, + amount: u64, +} + +impl TokenClaimEvent { + pub fn new(to_address: AccountAddress, token_id: TokenId, amount: u64) -> Self { + Self { + to_address, + token_id, + amount, + } + } + + pub fn try_from_bytes(bytes: &[u8]) -> Result { + bcs::from_bytes(bytes).map_err(Into::into) + } + + pub fn to_address(&self) -> &AccountAddress { + &self.to_address + } + + pub fn token_id(&self) -> &TokenId { + &self.token_id + } + + pub fn amount(&self) -> u64 { + self.amount + } +} + +impl MoveStructType for TokenClaimEvent { + const MODULE_NAME: &'static IdentStr = ident_str!("token_transfers"); + const STRUCT_NAME: &'static IdentStr = ident_str!("TokenClaimEvent"); +} + +impl MoveEventV1Type for TokenClaimEvent {} + +pub static TOKEN_CLAIM_EVENT_TYPE: Lazy = Lazy::new(|| { + TypeTag::Struct(Box::new(StructTag { + address: TOKEN_ADDRESS, + module: ident_str!("token_transfers").to_owned(), + name: ident_str!("TokenClaimEvent").to_owned(), + type_args: vec![], + })) +}); diff --git a/types/src/account_config/events/token_data_creation.rs b/types/src/account_config/events/token_data_creation.rs new file mode 100644 index 0000000000000..ac87b5cadf505 --- /dev/null +++ b/types/src/account_config/events/token_data_creation.rs @@ -0,0 +1,145 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use crate::{account_config::TokenDataId, move_utils::move_event_v2::MoveEventV2Type}; +use anyhow::Result; +use move_core_types::{ + account_address::AccountAddress, + ident_str, + identifier::IdentStr, + language_storage::{StructTag, TypeTag, TOKEN_ADDRESS}, + move_resource::MoveStructType, +}; +use once_cell::sync::Lazy; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Deserialize, Serialize)] +pub struct TokenDataCreation { + creator: AccountAddress, + id: TokenDataId, + description: String, + maximum: u64, + uri: String, + royalty_payee_address: AccountAddress, + royalty_points_denominator: u64, + royalty_points_numerator: u64, + name: String, + mutability_config: TokenMutabilityConfig, + property_keys: Vec, + property_values: Vec>, + property_types: Vec, +} +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct TokenMutabilityConfig { + maximum: bool, + uri: bool, + royalty: bool, + description: bool, + properties: bool, +} + +impl TokenDataCreation { + pub fn new( + creator: AccountAddress, + id: TokenDataId, + description: String, + maximum: u64, + uri: String, + royalty_payee_address: AccountAddress, + royalty_points_denominator: u64, + royalty_points_numerator: u64, + name: String, + mutability_config: TokenMutabilityConfig, + property_keys: Vec, + property_values: Vec>, + property_types: Vec, + ) -> Self { + Self { + creator, + id, + description, + maximum, + uri, + royalty_payee_address, + royalty_points_denominator, + royalty_points_numerator, + name, + mutability_config, + property_keys, + property_values, + property_types, + } + } + + pub fn try_from_bytes(bytes: &[u8]) -> Result { + bcs::from_bytes(bytes).map_err(Into::into) + } + + pub fn creator(&self) -> &AccountAddress { + &self.creator + } + + pub fn id(&self) -> &TokenDataId { + &self.id + } + + pub fn description(&self) -> &String { + &self.description + } + + pub fn maximum(&self) -> u64 { + self.maximum + } + + pub fn uri(&self) -> &String { + &self.uri + } + + pub fn royalty_payee_address(&self) -> &AccountAddress { + &self.royalty_payee_address + } + + pub fn royalty_points_denominator(&self) -> u64 { + self.royalty_points_denominator + } + + pub fn royalty_points_numerator(&self) -> u64 { + self.royalty_points_numerator + } + + pub fn name(&self) -> &String { + &self.name + } + + pub fn mutability_config(&self) -> &TokenMutabilityConfig { + &self.mutability_config + } + + pub fn property_keys(&self) -> &Vec { + &self.property_keys + } + + pub fn property_values(&self) -> &Vec> { + &self.property_values + } + + pub fn property_types(&self) -> &Vec { + &self.property_types + } +} + +impl MoveStructType for TokenDataCreation { + const MODULE_NAME: &'static IdentStr = ident_str!("token"); + const STRUCT_NAME: &'static IdentStr = ident_str!("TokenDataCreation"); +} + +impl MoveEventV2Type for TokenDataCreation {} + +pub static TOKEN_DATA_CREATION_TYPE: Lazy = Lazy::new(|| { + TypeTag::Struct(Box::new(StructTag { + address: TOKEN_ADDRESS, + module: ident_str!("token").to_owned(), + name: ident_str!("TokenDataCreation").to_owned(), + type_args: vec![], + })) +}); diff --git a/types/src/account_config/events/token_deposit.rs b/types/src/account_config/events/token_deposit.rs new file mode 100644 index 0000000000000..06e2afb1a39a1 --- /dev/null +++ b/types/src/account_config/events/token_deposit.rs @@ -0,0 +1,76 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use crate::move_utils::move_event_v2::MoveEventV2Type; +use anyhow::Result; +use move_core_types::{ + account_address::AccountAddress, + ident_str, + identifier::IdentStr, + language_storage::{StructTag, TypeTag, TOKEN_ADDRESS}, + move_resource::MoveStructType, +}; +use once_cell::sync::Lazy; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Deserialize, Serialize)] +pub struct TokenDeposit { + account: AccountAddress, + id: TokenId, + amount: u64, +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct TokenId { + token_data_id: TokenDataId, + property_version: u64, +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct TokenDataId { + creator: AccountAddress, + collection: String, + name: String, +} + +impl TokenDeposit { + pub fn new(account: AccountAddress, id: TokenId, amount: u64) -> Self { + Self { + account, + id, + amount, + } + } + + pub fn try_from_bytes(bytes: &[u8]) -> Result { + bcs::from_bytes(bytes).map_err(Into::into) + } + + pub fn account(&self) -> &AccountAddress { + &self.account + } + + pub fn id(&self) -> &TokenId { + &self.id + } + + pub fn amount(&self) -> u64 { + self.amount + } +} + +impl MoveStructType for TokenDeposit { + const MODULE_NAME: &'static IdentStr = ident_str!("token"); + const STRUCT_NAME: &'static IdentStr = ident_str!("TokenDeposit"); +} + +impl MoveEventV2Type for TokenDeposit {} + +pub static TOKEN_DEPOSIT_TYPE: Lazy = Lazy::new(|| { + TypeTag::Struct(Box::new(StructTag { + address: TOKEN_ADDRESS, + module: ident_str!("token").to_owned(), + name: ident_str!("TokenDeposit").to_owned(), + type_args: vec![], + })) +}); diff --git a/types/src/account_config/events/token_deposit_event.rs b/types/src/account_config/events/token_deposit_event.rs new file mode 100644 index 0000000000000..88c2472737c69 --- /dev/null +++ b/types/src/account_config/events/token_deposit_event.rs @@ -0,0 +1,53 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use crate::{account_config::TokenId, move_utils::move_event_v1::MoveEventV1Type}; +use anyhow::Result; +use move_core_types::{ + ident_str, + identifier::IdentStr, + language_storage::{StructTag, TypeTag, TOKEN_ADDRESS}, + move_resource::MoveStructType, +}; +use once_cell::sync::Lazy; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Deserialize, Serialize)] +pub struct TokenDepositEvent { + id: TokenId, + amount: u64, +} + +impl TokenDepositEvent { + pub fn new(id: TokenId, amount: u64) -> Self { + Self { id, amount } + } + + pub fn try_from_bytes(bytes: &[u8]) -> Result { + bcs::from_bytes(bytes).map_err(Into::into) + } + + pub fn id(&self) -> &TokenId { + &self.id + } + + pub fn amount(&self) -> u64 { + self.amount + } +} + +impl MoveStructType for TokenDepositEvent { + const MODULE_NAME: &'static IdentStr = ident_str!("token"); + const STRUCT_NAME: &'static IdentStr = ident_str!("DepositEvent"); +} + +impl MoveEventV1Type for TokenDepositEvent {} + +pub static TOKEN_DEPOSIT_EVENT_TYPE: Lazy = Lazy::new(|| { + TypeTag::Struct(Box::new(StructTag { + address: TOKEN_ADDRESS, + module: ident_str!("token").to_owned(), + name: ident_str!("DepositEvent").to_owned(), + type_args: vec![], + })) +}); diff --git a/types/src/account_config/events/token_mutation.rs b/types/src/account_config/events/token_mutation.rs new file mode 100644 index 0000000000000..da044a4ccb598 --- /dev/null +++ b/types/src/account_config/events/token_mutation.rs @@ -0,0 +1,73 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use crate::move_utils::move_event_v2::MoveEventV2Type; +use move_core_types::{ + account_address::AccountAddress, + ident_str, + identifier::IdentStr, + language_storage::{StructTag, TypeTag, TOKEN_OBJECTS_ADDRESS}, + move_resource::MoveStructType, +}; +use once_cell::sync::Lazy; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] +pub struct TokenMutation { + token_address: AccountAddress, + mutated_field_name: String, + old_value: String, + new_value: String, +} + +impl TokenMutation { + pub fn new( + token_address: AccountAddress, + mutated_field_name: String, + old_value: String, + new_value: String, + ) -> Self { + Self { + token_address, + mutated_field_name, + old_value, + new_value, + } + } + + pub fn try_from_bytes(bytes: &[u8]) -> anyhow::Result { + bcs::from_bytes(bytes).map_err(Into::into) + } + + pub fn token_address(&self) -> &AccountAddress { + &self.token_address + } + + pub fn mutated_field_name(&self) -> &String { + &self.mutated_field_name + } + + pub fn old_value(&self) -> &String { + &self.old_value + } + + pub fn new_value(&self) -> &String { + &self.new_value + } +} + +impl MoveStructType for TokenMutation { + const MODULE_NAME: &'static IdentStr = ident_str!("token"); + const STRUCT_NAME: &'static IdentStr = ident_str!("Mutation"); +} + +impl MoveEventV2Type for TokenMutation {} + +pub static TOKEN_MUTATION_TYPE: Lazy = Lazy::new(|| { + TypeTag::Struct(Box::new(StructTag { + address: TOKEN_OBJECTS_ADDRESS, + module: ident_str!("token").to_owned(), + name: ident_str!("Mutation").to_owned(), + type_args: vec![], + })) +}); diff --git a/types/src/account_config/events/token_mutation_event.rs b/types/src/account_config/events/token_mutation_event.rs new file mode 100644 index 0000000000000..557ec7aebc6fc --- /dev/null +++ b/types/src/account_config/events/token_mutation_event.rs @@ -0,0 +1,61 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use crate::move_utils::move_event_v1::MoveEventV1Type; +use move_core_types::{ + ident_str, + identifier::IdentStr, + language_storage::{StructTag, TypeTag, TOKEN_OBJECTS_ADDRESS}, + move_resource::MoveStructType, +}; +use once_cell::sync::Lazy; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] +pub struct TokenMutationEvent { + mutated_field_name: String, + old_value: String, + new_value: String, +} + +impl TokenMutationEvent { + pub fn new(mutated_field_name: String, old_value: String, new_value: String) -> Self { + Self { + mutated_field_name, + old_value, + new_value, + } + } + + pub fn try_from_bytes(bytes: &[u8]) -> anyhow::Result { + bcs::from_bytes(bytes).map_err(Into::into) + } + + pub fn mutated_field_name(&self) -> &String { + &self.mutated_field_name + } + + pub fn old_value(&self) -> &String { + &self.old_value + } + + pub fn new_value(&self) -> &String { + &self.new_value + } +} + +impl MoveStructType for TokenMutationEvent { + const MODULE_NAME: &'static IdentStr = ident_str!("token"); + const STRUCT_NAME: &'static IdentStr = ident_str!("MutationEvent"); +} + +impl MoveEventV1Type for TokenMutationEvent {} + +pub static TOKEN_MUTATION_EVENT_TYPE: Lazy = Lazy::new(|| { + TypeTag::Struct(Box::new(StructTag { + address: TOKEN_OBJECTS_ADDRESS, + module: ident_str!("token").to_owned(), + name: ident_str!("MutationEvent").to_owned(), + type_args: vec![], + })) +}); diff --git a/types/src/account_config/events/token_offer_event.rs b/types/src/account_config/events/token_offer_event.rs new file mode 100644 index 0000000000000..c2f8d391c3941 --- /dev/null +++ b/types/src/account_config/events/token_offer_event.rs @@ -0,0 +1,63 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use crate::{account_config::TokenId, move_utils::move_event_v1::MoveEventV1Type}; +use anyhow::Result; +use move_core_types::{ + account_address::AccountAddress, + ident_str, + identifier::IdentStr, + language_storage::{StructTag, TypeTag, TOKEN_ADDRESS}, + move_resource::MoveStructType, +}; +use once_cell::sync::Lazy; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Deserialize, Serialize)] +pub struct TokenOfferEvent { + to_address: AccountAddress, + token_id: TokenId, + amount: u64, +} + +impl TokenOfferEvent { + pub fn new(to_address: AccountAddress, token_id: TokenId, amount: u64) -> Self { + Self { + to_address, + token_id, + amount, + } + } + + pub fn try_from_bytes(bytes: &[u8]) -> Result { + bcs::from_bytes(bytes).map_err(Into::into) + } + + pub fn to_address(&self) -> &AccountAddress { + &self.to_address + } + + pub fn token_id(&self) -> &TokenId { + &self.token_id + } + + pub fn amount(&self) -> u64 { + self.amount + } +} + +impl MoveStructType for TokenOfferEvent { + const MODULE_NAME: &'static IdentStr = ident_str!("token_transfers"); + const STRUCT_NAME: &'static IdentStr = ident_str!("TokenOfferEvent"); +} + +impl MoveEventV1Type for TokenOfferEvent {} + +pub static TOKEN_OFFER_EVENT_TYPE: Lazy = Lazy::new(|| { + TypeTag::Struct(Box::new(StructTag { + address: TOKEN_ADDRESS, + module: ident_str!("token_transfers").to_owned(), + name: ident_str!("TokenOfferEvent").to_owned(), + type_args: vec![], + })) +}); diff --git a/types/src/account_config/events/token_withdraw.rs b/types/src/account_config/events/token_withdraw.rs new file mode 100644 index 0000000000000..6ad71998de35c --- /dev/null +++ b/types/src/account_config/events/token_withdraw.rs @@ -0,0 +1,63 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use crate::{account_config::TokenId, move_utils::move_event_v2::MoveEventV2Type}; +use anyhow::Result; +use move_core_types::{ + account_address::AccountAddress, + ident_str, + identifier::IdentStr, + language_storage::{StructTag, TypeTag, TOKEN_ADDRESS}, + move_resource::MoveStructType, +}; +use once_cell::sync::Lazy; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Deserialize, Serialize)] +pub struct TokenWithdraw { + account: AccountAddress, + id: TokenId, + amount: u64, +} + +impl TokenWithdraw { + pub fn new(account: AccountAddress, id: TokenId, amount: u64) -> Self { + Self { + account, + id, + amount, + } + } + + pub fn try_from_bytes(bytes: &[u8]) -> Result { + bcs::from_bytes(bytes).map_err(Into::into) + } + + pub fn account(&self) -> &AccountAddress { + &self.account + } + + pub fn id(&self) -> &TokenId { + &self.id + } + + pub fn amount(&self) -> u64 { + self.amount + } +} + +impl MoveStructType for TokenWithdraw { + const MODULE_NAME: &'static IdentStr = ident_str!("token"); + const STRUCT_NAME: &'static IdentStr = ident_str!("TokenWithdraw"); +} + +impl MoveEventV2Type for TokenWithdraw {} + +pub static TOKEN_WITHDRAW_TYPE: Lazy = Lazy::new(|| { + TypeTag::Struct(Box::new(StructTag { + address: TOKEN_ADDRESS, + module: ident_str!("token").to_owned(), + name: ident_str!("TokenWithdraw").to_owned(), + type_args: vec![], + })) +}); diff --git a/types/src/account_config/events/token_withdraw_event.rs b/types/src/account_config/events/token_withdraw_event.rs new file mode 100644 index 0000000000000..3a81da0200e44 --- /dev/null +++ b/types/src/account_config/events/token_withdraw_event.rs @@ -0,0 +1,53 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use crate::{account_config::TokenId, move_utils::move_event_v1::MoveEventV1Type}; +use anyhow::Result; +use move_core_types::{ + ident_str, + identifier::IdentStr, + language_storage::{StructTag, TypeTag, TOKEN_ADDRESS}, + move_resource::MoveStructType, +}; +use once_cell::sync::Lazy; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Deserialize, Serialize)] +pub struct TokenWithdrawEvent { + id: TokenId, + amount: u64, +} + +impl TokenWithdrawEvent { + pub fn new(id: TokenId, amount: u64) -> Self { + Self { id, amount } + } + + pub fn try_from_bytes(bytes: &[u8]) -> Result { + bcs::from_bytes(bytes).map_err(Into::into) + } + + pub fn id(&self) -> &TokenId { + &self.id + } + + pub fn amount(&self) -> u64 { + self.amount + } +} + +impl MoveStructType for TokenWithdrawEvent { + const MODULE_NAME: &'static IdentStr = ident_str!("token"); + const STRUCT_NAME: &'static IdentStr = ident_str!("WithdrawEvent"); +} + +impl MoveEventV1Type for TokenWithdrawEvent {} + +pub static TOKEN_WITHDRAW_EVENT_TYPE: Lazy = Lazy::new(|| { + TypeTag::Struct(Box::new(StructTag { + address: TOKEN_ADDRESS, + module: ident_str!("token").to_owned(), + name: ident_str!("WithdrawEvent").to_owned(), + type_args: vec![], + })) +}); diff --git a/types/src/account_config/events/transfer.rs b/types/src/account_config/events/transfer.rs new file mode 100644 index 0000000000000..2ed4d65046d8f --- /dev/null +++ b/types/src/account_config/events/transfer.rs @@ -0,0 +1,58 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use crate::move_utils::move_event_v2::MoveEventV2Type; +use move_core_types::{ + account_address::AccountAddress, + ident_str, + identifier::IdentStr, + language_storage::{StructTag, TypeTag, CORE_CODE_ADDRESS}, + move_resource::MoveStructType, +}; +use once_cell::sync::Lazy; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] +pub struct Transfer { + object: AccountAddress, + from: AccountAddress, + to: AccountAddress, +} + +impl Transfer { + pub fn new(object: AccountAddress, from: AccountAddress, to: AccountAddress) -> Self { + Self { object, from, to } + } + + pub fn try_from_bytes(bytes: &[u8]) -> anyhow::Result { + bcs::from_bytes(bytes).map_err(Into::into) + } + + pub fn object(&self) -> &AccountAddress { + &self.object + } + + pub fn from(&self) -> &AccountAddress { + &self.from + } + + pub fn to(&self) -> &AccountAddress { + &self.to + } +} + +impl MoveStructType for Transfer { + const MODULE_NAME: &'static IdentStr = ident_str!("object"); + const STRUCT_NAME: &'static IdentStr = ident_str!("Transfer"); +} + +impl MoveEventV2Type for Transfer {} + +pub static TRANSFER_TYPE: Lazy = Lazy::new(|| { + TypeTag::Struct(Box::new(StructTag { + address: CORE_CODE_ADDRESS, + module: ident_str!("object").to_owned(), + name: ident_str!("Transfer").to_owned(), + type_args: vec![], + })) +}); diff --git a/types/src/account_config/events/transfer_event.rs b/types/src/account_config/events/transfer_event.rs new file mode 100644 index 0000000000000..e805ec1ffc177 --- /dev/null +++ b/types/src/account_config/events/transfer_event.rs @@ -0,0 +1,58 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use crate::move_utils::move_event_v1::MoveEventV1Type; +use move_core_types::{ + account_address::AccountAddress, + ident_str, + identifier::IdentStr, + language_storage::{StructTag, TypeTag, CORE_CODE_ADDRESS}, + move_resource::MoveStructType, +}; +use once_cell::sync::Lazy; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] +pub struct TransferEvent { + object: AccountAddress, + from: AccountAddress, + to: AccountAddress, +} + +impl TransferEvent { + pub fn new(object: AccountAddress, from: AccountAddress, to: AccountAddress) -> Self { + Self { object, from, to } + } + + pub fn try_from_bytes(bytes: &[u8]) -> anyhow::Result { + bcs::from_bytes(bytes).map_err(Into::into) + } + + pub fn object(&self) -> &AccountAddress { + &self.object + } + + pub fn from(&self) -> &AccountAddress { + &self.from + } + + pub fn to(&self) -> &AccountAddress { + &self.to + } +} + +impl MoveStructType for TransferEvent { + const MODULE_NAME: &'static IdentStr = ident_str!("object"); + const STRUCT_NAME: &'static IdentStr = ident_str!("TransferEvent"); +} + +impl MoveEventV1Type for TransferEvent {} + +pub static TRANSFER_EVENT_TYPE: Lazy = Lazy::new(|| { + TypeTag::Struct(Box::new(StructTag { + address: CORE_CODE_ADDRESS, + module: ident_str!("object").to_owned(), + name: ident_str!("TransferEvent").to_owned(), + type_args: vec![], + })) +}); diff --git a/types/src/account_config/events/uri_mutation.rs b/types/src/account_config/events/uri_mutation.rs new file mode 100644 index 0000000000000..dc67b99337c39 --- /dev/null +++ b/types/src/account_config/events/uri_mutation.rs @@ -0,0 +1,81 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use crate::move_utils::move_event_v2::MoveEventV2Type; +use anyhow::Result; +use move_core_types::{ + account_address::AccountAddress, + ident_str, + identifier::IdentStr, + language_storage::{StructTag, TypeTag, TOKEN_ADDRESS}, + move_resource::MoveStructType, +}; +use once_cell::sync::Lazy; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Deserialize, Serialize)] +pub struct UriMutation { + creator: AccountAddress, + collection: String, + token: String, + old_uri: String, + new_uri: String, +} + +impl UriMutation { + pub fn new( + creator: AccountAddress, + collection: String, + token: String, + old_uri: String, + new_uri: String, + ) -> Self { + Self { + creator, + collection, + token, + old_uri, + new_uri, + } + } + + pub fn try_from_bytes(bytes: &[u8]) -> Result { + bcs::from_bytes(bytes).map_err(Into::into) + } + + pub fn creator(&self) -> &AccountAddress { + &self.creator + } + + pub fn collection(&self) -> &String { + &self.collection + } + + pub fn token(&self) -> &String { + &self.token + } + + pub fn old_uri(&self) -> &String { + &self.old_uri + } + + pub fn new_uri(&self) -> &String { + &self.new_uri + } +} + +impl MoveStructType for UriMutation { + const MODULE_NAME: &'static IdentStr = ident_str!("token_event_store"); + const STRUCT_NAME: &'static IdentStr = ident_str!("UriMutation"); +} + +impl MoveEventV2Type for UriMutation {} + +pub static URI_MUTATION_TYPE: Lazy = Lazy::new(|| { + TypeTag::Struct(Box::new(StructTag { + address: TOKEN_ADDRESS, + module: ident_str!("token_event_store").to_owned(), + name: ident_str!("UriMutation").to_owned(), + type_args: vec![], + })) +}); diff --git a/types/src/account_config/events/uri_mutation_event.rs b/types/src/account_config/events/uri_mutation_event.rs new file mode 100644 index 0000000000000..4bb25e0ccc7eb --- /dev/null +++ b/types/src/account_config/events/uri_mutation_event.rs @@ -0,0 +1,81 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use crate::move_utils::move_event_v1::MoveEventV1Type; +use anyhow::Result; +use move_core_types::{ + account_address::AccountAddress, + ident_str, + identifier::IdentStr, + language_storage::{StructTag, TypeTag, TOKEN_ADDRESS}, + move_resource::MoveStructType, +}; +use once_cell::sync::Lazy; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Deserialize, Serialize)] +pub struct UriMutationEvent { + creator: AccountAddress, + collection: String, + token: String, + old_uri: String, + new_uri: String, +} + +impl UriMutationEvent { + pub fn new( + creator: AccountAddress, + collection: String, + token: String, + old_uri: String, + new_uri: String, + ) -> Self { + Self { + creator, + collection, + token, + old_uri, + new_uri, + } + } + + pub fn try_from_bytes(bytes: &[u8]) -> Result { + bcs::from_bytes(bytes).map_err(Into::into) + } + + pub fn creator(&self) -> &AccountAddress { + &self.creator + } + + pub fn collection(&self) -> &String { + &self.collection + } + + pub fn token(&self) -> &String { + &self.token + } + + pub fn old_uri(&self) -> &String { + &self.old_uri + } + + pub fn new_uri(&self) -> &String { + &self.new_uri + } +} + +impl MoveStructType for UriMutationEvent { + const MODULE_NAME: &'static IdentStr = ident_str!("token_event_store"); + const STRUCT_NAME: &'static IdentStr = ident_str!("UriMutationEvent"); +} + +impl MoveEventV1Type for UriMutationEvent {} + +pub static URI_MUTATION_EVENT_TYPE: Lazy = Lazy::new(|| { + TypeTag::Struct(Box::new(StructTag { + address: TOKEN_ADDRESS, + module: ident_str!("token_event_store").to_owned(), + name: ident_str!("UriMutationEvent").to_owned(), + type_args: vec![], + })) +}); diff --git a/types/src/account_config/events/withdraw_event.rs b/types/src/account_config/events/withdraw_event.rs new file mode 100644 index 0000000000000..ff386b8f97d68 --- /dev/null +++ b/types/src/account_config/events/withdraw_event.rs @@ -0,0 +1,49 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use crate::move_utils::move_event_v1::MoveEventV1Type; +use anyhow::Result; +use move_core_types::{ + ident_str, + identifier::IdentStr, + language_storage::{StructTag, TypeTag, CORE_CODE_ADDRESS}, + move_resource::MoveStructType, +}; +use once_cell::sync::Lazy; +use serde::{Deserialize, Serialize}; + +/// Struct that represents a SentPaymentEvent. +#[derive(Debug, Serialize, Deserialize)] +pub struct WithdrawEvent { + amount: u64, +} + +impl WithdrawEvent { + pub fn new(amount: u64) -> Self { + Self { amount } + } + + pub fn try_from_bytes(bytes: &[u8]) -> Result { + bcs::from_bytes(bytes).map_err(Into::into) + } + + pub fn amount(&self) -> u64 { + self.amount + } +} + +impl MoveStructType for WithdrawEvent { + const MODULE_NAME: &'static IdentStr = ident_str!("coin"); + const STRUCT_NAME: &'static IdentStr = ident_str!("WithdrawEvent"); +} + +impl MoveEventV1Type for WithdrawEvent {} + +pub static WITHDRAW_EVENT_TYPE: Lazy = Lazy::new(|| { + TypeTag::Struct(Box::new(StructTag { + address: CORE_CODE_ADDRESS, + module: ident_str!("coin").to_owned(), + name: ident_str!("WithdrawEvent").to_owned(), + type_args: vec![], + })) +}); diff --git a/types/src/account_config/resources/aggregator.rs b/types/src/account_config/resources/aggregator.rs index cf8fdcc34c023..794d29ca52ac0 100644 --- a/types/src/account_config/resources/aggregator.rs +++ b/types/src/account_config/resources/aggregator.rs @@ -27,7 +27,7 @@ impl AggregatorResource { #[derive(Debug, Serialize, Deserialize)] pub struct AggregatorSnapshotResource { - value: T, + pub value: T, } #[derive(Debug, Serialize, Deserialize)] diff --git a/types/src/account_config/resources/any.rs b/types/src/account_config/resources/any.rs new file mode 100644 index 0000000000000..719a92b13f8d9 --- /dev/null +++ b/types/src/account_config/resources/any.rs @@ -0,0 +1,40 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use anyhow::Result; +use move_core_types::{ + ident_str, + identifier::IdentStr, + language_storage::{StructTag, TypeTag, CORE_CODE_ADDRESS}, + move_resource::{MoveResource, MoveStructType}, +}; +use once_cell::sync::Lazy; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] +pub struct AnyResource { + type_name: String, + data: Vec, +} + +impl AnyResource { + pub fn try_from_bytes(bytes: &[u8]) -> Result { + bcs::from_bytes(bytes).map_err(Into::into) + } +} + +impl MoveStructType for AnyResource { + const MODULE_NAME: &'static IdentStr = ident_str!("any"); + const STRUCT_NAME: &'static IdentStr = ident_str!("Any"); +} + +impl MoveResource for AnyResource {} + +pub static ANY_RESOURCE_TYPE: Lazy = Lazy::new(|| { + TypeTag::Struct(Box::new(StructTag { + address: CORE_CODE_ADDRESS, + module: ident_str!("any").to_owned(), + name: ident_str!("Any").to_owned(), + type_args: vec![], + })) +}); diff --git a/types/src/account_config/resources/collection.rs b/types/src/account_config/resources/collection.rs new file mode 100644 index 0000000000000..a975b27db4651 --- /dev/null +++ b/types/src/account_config/resources/collection.rs @@ -0,0 +1,65 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use crate::event::EventHandle; +use move_core_types::{ + account_address::AccountAddress, + ident_str, + identifier::IdentStr, + move_resource::{MoveResource, MoveStructType}, +}; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Eq, PartialEq, Serialize, Deserialize)] +pub struct CollectionResource { + creator: AccountAddress, + description: String, + name: String, + uri: String, + mutation_events: EventHandle, +} + +impl CollectionResource { + pub fn new( + creator: AccountAddress, + description: String, + name: String, + uri: String, + mutation_events: EventHandle, + ) -> Self { + Self { + creator, + description, + name, + uri, + mutation_events, + } + } + + pub fn creator(&self) -> &AccountAddress { + &self.creator + } + + pub fn description(&self) -> &String { + &self.description + } + + pub fn name(&self) -> &String { + &self.name + } + + pub fn uri(&self) -> &String { + &self.uri + } + + pub fn mutation_events(&self) -> &EventHandle { + &self.mutation_events + } +} + +impl MoveStructType for CollectionResource { + const MODULE_NAME: &'static IdentStr = ident_str!("collection"); + const STRUCT_NAME: &'static IdentStr = ident_str!("Collection"); +} + +impl MoveResource for CollectionResource {} diff --git a/types/src/account_config/resources/collections.rs b/types/src/account_config/resources/collections.rs new file mode 100644 index 0000000000000..0f9f958f282d2 --- /dev/null +++ b/types/src/account_config/resources/collections.rs @@ -0,0 +1,64 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use crate::{account_config::Table, event::EventHandle}; +use move_core_types::{ + ident_str, + identifier::IdentStr, + move_resource::{MoveResource, MoveStructType}, +}; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize)] +pub struct CollectionsResource { + collection_data: Table, + token_data: Table, + create_collection_events: EventHandle, + create_token_data_events: EventHandle, + mint_token_events: EventHandle, +} + +impl CollectionsResource { + pub fn new( + collection_data: Table, + token_data: Table, + create_collection_events: EventHandle, + create_token_data_events: EventHandle, + mint_token_events: EventHandle, + ) -> Self { + Self { + collection_data, + token_data, + create_collection_events, + create_token_data_events, + mint_token_events, + } + } + + pub fn collection_data(&self) -> &Table { + &self.collection_data + } + + pub fn token_data(&self) -> &Table { + &self.token_data + } + + pub fn create_collection_events(&self) -> &EventHandle { + &self.create_collection_events + } + + pub fn create_token_data_events(&self) -> &EventHandle { + &self.create_token_data_events + } + + pub fn mint_token_events(&self) -> &EventHandle { + &self.mint_token_events + } +} + +impl MoveStructType for CollectionsResource { + const MODULE_NAME: &'static IdentStr = ident_str!("token"); + const STRUCT_NAME: &'static IdentStr = ident_str!("Collections"); +} + +impl MoveResource for CollectionsResource {} diff --git a/types/src/account_config/resources/fixed_supply.rs b/types/src/account_config/resources/fixed_supply.rs new file mode 100644 index 0000000000000..9b37151c96da2 --- /dev/null +++ b/types/src/account_config/resources/fixed_supply.rs @@ -0,0 +1,64 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use crate::event::EventHandle; +use move_core_types::{ + ident_str, + identifier::IdentStr, + move_resource::{MoveResource, MoveStructType}, +}; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Eq, PartialEq, Serialize, Deserialize)] +pub struct FixedSupplyResource { + current_supply: u64, + max_supply: u64, + total_minted: u64, + burn_events: EventHandle, + mint_events: EventHandle, +} + +impl FixedSupplyResource { + pub fn new( + current_supply: u64, + max_supply: u64, + total_minted: u64, + burn_events: EventHandle, + mint_events: EventHandle, + ) -> Self { + Self { + current_supply, + max_supply, + total_minted, + burn_events, + mint_events, + } + } + + pub fn current_supply(&self) -> u64 { + self.current_supply + } + + pub fn max_supply(&self) -> u64 { + self.max_supply + } + + pub fn total_minted(&self) -> u64 { + self.total_minted + } + + pub fn burn_events(&self) -> &EventHandle { + &self.burn_events + } + + pub fn mint_events(&self) -> &EventHandle { + &self.mint_events + } +} + +impl MoveStructType for FixedSupplyResource { + const MODULE_NAME: &'static IdentStr = ident_str!("collection"); + const STRUCT_NAME: &'static IdentStr = ident_str!("FixedSupply"); +} + +impl MoveResource for FixedSupplyResource {} diff --git a/types/src/account_config/resources/mod.rs b/types/src/account_config/resources/mod.rs index cbe90b7599639..8f2ea28eaca5f 100644 --- a/types/src/account_config/resources/mod.rs +++ b/types/src/account_config/resources/mod.rs @@ -3,22 +3,41 @@ // SPDX-License-Identifier: Apache-2.0 pub mod aggregator; +pub mod any; pub mod chain_id; pub mod challenge; pub mod coin_info; pub mod coin_store; +pub mod collection; +pub mod collections; pub mod core_account; +pub mod fixed_supply; pub mod fungible_asset_metadata; pub mod fungible_store; pub mod object; +pub mod pending_claims; +pub mod token; +pub mod token_event_store_v1; +pub mod token_store; pub mod type_info; +pub mod unlimited_supply; +pub use aggregator::*; +pub use any::*; pub use chain_id::*; pub use challenge::*; pub use coin_info::*; pub use coin_store::*; +pub use collection::*; +pub use collections::*; pub use core_account::*; +pub use fixed_supply::*; pub use fungible_asset_metadata::*; pub use fungible_store::*; pub use object::*; +pub use pending_claims::*; +pub use token::*; +pub use token_event_store_v1::*; +pub use token_store::*; pub use type_info::*; +pub use unlimited_supply::*; diff --git a/types/src/account_config/resources/object.rs b/types/src/account_config/resources/object.rs index e2e821844e547..e6179af601fdf 100644 --- a/types/src/account_config/resources/object.rs +++ b/types/src/account_config/resources/object.rs @@ -61,6 +61,10 @@ impl ObjectCoreResource { transfer_events, } } + + pub fn transfer_events(&self) -> &EventHandle { + &self.transfer_events + } } impl MoveStructType for ObjectCoreResource { @@ -69,3 +73,18 @@ impl MoveStructType for ObjectCoreResource { } impl MoveResource for ObjectCoreResource {} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub struct Object { + inner: AccountAddress, +} + +impl Object { + pub fn new(inner: AccountAddress) -> Self { + Self { inner } + } + + pub fn inner(&self) -> &AccountAddress { + &self.inner + } +} diff --git a/types/src/account_config/resources/pending_claims.rs b/types/src/account_config/resources/pending_claims.rs new file mode 100644 index 0000000000000..3f1c6adb23772 --- /dev/null +++ b/types/src/account_config/resources/pending_claims.rs @@ -0,0 +1,57 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use crate::{account_config::Table, event::EventHandle}; +use move_core_types::{ + ident_str, + identifier::IdentStr, + move_resource::{MoveResource, MoveStructType}, +}; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize)] +pub struct PendingClaimsResource { + pending_claims: Table, + offer_events: EventHandle, + cancel_offer_events: EventHandle, + claim_events: EventHandle, +} + +impl PendingClaimsResource { + pub fn new( + pending_claims: Table, + offer_events: EventHandle, + cancel_offer_events: EventHandle, + claim_events: EventHandle, + ) -> Self { + Self { + pending_claims, + offer_events, + cancel_offer_events, + claim_events, + } + } + + pub fn pending_claims(&self) -> &Table { + &self.pending_claims + } + + pub fn offer_events(&self) -> &EventHandle { + &self.offer_events + } + + pub fn cancel_offer_events(&self) -> &EventHandle { + &self.cancel_offer_events + } + + pub fn claim_events(&self) -> &EventHandle { + &self.claim_events + } +} + +impl MoveStructType for PendingClaimsResource { + const MODULE_NAME: &'static IdentStr = ident_str!("token"); + const STRUCT_NAME: &'static IdentStr = ident_str!("PendingClaims"); +} + +impl MoveResource for PendingClaimsResource {} diff --git a/types/src/account_config/resources/token.rs b/types/src/account_config/resources/token.rs new file mode 100644 index 0000000000000..cdcddb1960ccf --- /dev/null +++ b/types/src/account_config/resources/token.rs @@ -0,0 +1,71 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use crate::{account_config::Object, event::EventHandle}; +use move_core_types::{ + ident_str, + identifier::IdentStr, + move_resource::{MoveResource, MoveStructType}, +}; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Eq, PartialEq, Serialize, Deserialize)] +pub struct TokenResource { + pub collection: Object, + pub index: u64, + description: String, + name: String, + uri: String, + mutation_events: EventHandle, +} + +impl TokenResource { + pub fn new( + collection: Object, + index: u64, + description: String, + name: String, + uri: String, + mutation_events: EventHandle, + ) -> Self { + Self { + collection, + index, + description, + name, + uri, + mutation_events, + } + } + + pub fn collection(&self) -> &Object { + &self.collection + } + + pub fn index(&self) -> &u64 { + &self.index + } + + pub fn description(&self) -> &String { + &self.description + } + + pub fn name(&self) -> &String { + &self.name + } + + pub fn uri(&self) -> &String { + &self.uri + } + + pub fn mutation_events(&self) -> &EventHandle { + &self.mutation_events + } +} + +impl MoveStructType for TokenResource { + const MODULE_NAME: &'static IdentStr = ident_str!("token"); + const STRUCT_NAME: &'static IdentStr = ident_str!("Token"); +} + +impl MoveResource for TokenResource {} diff --git a/types/src/account_config/resources/token_event_store_v1.rs b/types/src/account_config/resources/token_event_store_v1.rs new file mode 100644 index 0000000000000..70f0d63d5b6bf --- /dev/null +++ b/types/src/account_config/resources/token_event_store_v1.rs @@ -0,0 +1,99 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use crate::{account_config::AnyResource, event::EventHandle}; +use move_core_types::{ + ident_str, + identifier::IdentStr, + move_resource::{MoveResource, MoveStructType}, +}; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize)] +pub struct TokenEventStoreV1Resource { + collection_uri_mutate_events: EventHandle, + collection_maximum_mutate_events: EventHandle, + collection_description_mutate_events: EventHandle, + opt_in_events: EventHandle, + uri_mutate_events: EventHandle, + default_property_mutate_events: EventHandle, + description_mutate_events: EventHandle, + royalty_mutate_events: EventHandle, + maximum_mutate_events: EventHandle, + extension: Option, +} + +impl TokenEventStoreV1Resource { + pub fn new( + collection_uri_mutate_events: EventHandle, + collection_maximum_mutate_events: EventHandle, + collection_description_mutate_events: EventHandle, + opt_in_events: EventHandle, + uri_mutate_events: EventHandle, + default_property_mutate_events: EventHandle, + description_mutate_events: EventHandle, + royalty_mutate_events: EventHandle, + maximum_mutate_events: EventHandle, + extension: Option, + ) -> Self { + Self { + collection_uri_mutate_events, + collection_maximum_mutate_events, + collection_description_mutate_events, + opt_in_events, + uri_mutate_events, + default_property_mutate_events, + description_mutate_events, + royalty_mutate_events, + maximum_mutate_events, + extension, + } + } + + pub fn collection_uri_mutate_events(&self) -> &EventHandle { + &self.collection_uri_mutate_events + } + + pub fn collection_maximum_mutate_events(&self) -> &EventHandle { + &self.collection_maximum_mutate_events + } + + pub fn collection_description_mutate_events(&self) -> &EventHandle { + &self.collection_description_mutate_events + } + + pub fn opt_in_events(&self) -> &EventHandle { + &self.opt_in_events + } + + pub fn uri_mutate_events(&self) -> &EventHandle { + &self.uri_mutate_events + } + + pub fn default_property_mutate_events(&self) -> &EventHandle { + &self.default_property_mutate_events + } + + pub fn description_mutate_events(&self) -> &EventHandle { + &self.description_mutate_events + } + + pub fn royalty_mutate_events(&self) -> &EventHandle { + &self.royalty_mutate_events + } + + pub fn maximum_mutate_events(&self) -> &EventHandle { + &self.maximum_mutate_events + } + + pub fn extension(&self) -> &Option { + &self.extension + } +} + +impl MoveStructType for TokenEventStoreV1Resource { + const MODULE_NAME: &'static IdentStr = ident_str!("token_event_store"); + const STRUCT_NAME: &'static IdentStr = ident_str!("TokenEventStoreV1"); +} + +impl MoveResource for TokenEventStoreV1Resource {} diff --git a/types/src/account_config/resources/token_store.rs b/types/src/account_config/resources/token_store.rs new file mode 100644 index 0000000000000..a24f938ecb16c --- /dev/null +++ b/types/src/account_config/resources/token_store.rs @@ -0,0 +1,77 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use crate::event::EventHandle; +use move_core_types::{ + account_address::AccountAddress, + ident_str, + identifier::IdentStr, + move_resource::{MoveResource, MoveStructType}, +}; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize)] +pub struct TokenStoreResource { + tokens: Table, + direct_transfer: bool, + deposit_events: EventHandle, + withdraw_events: EventHandle, + burn_events: EventHandle, + mutate_token_property_events: EventHandle, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct Table { + handle: AccountAddress, +} + +impl TokenStoreResource { + pub fn new( + tokens: Table, + direct_transfer: bool, + deposit_events: EventHandle, + withdraw_events: EventHandle, + burn_events: EventHandle, + mutate_token_property_events: EventHandle, + ) -> Self { + Self { + tokens, + direct_transfer, + deposit_events, + withdraw_events, + burn_events, + mutate_token_property_events, + } + } + + pub fn tokens(&self) -> &Table { + &self.tokens + } + + pub fn direct_transfer(&self) -> bool { + self.direct_transfer + } + + pub fn deposit_events(&self) -> &EventHandle { + &self.deposit_events + } + + pub fn withdraw_events(&self) -> &EventHandle { + &self.withdraw_events + } + + pub fn burn_events(&self) -> &EventHandle { + &self.burn_events + } + + pub fn mutate_token_property_events(&self) -> &EventHandle { + &self.mutate_token_property_events + } +} + +impl MoveStructType for TokenStoreResource { + const MODULE_NAME: &'static IdentStr = ident_str!("token"); + const STRUCT_NAME: &'static IdentStr = ident_str!("TokenStore"); +} + +impl MoveResource for TokenStoreResource {} diff --git a/types/src/account_config/resources/type_info.rs b/types/src/account_config/resources/type_info.rs index aa4328e17cb06..230ee46646a01 100644 --- a/types/src/account_config/resources/type_info.rs +++ b/types/src/account_config/resources/type_info.rs @@ -1,25 +1,43 @@ // Copyright © Aptos Foundation // SPDX-License-Identifier: Apache-2.0 +use anyhow::Result; use move_core_types::{ account_address::AccountAddress, ident_str, identifier::IdentStr, + language_storage::{StructTag, TypeTag, CORE_CODE_ADDRESS}, move_resource::{MoveResource, MoveStructType}, }; +use once_cell::sync::Lazy; use serde::{Deserialize, Serialize}; /// A Rust representation of TypeInfo. -#[derive(Debug, Eq, PartialEq, Serialize, Deserialize)] +#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] pub struct TypeInfoResource { pub account_address: AccountAddress, pub module_name: Vec, pub struct_name: Vec, } +impl TypeInfoResource { + pub fn try_from_bytes(bytes: &[u8]) -> Result { + bcs::from_bytes(bytes).map_err(Into::into) + } +} + impl MoveStructType for TypeInfoResource { const MODULE_NAME: &'static IdentStr = ident_str!("type_info"); const STRUCT_NAME: &'static IdentStr = ident_str!("TypeInfo"); } impl MoveResource for TypeInfoResource {} + +pub static TYPE_INFO_RESOURCE_TYPE: Lazy = Lazy::new(|| { + TypeTag::Struct(Box::new(StructTag { + address: CORE_CODE_ADDRESS, + module: ident_str!("type_info").to_owned(), + name: ident_str!("TypeInfo").to_owned(), + type_args: vec![], + })) +}); diff --git a/types/src/account_config/resources/unlimited_supply.rs b/types/src/account_config/resources/unlimited_supply.rs new file mode 100644 index 0000000000000..843623e75202f --- /dev/null +++ b/types/src/account_config/resources/unlimited_supply.rs @@ -0,0 +1,57 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use crate::event::EventHandle; +use move_core_types::{ + ident_str, + identifier::IdentStr, + move_resource::{MoveResource, MoveStructType}, +}; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Eq, PartialEq, Serialize, Deserialize)] +pub struct UnlimitedSupplyResource { + current_supply: u64, + total_minted: u64, + burn_events: EventHandle, + mint_events: EventHandle, +} + +impl UnlimitedSupplyResource { + pub fn new( + current_supply: u64, + total_minted: u64, + burn_events: EventHandle, + mint_events: EventHandle, + ) -> Self { + Self { + current_supply, + total_minted, + burn_events, + mint_events, + } + } + + pub fn current_supply(&self) -> u64 { + self.current_supply + } + + pub fn total_minted(&self) -> u64 { + self.total_minted + } + + pub fn burn_events(&self) -> &EventHandle { + &self.burn_events + } + + pub fn mint_events(&self) -> &EventHandle { + &self.mint_events + } +} + +impl MoveStructType for UnlimitedSupplyResource { + const MODULE_NAME: &'static IdentStr = ident_str!("collection"); + const STRUCT_NAME: &'static IdentStr = ident_str!("UnlimitedSupply"); +} + +impl MoveResource for UnlimitedSupplyResource {} diff --git a/types/src/contract_event.rs b/types/src/contract_event.rs index a89e3d88a9f26..52647747eb6a7 100644 --- a/types/src/contract_event.rs +++ b/types/src/contract_event.rs @@ -169,6 +169,7 @@ impl ContractEvent { /// Entry produced via a call to the `emit_event` builtin. #[derive(Hash, Clone, Eq, PartialEq, Serialize, Deserialize, CryptoHasher)] +#[cfg_attr(any(test, feature = "fuzzing"), derive(Arbitrary))] pub struct ContractEventV1 { /// The unique key that the event was emitted to key: EventKey, diff --git a/types/src/indexer/indexer_db_reader.rs b/types/src/indexer/indexer_db_reader.rs index 0ab962c826374..ddd68f108b17b 100644 --- a/types/src/indexer/indexer_db_reader.rs +++ b/types/src/indexer/indexer_db_reader.rs @@ -3,7 +3,7 @@ use crate::{ account_address::AccountAddress, - contract_event::EventWithVersion, + contract_event::{ContractEventV1, ContractEventV2, EventWithVersion}, event::EventKey, state_store::{ state_key::{prefix::StateKeyPrefix, StateKey}, @@ -73,4 +73,11 @@ pub trait IndexerReader: Send + Sync { Ok(()) } + fn get_translated_v1_event_by_version_and_index( + &self, + version: Version, + index: u64, + ) -> Result; + + fn translate_event_v2_to_v1(&self, v2: &ContractEventV2) -> Result>; } diff --git a/types/src/state_store/mod.rs b/types/src/state_store/mod.rs index 7456b439d6287..1121b553c1eba 100644 --- a/types/src/state_store/mod.rs +++ b/types/src/state_store/mod.rs @@ -13,8 +13,10 @@ use aptos_crypto::HashValue; use bytes::Bytes; use move_core_types::move_resource::MoveResource; #[cfg(any(test, feature = "testing"))] +use std::collections::HashMap; +#[cfg(any(test, feature = "testing"))] use std::hash::Hash; -use std::{collections::HashMap, ops::Deref}; +use std::ops::Deref; pub mod errors; pub mod state_key; diff --git a/types/src/utility_coin.rs b/types/src/utility_coin.rs index 625f63e823109..13e674fcb2465 100644 --- a/types/src/utility_coin.rs +++ b/types/src/utility_coin.rs @@ -43,3 +43,23 @@ impl MoveStructType for AptosCoinType { const MODULE_NAME: &'static IdentStr = ident_str!("aptos_coin"); const STRUCT_NAME: &'static IdentStr = ident_str!("AptosCoin"); } + +pub static DUMMY_COIN_TYPE: Lazy = Lazy::new(|| { + TypeTag::Struct(Box::new(StructTag { + address: AccountAddress::ONE, + module: ident_str!("dummy_coin").to_owned(), + name: ident_str!("DummyCoin").to_owned(), + type_args: vec![], + })) +}); + +pub struct DummyCoinType; +impl CoinType for DummyCoinType { + fn type_tag() -> TypeTag { + DUMMY_COIN_TYPE.clone() + } + + fn coin_info_address() -> AccountAddress { + AccountAddress::ONE + } +}