From 12422eaee99795859c9a6dff90e838c73d104339 Mon Sep 17 00:00:00 2001 From: Allan Rasmussen Date: Tue, 23 Dec 2025 14:47:36 +0100 Subject: [PATCH 1/6] query --- plt/plt-token-module/src/token_module.rs | 131 +++++++++++++++++----- plt/plt-token-module/tests/kernel_stub.rs | 6 +- 2 files changed, 108 insertions(+), 29 deletions(-) diff --git a/plt/plt-token-module/src/token_module.rs b/plt/plt-token-module/src/token_module.rs index 3cfb39141..1d6ad80df 100644 --- a/plt/plt-token-module/src/token_module.rs +++ b/plt/plt-token-module/src/token_module.rs @@ -2,15 +2,21 @@ //! use crate::token_kernel_interface::*; +use concordium_base::base::AccountIndex; +use concordium_base::common; use concordium_base::common::cbor; -use concordium_base::common::cbor::{SerializationOptions, UnknownMapKeys, cbor_encode}; +use concordium_base::common::cbor::{ + CborDeserialize, CborSerializationError, CborSerializationResult, SerializationOptions, + UnknownMapKeys, +}; use concordium_base::contracts_common::AccountAddress; use concordium_base::protocol_level_tokens::{ - RawCbor, TokenAmount, TokenModuleInitializationParameters, + CborHolderAccount, MetadataUrl, RawCbor, TokenAmount, TokenModuleInitializationParameters, + TokenModuleState, }; /// Extension trait for `TokenKernelOperations` to provide convenience wrappers for -/// module state access and updating. +/// module state updates. trait KernelOperationsExt: TokenKernelOperations { /// Set or clear a value in the token module state at the corresponding key. fn set_module_state<'a>( @@ -25,6 +31,17 @@ trait KernelOperationsExt: TokenKernelOperations { impl KernelOperationsExt for T {} +/// Extension trait for `TokenQueryOperations` to provide convenience wrappers for +/// module state access. +trait KernelQueriesExt: TokenKernelQueries { + /// Get value from the token module state at the given key. + fn get_module_state<'a>(&self, key: impl IntoIterator) -> Option { + self.get_token_state(module_state_key(key)) + } +} + +impl KernelQueriesExt for T {} + /// Little-endian prefix used to distinguish module state keys. const MODULE_STATE_PREFIX: [u8; 2] = 0u16.to_le_bytes(); @@ -43,6 +60,8 @@ fn module_state_key<'a>(key: impl IntoIterator) -> StateKey { pub enum TokenInitializationError { #[error("Invalid token initialization parameters: {0}")] InvalidInitializationParameters(String), + #[error("CBOR serialization error during token initialization: {0}")] + CborSerialization(#[from] CborSerializationError), #[error("{0}")] LockedStateKey(#[from] LockedStateKeyError), #[error("The given governance account does not exist: {0}")] @@ -55,11 +74,19 @@ pub enum TokenInitializationError { /// Represents the reasons why [`execute_token_update_transaction`] can fail. #[derive(Debug, thiserror::Error)] -pub enum TokenUpdateError {} +pub enum TokenUpdateError { + #[error("CBOR serialization error during token update: {0}")] + CborSerialization(#[from] CborSerializationError), +} /// Represents the reasons why a query to the token module can fail. -#[derive(Debug)] -pub enum TokenQueryError {} +#[derive(Debug, thiserror::Error)] +pub enum TokenQueryError { + #[error("CBOR serialization error during token query: {0}")] + CborSerialization(#[from] CborSerializationError), + #[error("Token module state invariant broken: {0}")] + StateInvariantViolation(String), +} /// The context for a token-holder or token-governance transaction. #[derive(Debug)] @@ -99,26 +126,24 @@ const STATE_KEY_ALLOW_LIST: &[u8] = b"allowList"; const STATE_KEY_DENY_LIST: &[u8] = b"denyList"; const STATE_KEY_MINTABLE: &[u8] = b"mintable"; const STATE_KEY_BURNABLE: &[u8] = b"burnable"; +const STATE_KEY_PAUSED: &[u8] = b"paused"; const STATE_KEY_GOVERNANCE_ACCOUNT: &[u8] = b"governanceAccount"; +fn cbor_decode(cbor: impl AsRef<[u8]>) -> CborSerializationResult { + let decode_options = SerializationOptions { + unknown_map_keys: UnknownMapKeys::Fail, + }; + cbor::cbor_decode_with_options(cbor, decode_options) +} + /// Initialize a PLT by recording the relevant configuration parameters in the state and /// (if necessary) minting the initial supply to the token governance account. pub fn initialize_token( host: &mut impl TokenKernelOperations, initialization_parameters_cbor: RawCbor, ) -> Result<(), TokenInitializationError> { - let decode_options = SerializationOptions { - unknown_map_keys: UnknownMapKeys::Fail, - }; let init_params: TokenModuleInitializationParameters = - cbor::cbor_decode_with_options(initialization_parameters_cbor, decode_options).map_err( - |err| { - TokenInitializationError::InvalidInitializationParameters(format!( - "Error decoding token initialization parameters: {}", - err - )) - }, - )?; + cbor_decode(initialization_parameters_cbor)?; if !init_params.additional.is_empty() { return Err(TokenInitializationError::InvalidInitializationParameters( format!( @@ -148,12 +173,7 @@ pub fn initialize_token( ) })?; host.set_module_state(STATE_KEY_NAME, Some(name.into()))?; - let encoded_metadata = cbor_encode(&metadata).map_err(|err| { - TokenInitializationError::InvalidInitializationParameters(format!( - "Error encoding token metadata: {}", - err - )) - })?; + let encoded_metadata = cbor::cbor_encode(&metadata)?; host.set_module_state(STATE_KEY_METADATA, Some(encoded_metadata))?; if init_params.allow_list == Some(true) { host.set_module_state(STATE_KEY_ALLOW_LIST, Some(vec![]))?; @@ -174,7 +194,7 @@ pub fn initialize_token( let governance_account_index = host.account_index(&governance_account); host.set_module_state( STATE_KEY_GOVERNANCE_ACCOUNT, - Some(governance_account_index.index.to_be_bytes().to_vec()), + Some(common::to_bytes(&governance_account_index.index)), )?; if let Some(initial_supply) = init_params.initial_supply { let mint_amount = to_token_raw_amount(initial_supply, host.decimals())?; @@ -239,9 +259,68 @@ pub fn execute_token_update_transaction( /// Get the CBOR-encoded representation of the token module state. pub fn query_token_module_state( - _kernel: &impl TokenKernelQueries, + kernel: &impl TokenKernelQueries, ) -> Result { - todo!() + let name = kernel + .get_module_state(STATE_KEY_NAME) + .ok_or_else(|| TokenQueryError::StateInvariantViolation("Name not present".to_string())) + .and_then(|value| { + String::from_utf8(value).map_err(|err| { + TokenQueryError::StateInvariantViolation(format!("Name invalid UTF8: {}", err)) + }) + })?; + + let metadata_cbor = kernel.get_module_state(STATE_KEY_METADATA).ok_or_else(|| { + TokenQueryError::StateInvariantViolation("Metadata not present".to_string()) + })?; + let metadata: MetadataUrl = cbor_decode(metadata_cbor)?; + + let allow_list = kernel.get_module_state(STATE_KEY_ALLOW_LIST).is_some(); + let deny_list = kernel.get_module_state(STATE_KEY_DENY_LIST).is_some(); + let mintable = kernel.get_module_state(STATE_KEY_MINTABLE).is_some(); + let burnable = kernel.get_module_state(STATE_KEY_BURNABLE).is_some(); + let paused = kernel.get_module_state(STATE_KEY_PAUSED).is_some(); + + let governance_account_index = AccountIndex::from( + kernel + .get_module_state(STATE_KEY_GOVERNANCE_ACCOUNT) + .ok_or_else(|| { + TokenQueryError::StateInvariantViolation( + "Governance account not present".to_string(), + ) + }) + .and_then(|value| { + common::from_bytes::(&mut value.as_slice()).map_err(|err| { + TokenQueryError::StateInvariantViolation(format!( + "Governance account index cannot be decoded: {}", + err + )) + }) + })?, + ); + let governance_account = kernel + .account_by_index(governance_account_index) + .ok_or_else(|| { + TokenQueryError::StateInvariantViolation(format!( + "Governance account with index {} does not exist", + governance_account_index + )) + })?; + let governance_account_address = kernel.account_canonical_address(&governance_account); + + let state = TokenModuleState { + name: Some(name), + metadata: Some(metadata), + governance_account: Some(CborHolderAccount::from(governance_account_address)), + allow_list: Some(allow_list), + deny_list: Some(deny_list), + mintable: Some(mintable), + burnable: Some(burnable), + paused: Some(paused), + additional: Default::default(), + }; + + Ok(RawCbor::from(cbor::cbor_encode(&state)?)) } /// Get the CBOR-encoded representation of the token module account state. diff --git a/plt/plt-token-module/tests/kernel_stub.rs b/plt/plt-token-module/tests/kernel_stub.rs index 753fbb508..07d8d017c 100644 --- a/plt/plt-token-module/tests/kernel_stub.rs +++ b/plt/plt-token-module/tests/kernel_stub.rs @@ -5,8 +5,8 @@ use concordium_base::contracts_common::AccountAddress; use concordium_base::protocol_level_tokens::TokenModuleEventType; use concordium_base::transactions::Memo; use plt_token_module::token_kernel_interface::{ - AmountNotRepresentableError, InsufficientBalanceError, LockedStateKeyError, RawTokenAmount, - StateKey, StateValue, TokenKernelOperations, TokenKernelQueries, + AmountNotRepresentableError, InsufficientBalanceError, LockedStateKeyError, OutOfEnergyError, + RawTokenAmount, StateKey, StateValue, TokenKernelOperations, TokenKernelQueries, }; /// Token kernel stub providing an implementation of [`TokenKernelOperations`] and methods for @@ -193,7 +193,7 @@ impl TokenKernelOperations for KernelStub { Ok(res) } - fn tick_energy(&mut self, _energy: Energy) { + fn tick_energy(&mut self, _energy: Energy) -> Result<(), OutOfEnergyError> { todo!() } From c3fd73799b07e955edb4fe779ed698ce65e668d9 Mon Sep 17 00:00:00 2001 From: Allan Rasmussen Date: Tue, 23 Dec 2025 15:14:44 +0100 Subject: [PATCH 2/6] test --- plt/Cargo.lock | 3 +- plt/plt-token-module/src/token_module.rs | 4 +-- .../tests/token_module_initialize.rs | 28 +++++++++++++++---- 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/plt/Cargo.lock b/plt/Cargo.lock index 9da4daa04..2a8cda7fa 100644 --- a/plt/Cargo.lock +++ b/plt/Cargo.lock @@ -371,7 +371,7 @@ dependencies = [ [[package]] name = "concordium_base" -version = "8.0.0-alpha.3" +version = "10.0.0-alpha.0" dependencies = [ "anyhow", "ark-bls12-381", @@ -391,6 +391,7 @@ dependencies = [ "ed25519-dalek", "either", "ff", + "generic-array", "hex", "itertools 0.14.0", "leb128", diff --git a/plt/plt-token-module/src/token_module.rs b/plt/plt-token-module/src/token_module.rs index 1d6ad80df..85da057df 100644 --- a/plt/plt-token-module/src/token_module.rs +++ b/plt/plt-token-module/src/token_module.rs @@ -259,7 +259,7 @@ pub fn execute_token_update_transaction( /// Get the CBOR-encoded representation of the token module state. pub fn query_token_module_state( - kernel: &impl TokenKernelQueries, + kernel: &Kernel, ) -> Result { let name = kernel .get_module_state(STATE_KEY_NAME) @@ -325,7 +325,7 @@ pub fn query_token_module_state( /// Get the CBOR-encoded representation of the token module account state. pub fn query_account_state( - _kernel: &impl TokenKernelQueries, + _kernel: &Kernel, _account: Kernel::Account, ) -> Result, TokenQueryError> { todo!() diff --git a/plt/plt-token-module/tests/token_module_initialize.rs b/plt/plt-token-module/tests/token_module_initialize.rs index fc4cf8e7b..97eed89af 100644 --- a/plt/plt-token-module/tests/token_module_initialize.rs +++ b/plt/plt-token-module/tests/token_module_initialize.rs @@ -3,6 +3,7 @@ use std::collections::HashMap; use assert_matches::assert_matches; use concordium_base::common::cbor; use concordium_base::contracts_common::AccountAddress; +use concordium_base::protocol_level_tokens::{CborHolderAccount, MetadataUrl, TokenModuleState}; use concordium_base::{ common::cbor::value::Value, protocol_level_tokens::{TokenAmount, TokenModuleInitializationParameters}, @@ -87,12 +88,14 @@ fn test_initialize_token_additional_parameter() { fn test_initialize_token_default_values() { let mut stub = KernelStub::new(0); let gov_account = stub.create_account(); - let metadata = "https://plt.token".to_owned().into(); + let governance_holder_account = + CborHolderAccount::from(stub.account_canonical_address(&gov_account)); + let metadata = MetadataUrl::from("https://plt.token".to_string()); let encoded_metadata = cbor::cbor_encode(&metadata).unwrap(); let parameters = TokenModuleInitializationParameters { name: Some("Protocol-level token".to_owned()), - metadata: Some(metadata), - governance_account: Some(stub.account_canonical_address(&gov_account).into()), + metadata: Some(metadata.clone()), + governance_account: Some(governance_holder_account.clone()), allow_list: None, deny_list: None, initial_supply: None, @@ -102,23 +105,38 @@ fn test_initialize_token_default_values() { }; let encoded_parameters = cbor::cbor_encode(¶meters).unwrap().into(); token_module::initialize_token(&mut stub, encoded_parameters).unwrap(); + let mut expected_state = HashMap::with_capacity(3); expected_state.insert(b"\0\0name".into(), b"Protocol-level token".into()); expected_state.insert(b"\0\0metadata".into(), encoded_metadata); - expected_state.insert( b"\0\0governanceAccount".into(), stub.account_index(&gov_account).index.to_be_bytes().into(), ); assert_eq!(stub.state, expected_state); + + let state: TokenModuleState = + cbor::cbor_decode(token_module::query_token_module_state(&stub).unwrap()).unwrap(); + assert_eq!(state.name, Some("Protocol-level token".to_owned())); + assert_eq!(state.metadata, Some(metadata)); + assert_eq!(state.governance_account, Some(governance_holder_account)); + assert_eq!(state.allow_list, Some(false)); + assert_eq!(state.deny_list, Some(false)); + assert_eq!(state.mintable, Some(false)); + assert_eq!(state.burnable, Some(false)); + assert_eq!(state.paused, Some(false)); + assert!(state.additional.is_empty()); } +// todo ar write rest of tests +// todo ar trim down plt model in base + /// In this example, the parameters are valid, no minting. #[test] fn test_initialize_token_no_minting() { let mut stub = KernelStub::new(0); let gov_account = stub.create_account(); - let metadata = "https://plt.token".to_owned().into(); + let metadata = MetadataUrl::from("https://plt.token".to_string()); let encoded_metadata = cbor::cbor_encode(&metadata).unwrap(); let parameters = TokenModuleInitializationParameters { name: Some("Protocol-level token".to_owned()), From 7b6d23bbcd037eda6b856a32472af7e22e38cad5 Mon Sep 17 00:00:00 2001 From: Allan Rasmussen Date: Tue, 23 Dec 2025 15:17:22 +0100 Subject: [PATCH 3/6] todo --- concordium-base | 2 +- plt/plt-token-module/tests/token_module_initialize.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/concordium-base b/concordium-base index d0590c6d6..c541f6033 160000 --- a/concordium-base +++ b/concordium-base @@ -1 +1 @@ -Subproject commit d0590c6d67232d50342461075267b280c134daf2 +Subproject commit c541f603343df033625e44025d71789b731ba0e0 diff --git a/plt/plt-token-module/tests/token_module_initialize.rs b/plt/plt-token-module/tests/token_module_initialize.rs index 97eed89af..e67a7b5a4 100644 --- a/plt/plt-token-module/tests/token_module_initialize.rs +++ b/plt/plt-token-module/tests/token_module_initialize.rs @@ -128,7 +128,7 @@ fn test_initialize_token_default_values() { assert!(state.additional.is_empty()); } -// todo ar write rest of tests +// todo ar write rest of testsf // todo ar trim down plt model in base /// In this example, the parameters are valid, no minting. From fe0ee7b0a1d949f7e3ff4c1eafafe79f1a58b936 Mon Sep 17 00:00:00 2001 From: Allan Rasmussen Date: Tue, 23 Dec 2025 15:19:13 +0100 Subject: [PATCH 4/6] updatebase --- concordium-base | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/concordium-base b/concordium-base index c541f6033..ccabee1a8 160000 --- a/concordium-base +++ b/concordium-base @@ -1 +1 @@ -Subproject commit c541f603343df033625e44025d71789b731ba0e0 +Subproject commit ccabee1a8e3c3cec4ceeb4f3139ac7e6a32f67ec From deef081017355260987244a8f529c8038d4115fa Mon Sep 17 00:00:00 2001 From: Allan Rasmussen Date: Thu, 25 Dec 2025 17:10:54 +0100 Subject: [PATCH 5/6] test --- .../tests/token_module_initialize.rs | 60 ++++++++++++++----- 1 file changed, 44 insertions(+), 16 deletions(-) diff --git a/plt/plt-token-module/tests/token_module_initialize.rs b/plt/plt-token-module/tests/token_module_initialize.rs index e67a7b5a4..1564a937b 100644 --- a/plt/plt-token-module/tests/token_module_initialize.rs +++ b/plt/plt-token-module/tests/token_module_initialize.rs @@ -25,8 +25,10 @@ fn test_initialize_token_parameters_decode_failure() { let res = token_module::initialize_token(&mut stub, vec![].into()); assert_matches!( &res, - Err(TokenInitializationError::InvalidInitializationParameters(err)) - if err.contains("Error decoding token initialization parameters") + Err(TokenInitializationError::CborSerialization(err)) => { + let msg = err.to_string(); + assert!(msg.contains("IO error"), "msg: {}", msg); + } ); } @@ -88,14 +90,13 @@ fn test_initialize_token_additional_parameter() { fn test_initialize_token_default_values() { let mut stub = KernelStub::new(0); let gov_account = stub.create_account(); - let governance_holder_account = - CborHolderAccount::from(stub.account_canonical_address(&gov_account)); + let gov_holder_account = CborHolderAccount::from(stub.account_canonical_address(&gov_account)); let metadata = MetadataUrl::from("https://plt.token".to_string()); let encoded_metadata = cbor::cbor_encode(&metadata).unwrap(); let parameters = TokenModuleInitializationParameters { name: Some("Protocol-level token".to_owned()), metadata: Some(metadata.clone()), - governance_account: Some(governance_holder_account.clone()), + governance_account: Some(gov_holder_account.clone()), allow_list: None, deny_list: None, initial_supply: None, @@ -115,11 +116,12 @@ fn test_initialize_token_default_values() { ); assert_eq!(stub.state, expected_state); + assert_eq!(stub.account_balance(&gov_account), RawTokenAmount(0)); let state: TokenModuleState = cbor::cbor_decode(token_module::query_token_module_state(&stub).unwrap()).unwrap(); assert_eq!(state.name, Some("Protocol-level token".to_owned())); assert_eq!(state.metadata, Some(metadata)); - assert_eq!(state.governance_account, Some(governance_holder_account)); + assert_eq!(state.governance_account, Some(gov_holder_account)); assert_eq!(state.allow_list, Some(false)); assert_eq!(state.deny_list, Some(false)); assert_eq!(state.mintable, Some(false)); @@ -128,20 +130,18 @@ fn test_initialize_token_default_values() { assert!(state.additional.is_empty()); } -// todo ar write rest of testsf -// todo ar trim down plt model in base - /// In this example, the parameters are valid, no minting. #[test] fn test_initialize_token_no_minting() { let mut stub = KernelStub::new(0); let gov_account = stub.create_account(); + let gov_holder_account = CborHolderAccount::from(stub.account_canonical_address(&gov_account)); let metadata = MetadataUrl::from("https://plt.token".to_string()); let encoded_metadata = cbor::cbor_encode(&metadata).unwrap(); let parameters = TokenModuleInitializationParameters { name: Some("Protocol-level token".to_owned()), - metadata: Some(metadata), - governance_account: Some(stub.account_canonical_address(&gov_account).into()), + metadata: Some(metadata.clone()), + governance_account: Some(gov_holder_account.clone()), allow_list: Some(true), deny_list: Some(false), initial_supply: None, @@ -151,6 +151,7 @@ fn test_initialize_token_no_minting() { }; let encoded_parameters = cbor::cbor_encode(¶meters).unwrap().into(); token_module::initialize_token(&mut stub, encoded_parameters).unwrap(); + let mut expected_state = HashMap::with_capacity(3); expected_state.insert(b"\0\0name".into(), b"Protocol-level token".into()); expected_state.insert(b"\0\0metadata".into(), encoded_metadata); @@ -162,19 +163,33 @@ fn test_initialize_token_no_minting() { expected_state.insert(b"\0\0mintable".into(), vec![]); expected_state.insert(b"\0\0burnable".into(), vec![]); assert_eq!(stub.state, expected_state); + + assert_eq!(stub.account_balance(&gov_account), RawTokenAmount(0)); + let state: TokenModuleState = + cbor::cbor_decode(token_module::query_token_module_state(&stub).unwrap()).unwrap(); + assert_eq!(state.name, Some("Protocol-level token".to_owned())); + assert_eq!(state.metadata, Some(metadata)); + assert_eq!(state.governance_account, Some(gov_holder_account)); + assert_eq!(state.allow_list, Some(true)); + assert_eq!(state.deny_list, Some(false)); + assert_eq!(state.mintable, Some(true)); + assert_eq!(state.burnable, Some(true)); + assert_eq!(state.paused, Some(false)); + assert!(state.additional.is_empty()); } /// In this example, the parameters are valid, with minting. #[test] -fn test_initialize_token_valid_2() { +fn test_initialize_token_with_minting() { let mut stub = KernelStub::new(2); let gov_account = stub.create_account(); - let metadata = "https://plt.token".to_owned().into(); + let gov_holder_account = CborHolderAccount::from(stub.account_canonical_address(&gov_account)); + let metadata = MetadataUrl::from("https://plt.token".to_string()); let encoded_metadata = cbor::cbor_encode(&metadata).unwrap(); let parameters = TokenModuleInitializationParameters { name: Some("Protocol-level token".to_owned()), - metadata: Some(metadata), - governance_account: Some(stub.account_canonical_address(&gov_account).into()), + metadata: Some(metadata.clone()), + governance_account: Some(gov_holder_account.clone()), allow_list: Some(false), deny_list: Some(true), initial_supply: Some(TokenAmount::from_raw(500000, 2)), @@ -184,7 +199,7 @@ fn test_initialize_token_valid_2() { }; let encoded_parameters = cbor::cbor_encode(¶meters).unwrap().into(); token_module::initialize_token(&mut stub, encoded_parameters).unwrap(); - assert_eq!(stub.account_balance(&gov_account), RawTokenAmount(500000)); + let mut expected_state = HashMap::with_capacity(3); expected_state.insert(b"\0\0name".into(), b"Protocol-level token".into()); expected_state.insert(b"\0\0metadata".into(), encoded_metadata); @@ -194,6 +209,19 @@ fn test_initialize_token_valid_2() { ); expected_state.insert(b"\0\0denyList".into(), vec![]); assert_eq!(stub.state, expected_state); + + assert_eq!(stub.account_balance(&gov_account), RawTokenAmount(500000)); + let state: TokenModuleState = + cbor::cbor_decode(token_module::query_token_module_state(&stub).unwrap()).unwrap(); + assert_eq!(state.name, Some("Protocol-level token".to_owned())); + assert_eq!(state.metadata, Some(metadata)); + assert_eq!(state.governance_account, Some(gov_holder_account)); + assert_eq!(state.allow_list, Some(false)); + assert_eq!(state.deny_list, Some(true)); + assert_eq!(state.mintable, Some(false)); + assert_eq!(state.burnable, Some(false)); + assert_eq!(state.paused, Some(false)); + assert!(state.additional.is_empty()); } /// In this example, the parameters specify an initial supply with higher precision From af4cd7d0d2ab9ea73b5a451839c6d6247b8a123c Mon Sep 17 00:00:00 2001 From: Allan Rasmussen Date: Thu, 25 Dec 2025 17:29:49 +0100 Subject: [PATCH 6/6] fmt --- plt/plt-token-module/tests/kernel_stub.rs | 3 +- .../tests/token_module_initialize.rs | 85 +++++++++++++------ 2 files changed, 59 insertions(+), 29 deletions(-) diff --git a/plt/plt-token-module/tests/kernel_stub.rs b/plt/plt-token-module/tests/kernel_stub.rs index 07d8d017c..3412f080a 100644 --- a/plt/plt-token-module/tests/kernel_stub.rs +++ b/plt/plt-token-module/tests/kernel_stub.rs @@ -16,9 +16,10 @@ pub struct KernelStub { /// List of accounts existing. accounts: Vec, /// Token managed state. - pub state: HashMap, + state: HashMap, /// Decimal places in token representation. decimals: u8, + /// Counter for creating accounts in the stub next_account_index: AccountIndex, } diff --git a/plt/plt-token-module/tests/token_module_initialize.rs b/plt/plt-token-module/tests/token_module_initialize.rs index 1564a937b..9b70a85c1 100644 --- a/plt/plt-token-module/tests/token_module_initialize.rs +++ b/plt/plt-token-module/tests/token_module_initialize.rs @@ -107,16 +107,27 @@ fn test_initialize_token_default_values() { let encoded_parameters = cbor::cbor_encode(¶meters).unwrap().into(); token_module::initialize_token(&mut stub, encoded_parameters).unwrap(); - let mut expected_state = HashMap::with_capacity(3); - expected_state.insert(b"\0\0name".into(), b"Protocol-level token".into()); - expected_state.insert(b"\0\0metadata".into(), encoded_metadata); - expected_state.insert( - b"\0\0governanceAccount".into(), - stub.account_index(&gov_account).index.to_be_bytes().into(), + // assertions directly on token state + assert_eq!( + stub.get_token_state(b"\0\0name".into()), + Some(b"Protocol-level token".into()) ); - assert_eq!(stub.state, expected_state); - + assert_eq!( + stub.get_token_state(b"\0\0metadata".into()), + Some(encoded_metadata) + ); + assert_eq!( + stub.get_token_state(b"\0\0governanceAccount".into()), + Some(stub.account_index(&gov_account).index.to_be_bytes().into()) + ); + assert_eq!(stub.get_token_state(b"\0\0allowList".into()), None); + assert_eq!(stub.get_token_state(b"\0\0denyList".into()), None); + assert_eq!(stub.get_token_state(b"\0\0mintable".into()), None); + assert_eq!(stub.get_token_state(b"\0\0burnable".into()), None); + assert_eq!(stub.get_token_state(b"\0\0paused".into()), None); + // assert governance account balance assert_eq!(stub.account_balance(&gov_account), RawTokenAmount(0)); + // assertions using token module state query let state: TokenModuleState = cbor::cbor_decode(token_module::query_token_module_state(&stub).unwrap()).unwrap(); assert_eq!(state.name, Some("Protocol-level token".to_owned())); @@ -152,19 +163,27 @@ fn test_initialize_token_no_minting() { let encoded_parameters = cbor::cbor_encode(¶meters).unwrap().into(); token_module::initialize_token(&mut stub, encoded_parameters).unwrap(); - let mut expected_state = HashMap::with_capacity(3); - expected_state.insert(b"\0\0name".into(), b"Protocol-level token".into()); - expected_state.insert(b"\0\0metadata".into(), encoded_metadata); - expected_state.insert( - b"\0\0governanceAccount".into(), - stub.account_index(&gov_account).index.to_be_bytes().into(), + // assertions directly on token state + assert_eq!( + stub.get_token_state(b"\0\0name".into()), + Some(b"Protocol-level token".into()) ); - expected_state.insert(b"\0\0allowList".into(), vec![]); - expected_state.insert(b"\0\0mintable".into(), vec![]); - expected_state.insert(b"\0\0burnable".into(), vec![]); - assert_eq!(stub.state, expected_state); - + assert_eq!( + stub.get_token_state(b"\0\0metadata".into()), + Some(encoded_metadata) + ); + assert_eq!( + stub.get_token_state(b"\0\0governanceAccount".into()), + Some(stub.account_index(&gov_account).index.to_be_bytes().into()) + ); + assert_eq!(stub.get_token_state(b"\0\0allowList".into()), Some(vec![])); + assert_eq!(stub.get_token_state(b"\0\0denyList".into()), None); + assert_eq!(stub.get_token_state(b"\0\0mintable".into()), Some(vec![])); + assert_eq!(stub.get_token_state(b"\0\0burnable".into()), Some(vec![])); + assert_eq!(stub.get_token_state(b"\0\0paused".into()), None); + // assert governance account balance assert_eq!(stub.account_balance(&gov_account), RawTokenAmount(0)); + // assertions using token module state query let state: TokenModuleState = cbor::cbor_decode(token_module::query_token_module_state(&stub).unwrap()).unwrap(); assert_eq!(state.name, Some("Protocol-level token".to_owned())); @@ -200,17 +219,27 @@ fn test_initialize_token_with_minting() { let encoded_parameters = cbor::cbor_encode(¶meters).unwrap().into(); token_module::initialize_token(&mut stub, encoded_parameters).unwrap(); - let mut expected_state = HashMap::with_capacity(3); - expected_state.insert(b"\0\0name".into(), b"Protocol-level token".into()); - expected_state.insert(b"\0\0metadata".into(), encoded_metadata); - expected_state.insert( - b"\0\0governanceAccount".into(), - stub.account_index(&gov_account).index.to_be_bytes().into(), + // assertions directly on token state + assert_eq!( + stub.get_token_state(b"\0\0name".into()), + Some(b"Protocol-level token".into()) ); - expected_state.insert(b"\0\0denyList".into(), vec![]); - assert_eq!(stub.state, expected_state); - + assert_eq!( + stub.get_token_state(b"\0\0metadata".into()), + Some(encoded_metadata) + ); + assert_eq!( + stub.get_token_state(b"\0\0governanceAccount".into()), + Some(stub.account_index(&gov_account).index.to_be_bytes().into()) + ); + assert_eq!(stub.get_token_state(b"\0\0allowList".into()), None); + assert_eq!(stub.get_token_state(b"\0\0denyList".into()), Some(vec![])); + assert_eq!(stub.get_token_state(b"\0\0mintable".into()), None); + assert_eq!(stub.get_token_state(b"\0\0burnable".into()), None); + assert_eq!(stub.get_token_state(b"\0\0paused".into()), None); + // assert governance account balance assert_eq!(stub.account_balance(&gov_account), RawTokenAmount(500000)); + // assertions using token module state query let state: TokenModuleState = cbor::cbor_decode(token_module::query_token_module_state(&stub).unwrap()).unwrap(); assert_eq!(state.name, Some("Protocol-level token".to_owned()));