Skip to content

Commit

Permalink
test: assert events emitted from contract (#216)
Browse files Browse the repository at this point in the history
Co-authored-by: Daanvdplas <daanvdplas@live.nl>
Co-authored-by: Peter White <petras9789@gmail.com>
  • Loading branch information
3 people authored Sep 13, 2024
1 parent a81c8b4 commit bf27640
Show file tree
Hide file tree
Showing 10 changed files with 126 additions and 31 deletions.
2 changes: 1 addition & 1 deletion pop-api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ version = "0.0.0"
[dependencies]
ink = { version = "5.0.0", default-features = false }
pop-primitives = { path = "../primitives", default-features = false }
sp-io = { version = "31.0.0", default-features = false, features = [
sp-io = { version = "37.0.0", default-features = false, features = [
"disable_allocator",
"disable_oom",
"disable_panic_handler",
Expand Down
5 changes: 4 additions & 1 deletion pop-api/integration-tests/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ log = "0.4.22"
pallet-assets = { version = "37.0.0", default-features = false }
pallet-balances = { version = "37.0.0", default-features = false }
pallet-contracts = { version = "35.0.0", default-features = false }
pop-api = { path = "../../pop-api", default-features = false, features = [
"fungibles",
] }
pop-primitives = { path = "../../primitives", default-features = false }
pop-runtime-devnet = { path = "../../runtime/devnet", default-features = false }
scale = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = [
Expand All @@ -24,7 +27,6 @@ scale = { package = "parity-scale-codec", version = "3.6.12", default-features =
sp-io = { version = "37.0.0", default-features = false }
sp-runtime = { version = "=38.0.0", default-features = false }


[features]
default = [ "std" ]
std = [
Expand All @@ -33,6 +35,7 @@ std = [
"pallet-assets/std",
"pallet-balances/std",
"pallet-contracts/std",
"pop-api/std",
"pop-primitives/std",
"pop-runtime-devnet/std",
"scale/std",
Expand Down
9 changes: 5 additions & 4 deletions pop-api/integration-tests/build.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
use contract_build::{
execute, BuildArtifacts, BuildMode, BuildResult, ExecuteArgs, ManifestPath, OutputType,
Verbosity,
};
use std::{
fs,
path::{Path, PathBuf},
process,
};

use contract_build::{
execute, BuildArtifacts, BuildMode, BuildResult, ExecuteArgs, ManifestPath, OutputType,
Verbosity,
};

fn main() {
let contracts_dir = PathBuf::from("./contracts/");
let contract_dirs = match get_subcontract_directories(&contracts_dir) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#![cfg_attr(not(feature = "std"), no_std, no_main)]

use pop_api::{
fungibles::{self as api},
fungibles::{self as api, events::Created},
primitives::TokenId,
StatusCode,
};
Expand All @@ -14,22 +14,23 @@ mod create_token_in_constructor {

#[ink(storage)]
pub struct Fungible {
id: TokenId,
token: TokenId,
}

impl Fungible {
#[ink(constructor, payable)]
pub fn new(id: TokenId, min_balance: Balance) -> Result<Self> {
let contract = Self { id };
let contract = Self { token: id };
// AccountId of the contract which will be set to the owner of the fungible token.
let owner = contract.env().account_id();
api::create(id, owner, min_balance)?;
contract.env().emit_event(Created { id, creator: owner, admin: owner });
Ok(contract)
}

#[ink(message)]
pub fn token_exists(&self) -> Result<bool> {
api::token_exists(self.id)
api::token_exists(self.token)
}
}
}
47 changes: 37 additions & 10 deletions pop-api/integration-tests/contracts/fungibles/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@
/// 4. PSP-22 Mintable & Burnable
use ink::prelude::vec::Vec;
use pop_api::{
fungibles::{self as api},
fungibles::{
self as api,
events::{Approval, Created, DestroyStarted, MetadataCleared, MetadataSet, Transfer},
},
primitives::TokenId,
StatusCode,
};
Expand Down Expand Up @@ -60,7 +63,13 @@ mod fungibles {

#[ink(message)]
pub fn transfer(&mut self, token: TokenId, to: AccountId, value: Balance) -> Result<()> {
api::transfer(token, to, value)
api::transfer(token, to, value)?;
self.env().emit_event(Transfer {
from: Some(self.env().account_id()),
to: Some(to),
value,
});
Ok(())
}

#[ink(message)]
Expand All @@ -73,12 +82,22 @@ mod fungibles {
// In the PSP-22 standard a `[u8]`, but the size needs to be known at compile time.
_data: Vec<u8>,
) -> Result<()> {
api::transfer_from(token, from, to, value)
api::transfer_from(token, from, to, value)?;
self.env().emit_event(Transfer { from: Some(from), to: Some(to), value });
Ok(())
}

#[ink(message)]
pub fn approve(&mut self, token: TokenId, spender: AccountId, value: Balance) -> Result<()> {
api::approve(token, spender, value)
pub fn approve(
&mut self,
token: TokenId,
spender: AccountId,
value: Balance,
) -> Result<()> {
api::approve(token, spender, value)?;
self.env()
.emit_event(Approval { owner: self.env().account_id(), spender, value });
Ok(())
}

#[ink(message)]
Expand Down Expand Up @@ -135,12 +154,16 @@ mod fungibles {
admin: AccountId,
min_balance: Balance,
) -> Result<()> {
api::create(id, admin, min_balance)
api::create(id, admin, min_balance)?;
self.env().emit_event(Created { id, creator: admin, admin });
Ok(())
}

#[ink(message)]
pub fn start_destroy(&mut self, token: TokenId) -> Result<()> {
api::start_destroy(token)
api::start_destroy(token)?;
self.env().emit_event(DestroyStarted { token });
Ok(())
}

#[ink(message)]
Expand All @@ -151,12 +174,16 @@ mod fungibles {
symbol: Vec<u8>,
decimals: u8,
) -> Result<()> {
api::set_metadata(token, name, symbol, decimals)
api::set_metadata(token, name.clone(), symbol.clone(), decimals)?;
self.env().emit_event(MetadataSet { token, name, symbol, decimals });
Ok(())
}

#[ink(message)]
pub fn clear_metadata(&self, token: TokenId) -> Result<()> {
api::clear_metadata(token)
pub fn clear_metadata(&mut self, token: TokenId) -> Result<()> {
api::clear_metadata(token)?;
self.env().emit_event(MetadataCleared { token });
Ok(())
}

#[ink(message)]
Expand Down
50 changes: 46 additions & 4 deletions pop-api/integration-tests/src/fungibles/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
use pop_api::fungibles::events::{
Approval, Created, DestroyStarted, MetadataCleared, MetadataSet, Transfer,
};
use pop_primitives::{ArithmeticError::*, Error, Error::*, TokenError::*, TokenId};
use utils::*;

Expand Down Expand Up @@ -98,6 +101,11 @@ fn transfer_works() {
assert_ok!(transfer(&addr, token, BOB, amount / 2));
let balance_after_transfer = Assets::balance(token, &BOB);
assert_eq!(balance_after_transfer, balance_before_transfer + amount / 2);
// Successfully emit event.
let from = account_id_from_slice(addr.as_ref());
let to = account_id_from_slice(BOB.as_ref());
let expected = Transfer { from: Some(from), to: Some(to), value: amount / 2 }.encode();
assert_eq!(last_contract_event(), expected.as_slice());
// Transfer token to account that does not exist.
assert_eq!(transfer(&addr, token, FERDIE, amount / 4), Err(Token(CannotCreate)));
// Token is not live, i.e. frozen or being destroyed.
Expand Down Expand Up @@ -150,6 +158,11 @@ fn transfer_from_works() {
assert_ok!(transfer_from(&addr, token, ALICE, BOB, amount / 2));
let balance_after_transfer = Assets::balance(token, &BOB);
assert_eq!(balance_after_transfer, balance_before_transfer + amount / 2);
// Successfully emit event.
let from = account_id_from_slice(ALICE.as_ref());
let to = account_id_from_slice(BOB.as_ref());
let expected = Transfer { from: Some(from), to: Some(to), value: amount / 2 }.encode();
assert_eq!(last_contract_event(), expected.as_slice());
});
}

Expand All @@ -170,13 +183,23 @@ fn approve_works() {
assets::freeze(&ALICE, token);
assert_eq!(approve(&addr, token, &BOB, amount), Err(Module { index: 52, error: [16, 0] }));
assets::thaw(&ALICE, token);
// Successful approvals:
// Successful approvals.
assert_eq!(0, Assets::allowance(token, &addr, &BOB));
assert_ok!(approve(&addr, token, &BOB, amount));
assert_eq!(Assets::allowance(token, &addr, &BOB), amount);
// Successfully emit event.
let owner = account_id_from_slice(addr.as_ref());
let spender = account_id_from_slice(BOB.as_ref());
let expected = Approval { owner, spender, value: amount }.encode();
assert_eq!(last_contract_event(), expected.as_slice());
// Non-additive, sets new value.
assert_ok!(approve(&addr, token, &BOB, amount / 2));
assert_eq!(Assets::allowance(token, &addr, &BOB), amount / 2);
// Successfully emit event.
let owner = account_id_from_slice(addr.as_ref());
let spender = account_id_from_slice(BOB.as_ref());
let expected = Approval { owner, spender, value: amount / 2 }.encode();
assert_eq!(last_contract_event(), expected.as_slice());
// Token is not live, i.e. frozen or being destroyed.
assets::start_destroy(&ALICE, token);
assert_eq!(approve(&addr, token, &BOB, amount), Err(Module { index: 52, error: [16, 0] }));
Expand Down Expand Up @@ -316,6 +339,10 @@ fn create_works() {
// Create token successfully.
assert_ok!(create(&addr, TOKEN_ID, &BOB, 1));
assert_eq!(Assets::owner(TOKEN_ID), Some(addr.clone()));
// Successfully emit event.
let admin = account_id_from_slice(BOB.as_ref());
let expected = Created { id: TOKEN_ID, creator: admin, admin }.encode();
assert_eq!(last_contract_event(), expected.as_slice());
// Token ID is already taken.
assert_eq!(create(&addr, TOKEN_ID, &BOB, 1), Err(Module { index: 52, error: [5, 0] }),);
});
Expand All @@ -335,9 +362,15 @@ fn instantiate_and_create_fungible_works() {
);
// Successfully create a token when instantiating the contract.
let result_with_address = instantiate_and_create_fungible(contract, TOKEN_ID, 1);
assert_ok!(result_with_address.clone());
assert_eq!(Assets::owner(TOKEN_ID), result_with_address.ok());
let instantiator = result_with_address.clone().ok();
assert_ok!(result_with_address);
assert_eq!(&Assets::owner(TOKEN_ID), &instantiator);
assert!(Assets::asset_exists(TOKEN_ID));
// Successfully emit event.
let instantiator = account_id_from_slice(instantiator.unwrap().as_ref());
let expected =
Created { id: TOKEN_ID, creator: instantiator.clone(), admin: instantiator }.encode();
assert_eq!(last_contract_event(), expected.as_slice());
});
}

Expand All @@ -354,6 +387,9 @@ fn start_destroy_works() {
assert_eq!(start_destroy(&addr, token), Err(Module { index: 52, error: [2, 0] }),);
let token = assets::create(&addr, TOKEN_ID, 1);
assert_ok!(start_destroy(&addr, token));
// Successfully emit event.
let expected = DestroyStarted { token: TOKEN_ID }.encode();
assert_eq!(last_contract_event(), expected.as_slice());
});
}

Expand Down Expand Up @@ -393,7 +429,10 @@ fn set_metadata_works() {
Err(Module { index: 52, error: [9, 0] }),
);
// Set metadata successfully.
assert_ok!(set_metadata(&addr, TOKEN_ID, name, symbol, decimals));
assert_ok!(set_metadata(&addr, TOKEN_ID, name.clone(), symbol.clone(), decimals));
// Successfully emit event.
let expected = MetadataSet { token: TOKEN_ID, name, symbol, decimals }.encode();
assert_eq!(last_contract_event(), expected.as_slice());
// Token is not live, i.e. frozen or being destroyed.
assets::start_destroy(&addr, token);
assert_eq!(
Expand Down Expand Up @@ -427,6 +466,9 @@ fn clear_metadata_works() {
assets::set_metadata(&addr, token, name, symbol, decimals);
// Clear metadata successfully.
assert_ok!(clear_metadata(&addr, TOKEN_ID));
// Successfully emit event.
let expected = MetadataCleared { token: TOKEN_ID }.encode();
assert_eq!(last_contract_event(), expected.as_slice());
// Token is not live, i.e. frozen or being destroyed.
assets::start_destroy(&addr, token);
assert_eq!(
Expand Down
22 changes: 22 additions & 0 deletions pop-api/integration-tests/src/fungibles/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -337,3 +337,25 @@ pub(super) fn instantiate_and_create_fungible(
.unwrap_or_else(|_| panic!("Contract reverted: {:?}", result))
.map(|_| address)
}

/// Get the last event from pallet contracts.
pub(super) fn last_contract_event() -> Vec<u8> {
let events = System::read_events_for_pallet::<pallet_contracts::Event<Runtime>>();
let contract_events = events
.iter()
.filter_map(|event| match event {
pallet_contracts::Event::<Runtime>::ContractEmitted { data, .. } =>
Some(data.as_slice()),
_ => None,
})
.collect::<Vec<&[u8]>>();
contract_events.last().unwrap().to_vec()
}

/// Decodes a byte slice into an `AccountId` as defined in `primitives`.
///
/// This is used to resolve type mismatches between the `AccountId` in the integration tests and the
/// contract environment.
pub fn account_id_from_slice(s: &[u8; 32]) -> pop_api::primitives::AccountId {
pop_api::primitives::AccountId::decode(&mut &s[..]).expect("Should be decoded to AccountId")
}
3 changes: 2 additions & 1 deletion pop-api/src/primitives.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use ink::env::{DefaultEnvironment, Environment};
pub use pop_primitives::*;

pub(crate) type AccountId = <DefaultEnvironment as Environment>::AccountId;
// Public due to integration tests crate.
pub type AccountId = <DefaultEnvironment as Environment>::AccountId;
pub(crate) type Balance = <DefaultEnvironment as Environment>::Balance;
8 changes: 4 additions & 4 deletions pop-api/src/v0/fungibles.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ pub mod events {

/// Event emitted when a token is created.
#[ink::event]
pub struct Create {
pub struct Created {
/// The token identifier.
#[ink(topic)]
pub id: TokenId,
Expand All @@ -115,15 +115,15 @@ pub mod events {

/// Event emitted when a token is in the process of being destroyed.
#[ink::event]
pub struct StartDestroy {
pub struct DestroyStarted {
/// The token.
#[ink(topic)]
pub token: TokenId,
}

/// Event emitted when new metadata is set for a token.
#[ink::event]
pub struct SetMetadata {
pub struct MetadataSet {
/// The token.
#[ink(topic)]
pub token: TokenId,
Expand All @@ -139,7 +139,7 @@ pub mod events {

/// Event emitted when metadata is cleared for a token.
#[ink::event]
pub struct ClearMetadata {
pub struct MetadataCleared {
/// The token.
#[ink(topic)]
pub token: TokenId,
Expand Down
2 changes: 0 additions & 2 deletions pop-api/src/v0/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
use ink::env::chain_extension::ChainExtensionMethod;

use crate::{
build_extension_method,
constants::{DISPATCH, READ_STATE},
Expand Down

0 comments on commit bf27640

Please sign in to comment.