From dfe8bfb583d9ceec6971f755e859ea7a381b9cfe Mon Sep 17 00:00:00 2001 From: mubarak23 Date: Mon, 19 Aug 2024 19:47:25 +0100 Subject: [PATCH] test for lockable components --- src/components/lockable/lockable.cairo | 18 +-- src/components/presets/account_preset.cairo | 28 +++- tests/test_lockable_component.cairo | 152 ++++++++++++++++++++ 3 files changed, 184 insertions(+), 14 deletions(-) create mode 100644 tests/test_lockable_component.cairo diff --git a/src/components/lockable/lockable.cairo b/src/components/lockable/lockable.cairo index a175f1a..63020e8 100644 --- a/src/components/lockable/lockable.cairo +++ b/src/components/lockable/lockable.cairo @@ -18,13 +18,13 @@ pub mod LockableComponent { }; #[storage] - struct Storage { + pub struct Storage { lock_until: u64 } #[event] #[derive(Drop, starknet::Event)] - enum Event { + pub enum Event { AccountLocked: AccountLocked } @@ -69,20 +69,16 @@ pub mod LockableComponent { let account_comp = get_dep_component!(@self, Account); - // get the token - // let (token_contract, token_id, chain_id) = account_comp.token(); - // get the token owner let owner = account_comp.owner(); - // assert(account_comp.is_non_zero(), Errors::UNAUTHORIZED); - assert(get_caller_address() != owner, Errors::NOT_OWNER); + assert(get_caller_address() == owner, Errors::NOT_OWNER); assert(lock_until <= current_timestamp + 356, Errors::EXCEEDS_MAX_LOCK_TIME); - // _beforeLock may be call before upating the lock period - let lock_status = self.is_lock(); //.is_locked(); - assert(!lock_status, Errors::LOCKED_ACCOUNT); + let lock_status = self.is_lock(); + + assert(lock_status != true, Errors::LOCKED_ACCOUNT); // set the lock_util which set the period the account is lock self.lock_until.write(lock_until); // emit event @@ -90,7 +86,7 @@ pub mod LockableComponent { .emit( AccountLocked { account: get_caller_address(), - locked_at: current_timestamp, + locked_at: get_block_timestamp(), lock_until: lock_until } ); diff --git a/src/components/presets/account_preset.cairo b/src/components/presets/account_preset.cairo index 39abee2..dc050f2 100644 --- a/src/components/presets/account_preset.cairo +++ b/src/components/presets/account_preset.cairo @@ -6,10 +6,14 @@ pub mod AccountPreset { use starknet::{ContractAddress, get_caller_address, ClassHash, account::Call}; use token_bound_accounts::components::account::account::AccountComponent; use token_bound_accounts::components::upgradeable::upgradeable::UpgradeableComponent; - use token_bound_accounts::interfaces::{IUpgradeable::IUpgradeable, IExecutable::IExecutable,}; + use token_bound_accounts::components::lockable::lockable::LockableComponent; + use token_bound_accounts::interfaces::{ + IUpgradeable::IUpgradeable, IExecutable::IExecutable, ILockable::ILockable + }; component!(path: AccountComponent, storage: account, event: AccountEvent); component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent); + component!(path: LockableComponent, storage: lockable, event: LockableEvent); // Account #[abi(embed_v0)] @@ -17,6 +21,7 @@ pub mod AccountPreset { impl AccountInternalImpl = AccountComponent::InternalImpl; impl UpgradeableInternalImpl = UpgradeableComponent::Private; + impl LockableImpl = LockableComponent::LockableImpl; // ************************************************************************* // STORAGE @@ -26,7 +31,9 @@ pub mod AccountPreset { #[substorage(v0)] account: AccountComponent::Storage, #[substorage(v0)] - upgradeable: UpgradeableComponent::Storage + upgradeable: UpgradeableComponent::Storage, + #[substorage(v0)] + lockable: LockableComponent::Storage, } // ************************************************************************* @@ -38,7 +45,9 @@ pub mod AccountPreset { #[flat] AccountEvent: AccountComponent::Event, #[flat] - UpgradeableEvent: UpgradeableComponent::Event + UpgradeableEvent: UpgradeableComponent::Event, + #[flat] + LockableEvent: LockableComponent::Event } // ************************************************************************* @@ -68,4 +77,17 @@ pub mod AccountPreset { self.upgradeable._upgrade(new_class_hash); } } + + // ************************************************************************* + // LOCKABLE IMPL + // ************************************************************************* + #[abi(embed_v0)] + impl Lockable of ILockable { + fn lock(ref self: ContractState, lock_until: u64) { + self.lockable.lock(lock_until); + } + fn is_lock(self: @ContractState) -> bool { + self.lockable.is_lock() + } + } } diff --git a/tests/test_lockable_component.cairo b/tests/test_lockable_component.cairo new file mode 100644 index 0000000..f69787f --- /dev/null +++ b/tests/test_lockable_component.cairo @@ -0,0 +1,152 @@ +// ************************************************************************* +// LOCKABLE COMPONENT TEST +// ************************************************************************* +use starknet::{ContractAddress, account::Call, get_block_timestamp}; +use snforge_std::{ + declare, start_cheat_caller_address, stop_cheat_caller_address, start_cheat_transaction_hash, + start_cheat_nonce, spy_events, EventSpyAssertionsTrait, ContractClassTrait, ContractClass +}; +use core::hash::HashStateTrait; +use core::pedersen::PedersenTrait; + +use token_bound_accounts::interfaces::IAccount::{ + IAccountDispatcher, IAccountDispatcherTrait, IAccountSafeDispatcher, IAccountSafeDispatcherTrait +}; +use token_bound_accounts::interfaces::ILockable::{ILockableDispatcher, ILockableDispatcherTrait}; + +use token_bound_accounts::interfaces::IExecutable::{ + IExecutableDispatcher, IExecutableDispatcherTrait +}; +use token_bound_accounts::components::presets::account_preset::AccountPreset; +use token_bound_accounts::components::account::account::AccountComponent; +use token_bound_accounts::components::lockable::lockable::LockableComponent; + +use token_bound_accounts::test_helper::{ + hello_starknet::{IHelloStarknetDispatcher, IHelloStarknetDispatcherTrait, HelloStarknet}, + erc721_helper::{IERC721Dispatcher, IERC721DispatcherTrait, ERC721}, + simple_account::{ISimpleAccountDispatcher, ISimpleAccountDispatcherTrait, SimpleAccount} +}; + + +const ACCOUNT: felt252 = 1234; +const ACCOUNT2: felt252 = 5729; +const SALT: felt252 = 123; + +#[derive(Drop)] +struct SignedTransactionData { + private_key: felt252, + public_key: felt252, + transaction_hash: felt252, + r: felt252, + s: felt252 +} + +fn SIGNED_TX_DATA() -> SignedTransactionData { + SignedTransactionData { + private_key: 1234, + public_key: 883045738439352841478194533192765345509759306772397516907181243450667673002, + transaction_hash: 2717105892474786771566982177444710571376803476229898722748888396642649184538, + r: 3068558690657879390136740086327753007413919701043650133111397282816679110801, + s: 3355728545224320878895493649495491771252432631648740019139167265522817576501 + } +} + +// ************************************************************************* +// SETUP +// ************************************************************************* +fn __setup__() -> (ContractAddress, ContractAddress) { + // deploy erc721 helper contract + let erc721_contract = declare("ERC721").unwrap(); + let mut erc721_constructor_calldata = array!['tokenbound', 'TBA']; + let (erc721_contract_address, _) = erc721_contract + .deploy(@erc721_constructor_calldata) + .unwrap(); + + // deploy recipient contract + let account_contract = declare("SimpleAccount").unwrap(); + let (recipient, _) = account_contract + .deploy( + @array![883045738439352841478194533192765345509759306772397516907181243450667673002] + ) + .unwrap(); + + // mint a new token + let dispatcher = IERC721Dispatcher { contract_address: erc721_contract_address }; + dispatcher.mint(recipient, 1.try_into().unwrap()); + + // deploy account contract + let account_contract = declare("AccountPreset").unwrap(); + let mut acct_constructor_calldata = array![erc721_contract_address.try_into().unwrap(), 1, 0]; + let (account_contract_address, _) = account_contract + .deploy(@acct_constructor_calldata) + .unwrap(); + + (account_contract_address, erc721_contract_address) +} + + +#[test] +fn test_lockable_owner() { + let (contract_address, erc721_contract_address) = __setup__(); + let acct_dispatcher = IAccountDispatcher { contract_address: contract_address }; + + let token_dispatcher = IERC721Dispatcher { contract_address: erc721_contract_address }; + let owner = acct_dispatcher.owner(); + let token_owner = token_dispatcher.ownerOf(1.try_into().unwrap()); + + start_cheat_caller_address(contract_address, token_owner); + + assert(owner == token_owner, 'invalid owner'); + stop_cheat_caller_address(contract_address); +} +#[test] +fn test_lockable() { + let (contract_address, _) = __setup__(); + let acct_dispatcher = IAccountDispatcher { contract_address: contract_address }; + + let owner = acct_dispatcher.owner(); + + start_cheat_caller_address(contract_address, owner); + + let lockable_dispatcher = ILockableDispatcher { contract_address }; + + lockable_dispatcher.lock(40); + let check_lock = lockable_dispatcher.is_lock(); + + assert(check_lock == true, 'Account Not Lock'); + stop_cheat_caller_address(contract_address); +} +#[test] +fn test_lockable_emits_event() { + let (contract_address, _) = __setup__(); + + let acct_dispatcher = IAccountDispatcher { contract_address: contract_address }; + + let owner = acct_dispatcher.owner(); + + // spy on emitted events + let mut spy = spy_events(); + + start_cheat_caller_address(contract_address, owner); + + // call the lock function + let lockable_dispatcher = ILockableDispatcher { contract_address: contract_address }; + + lockable_dispatcher.lock(40); + + // check events are emitted + spy + .assert_emitted( + @array![ + ( + contract_address, + LockableComponent::Event::AccountLocked( + LockableComponent::AccountLocked { + account: owner, locked_at: get_block_timestamp(), lock_until: 40 + } + ) + ) + ] + ); +} +