From b753a64bb154678953e2bddc2fc7ac3b3d434e6e Mon Sep 17 00:00:00 2001 From: Mehul Chauhan Date: Tue, 20 Aug 2024 21:08:32 +0530 Subject: [PATCH] Withdrawal tests (#11) * feat: initiliased testcases * admin function tests * fix: max total balance check * feat: block token test * disable limit test * feat: add failing tc for withdraw limit * fixed testcases after rebase * chore: added messaging mock * Update src/bridge/token_bridge.cairo Co-authored-by: Apoorv Sadana <95699312+apoorvsadana@users.noreply.github.com> * resolve comments * add reactivate and unblock * add reactivate and unblock * unblock tests * reactivate and unblock tests * resolved merge conflicts * restructure testcases * fix: visibility modifier * deposit tests * make them unit * make them unit * deposit flow tests * change to mock usdc address * improve: not needed to deploy usdc in while mock testing * unit testcases * add token actions restructure * migrate to latest foundry * restructure * deposit failing tc * test: happy withdraw test * chore: ran formatter * fix settlement of message * change deposit tests to use message_payloads * add assert * failing withdraw tc * cancel request * deposit with message cancels * Update tests/deposit_test.cairo Co-authored-by: Apoorv Sadana <95699312+apoorvsadana@users.noreply.github.com> * resolved comments * fix consume message * reclaim testcases * fix consume message check * consume message * add balance check * add events in actions * deactivate tc * send messages tc * change name * withdrawal limit tests initialised * fix build failure * remaining quota * withdrawal tests * Update src/withdrawal_limit/mock.cairo Co-authored-by: Apoorv Sadana <95699312+apoorvsadana@users.noreply.github.com> * Update src/withdrawal_limit/tests/withdrawal_limit_test.cairo Co-authored-by: Apoorv Sadana <95699312+apoorvsadana@users.noreply.github.com> * Update src/withdrawal_limit/tests/withdrawal_limit_test.cairo Co-authored-by: Apoorv Sadana <95699312+apoorvsadana@users.noreply.github.com> * Update src/withdrawal_limit/tests/withdrawal_limit_test.cairo Co-authored-by: Apoorv Sadana <95699312+apoorvsadana@users.noreply.github.com> * should fail if message not registered (#12) * resolve commits * Update src/withdrawal_limit/tests/withdrawal_limit_test.cairo Co-authored-by: Apoorv Sadana <95699312+apoorvsadana@users.noreply.github.com> * Update src/withdrawal_limit/tests/withdrawal_limit_test.cairo Co-authored-by: Apoorv Sadana <95699312+apoorvsadana@users.noreply.github.com> * move file to mocks * code repetition reduced * failing tests fixed --------- Co-authored-by: Apoorv Sadana <95699312+apoorvsadana@users.noreply.github.com> --- src/bridge/tests/messaging_test.cairo | 22 +- src/bridge/tests/token_actions_test.cairo | 22 +- {tests => src/bridge/tests/utils}/setup.cairo | 4 +- src/bridge/token_bridge.cairo | 1 + src/lib.cairo | 8 + src/mocks/messaging_malicious.cairo | 56 +++++ src/mocks/withdrawal_limit_mock.cairo | 80 ++++++ src/withdrawal_limit/component.cairo | 25 +- .../tests/withdrawal_limit_test.cairo | 227 ++++++++++++++++++ tests/deposit_reclaim_test.cairo | 2 +- tests/deposit_test.cairo | 2 +- tests/enroll_token_test.cairo | 33 ++- tests/lib.cairo | 1 - tests/token_bridge_test.cairo | 2 +- tests/withdraw_test.cairo | 2 +- tests/withdrawal_limit_bridge_test.cairo | 2 +- 16 files changed, 437 insertions(+), 52 deletions(-) rename {tests => src/bridge/tests/utils}/setup.cairo (97%) create mode 100644 src/mocks/messaging_malicious.cairo create mode 100644 src/mocks/withdrawal_limit_mock.cairo create mode 100644 src/withdrawal_limit/tests/withdrawal_limit_test.cairo diff --git a/src/bridge/tests/messaging_test.cairo b/src/bridge/tests/messaging_test.cairo index 3d65fa3..19cca39 100644 --- a/src/bridge/tests/messaging_test.cairo +++ b/src/bridge/tests/messaging_test.cairo @@ -25,32 +25,12 @@ use openzeppelin::{ interface::{IOwnableTwoStepDispatcher, IOwnableTwoStepDispatcherTrait} } }; +use starknet_bridge::bridge::tests::utils::setup::{deploy_erc20, mock_state_testing}; use starknet_bridge::bridge::tests::utils::message_payloads; use starknet::contract_address::{contract_address_const}; use starknet_bridge::constants; -/// Returns the state of a contract for testing. This must be used -/// to test internal functions or directly access the storage. -/// You can't spy event with this. Use deploy instead. -pub fn mock_state_testing() -> TokenBridge::ContractState { - TokenBridge::contract_state_for_testing() -} - -fn deploy_erc20(name: ByteArray, symbol: ByteArray) -> ContractAddress { - let erc20_class_hash = snf::declare("ERC20").unwrap(); - let mut constructor_args = ArrayTrait::new(); - name.serialize(ref constructor_args); - symbol.serialize(ref constructor_args); - let fixed_supply: u256 = 1000000000; - fixed_supply.serialize(ref constructor_args); - OWNER().serialize(ref constructor_args); - - let (usdc, _) = erc20_class_hash.deploy(@constructor_args).unwrap(); - return usdc; -} - - #[test] fn deploy_message_payload_ok() { let usdc_address = deploy_erc20("USDC", "USDC"); diff --git a/src/bridge/tests/token_actions_test.cairo b/src/bridge/tests/token_actions_test.cairo index c8d973f..cc00c3f 100644 --- a/src/bridge/tests/token_actions_test.cairo +++ b/src/bridge/tests/token_actions_test.cairo @@ -23,32 +23,12 @@ use starknet_bridge::bridge::tests::utils::message_payloads; use starknet_bridge::mocks::hash; use starknet::contract_address::{contract_address_const}; use starknet_bridge::constants; +use starknet_bridge::bridge::tests::utils::setup::{deploy_erc20, mock_state_testing}; use starknet_bridge::bridge::tests::constants::{ OWNER, L3_BRIDGE_ADDRESS, USDC_MOCK_ADDRESS, DELAY_TIME }; - -/// Returns the state of a contract for testing. This must be used -/// to test internal functions or directly access the storage. -/// You can't spy event with this. Use deploy instead. -pub fn mock_state_testing() -> TokenBridge::ContractState { - TokenBridge::contract_state_for_testing() -} - -fn deploy_erc20(name: ByteArray, symbol: ByteArray) -> ContractAddress { - let erc20_class_hash = snf::declare("ERC20").unwrap(); - let mut constructor_args = ArrayTrait::new(); - name.serialize(ref constructor_args); - symbol.serialize(ref constructor_args); - let fixed_supply: u256 = 1000000000; - fixed_supply.serialize(ref constructor_args); - OWNER().serialize(ref constructor_args); - - let (usdc, _) = erc20_class_hash.deploy(@constructor_args).unwrap(); - return usdc; -} - #[test] fn deactivate_token_ok() { let mut mock = mock_state_testing(); diff --git a/tests/setup.cairo b/src/bridge/tests/utils/setup.cairo similarity index 97% rename from tests/setup.cairo rename to src/bridge/tests/utils/setup.cairo index 8ccaede..5017086 100644 --- a/tests/setup.cairo +++ b/src/bridge/tests/utils/setup.cairo @@ -18,7 +18,9 @@ use openzeppelin::access::ownable::{ }; use openzeppelin::token::erc20::interface::{IERC20, IERC20Dispatcher, IERC20DispatcherTrait}; use starknet::contract_address::{contract_address_const}; -use super::constants::{OWNER, L3_BRIDGE_ADDRESS, DELAY_TIME}; +use starknet_bridge::bridge::tests::constants::{ + OWNER, USDC_MOCK_ADDRESS, L3_BRIDGE_ADDRESS, DELAY_TIME +}; use starknet_bridge::constants; use starknet_bridge::bridge::tests::utils::message_payloads; diff --git a/src/bridge/token_bridge.cairo b/src/bridge/token_bridge.cairo index 546f257..5734c03 100644 --- a/src/bridge/token_bridge.cairo +++ b/src/bridge/token_bridge.cairo @@ -283,6 +283,7 @@ pub mod TokenBridge { self .messaging_contract .write(IMessagingDispatcher { contract_address: messaging_contract }); + self.withdrawal.initialize(5); self.ownable.initializer(owner); } diff --git a/src/lib.cairo b/src/lib.cairo index b9cac6e..07f663d 100644 --- a/src/lib.cairo +++ b/src/lib.cairo @@ -10,6 +10,7 @@ pub mod bridge { mod messaging_test; pub mod utils { pub mod message_payloads; + pub mod setup; } } @@ -25,6 +26,11 @@ pub mod bridge { pub mod withdrawal_limit { pub mod component; pub mod interface; + + #[cfg(test)] + mod tests { + mod withdrawal_limit_test; + } } pub mod constants; @@ -32,6 +38,8 @@ pub mod constants; pub mod mocks { pub mod erc20; pub mod messaging; + pub mod messaging_malicious; + pub mod withdrawal_limit_mock; pub mod hash; } diff --git a/src/mocks/messaging_malicious.cairo b/src/mocks/messaging_malicious.cairo new file mode 100644 index 0000000..40418bf --- /dev/null +++ b/src/mocks/messaging_malicious.cairo @@ -0,0 +1,56 @@ +#[starknet::contract] +mod messaging_malicious { + use piltover::messaging::interface::IMessaging; + use starknet::ContractAddress; + + + #[storage] + struct Storage {} + + + #[abi(embed_v0)] + impl MessagingImpl of IMessaging { + fn send_message_to_appchain( + ref self: ContractState, + to_address: ContractAddress, + selector: felt252, + payload: Span + ) -> (felt252, felt252) { + (0, 0) + } + + fn consume_message_from_appchain( + ref self: ContractState, from_address: ContractAddress, payload: Span + ) -> felt252 { + 0 + } + + fn sn_to_appchain_messages(self: @ContractState, message_hash: felt252) -> felt252 { + 0 + } + + fn appchain_to_sn_messages(self: @ContractState, message_hash: felt252) -> felt252 { + 0 + } + + fn start_message_cancellation( + ref self: ContractState, + to_address: ContractAddress, + selector: felt252, + payload: Span, + nonce: felt252, + ) -> felt252 { + 0 + } + + fn cancel_message( + ref self: ContractState, + to_address: ContractAddress, + selector: felt252, + payload: Span, + nonce: felt252, + ) -> felt252 { + 0 + } + } +} diff --git a/src/mocks/withdrawal_limit_mock.cairo b/src/mocks/withdrawal_limit_mock.cairo new file mode 100644 index 0000000..ea1f31d --- /dev/null +++ b/src/mocks/withdrawal_limit_mock.cairo @@ -0,0 +1,80 @@ +use starknet::ContractAddress; + +#[starknet::interface] +pub trait IMockWithdrawalLimit { + fn toggle_withdrawal_limit_for_token( + ref self: TState, token: ContractAddress, is_applied: bool + ); + fn consume_quota(ref self: TState, token: ContractAddress, amount: u256); + fn write_daily_withdrawal_limit_pct(ref self: TState, limit_percent: u8); + fn get_daily_withdrawal_limit_pct(self: @TState) -> u8; +} + +#[starknet::contract] +pub mod withdrawal_limit_mock { + use starknet_bridge::withdrawal_limit::component::WithdrawalLimitComponent::InternalTrait; + use starknet_bridge::withdrawal_limit::{ + component::WithdrawalLimitComponent, + interface::{IWithdrawalLimitDispatcher, IWithdrawalLimitDispatcherTrait, IWithdrawalLimit} + }; + use starknet_bridge::bridge::interface::IWithdrawalLimitStatus; + use starknet::ContractAddress; + + + component!(path: WithdrawalLimitComponent, storage: withdrawal, event: WithdrawalEvent); + + // WithdrawalLimit + #[abi(embed_v0)] + impl WithdrawalLimitImpl = + WithdrawalLimitComponent::WithdrawalLimitImpl; + impl WithdrawalLimitInternal = WithdrawalLimitComponent::InternalImpl; + + + #[storage] + struct Storage { + limits: LegacyMap, + #[substorage(v0)] + withdrawal: WithdrawalLimitComponent::Storage, + } + + #[event] + #[derive(Drop, starknet::Event)] + pub enum Event { + #[flat] + WithdrawalEvent: WithdrawalLimitComponent::Event, + } + + #[constructor] + pub fn constructor(ref self: ContractState) { + self.withdrawal.initialize(5); + } + + + #[abi(embed_v0)] + impl MockWithdrawalLimitImpl of super::IMockWithdrawalLimit { + fn toggle_withdrawal_limit_for_token( + ref self: ContractState, token: ContractAddress, is_applied: bool + ) { + self.limits.write(token, is_applied); + } + + fn consume_quota(ref self: ContractState, token: ContractAddress, amount: u256) { + self.withdrawal.consume_withdrawal_quota(token, amount); + } + + fn write_daily_withdrawal_limit_pct(ref self: ContractState, limit_percent: u8) { + self.withdrawal.write_daily_withdrawal_limit_pct(limit_percent); + } + + fn get_daily_withdrawal_limit_pct(self: @ContractState) -> u8 { + self.withdrawal.daily_withdrawal_limit_pct.read() + } + } + + #[abi(embed_v0)] + impl WithdrawalLimitStatusImpl of IWithdrawalLimitStatus { + fn is_withdrawal_limit_applied(self: @ContractState, token: ContractAddress) -> bool { + self.limits.read(token) + } + } +} diff --git a/src/withdrawal_limit/component.cairo b/src/withdrawal_limit/component.cairo index e2f600b..5f7d4ff 100644 --- a/src/withdrawal_limit/component.cairo +++ b/src/withdrawal_limit/component.cairo @@ -21,14 +21,21 @@ pub mod WithdrawalLimitComponent { #[event] #[derive(Drop, starknet::Event)] pub enum Event { - RemainingQuotaUpdated: RemainingQuotaUpdated + RemainingQuotaUpdated: RemainingQuotaUpdated, + DailyWithdrawalPercentageUpdated: DailyWithdrawalPercentageUpdated } #[derive(Drop, starknet::Event)] pub struct RemainingQuotaUpdated { - new_quota: u256 + pub token: ContractAddress, + pub day: u64, + pub new_quota: u256 } + #[derive(Drop, starknet::Event)] + pub struct DailyWithdrawalPercentageUpdated { + pub new_percentage: u8 + } #[embeddable_as(WithdrawalLimitImpl)] pub impl WithdrawalLimit< @@ -45,6 +52,8 @@ pub mod WithdrawalLimitComponent { return BoundedInt::max(); } let remaining_quota = self.read_withdrawal_quota_slot(:token); + + // if remaining_quota is 0 then quota is not initialised if remaining_quota == 0 { return self.get_daily_withdrawal_limit(:token); } @@ -56,6 +65,11 @@ pub mod WithdrawalLimitComponent { pub impl InternalImpl< TContractState, +HasComponent, +IWithdrawalLimitStatus > of InternalTrait { + // This initializes the withdrawal_limit component + fn initialize(ref self: ComponentState, daily_withdrawal_limit_pct: u8) { + self.daily_withdrawal_limit_pct.write(daily_withdrawal_limit_pct); + } + // Sets the remaining withdrawal quota for today. fn set_remaining_withdrawal_quota( ref self: ComponentState, token: ContractAddress, amount: u256 @@ -65,6 +79,8 @@ pub mod WithdrawalLimitComponent { self .remaining_intraday_withdraw_quota .write((token, day), amount + constants::REMAINING_QUOTA_OFFSET); + + self.emit(RemainingQuotaUpdated { token: token, day: day, new_quota: amount }); } // Returns the remaining withdrawal quota for today. @@ -118,6 +134,11 @@ pub mod WithdrawalLimitComponent { ) { assert(daily_withdrawal_limit_pct <= 100, 'LIMIT_PCT_TOO_HIGH'); self.daily_withdrawal_limit_pct.write(daily_withdrawal_limit_pct); + + self + .emit( + DailyWithdrawalPercentageUpdated { new_percentage: daily_withdrawal_limit_pct } + ); } } } diff --git a/src/withdrawal_limit/tests/withdrawal_limit_test.cairo b/src/withdrawal_limit/tests/withdrawal_limit_test.cairo new file mode 100644 index 0000000..2f8ac3d --- /dev/null +++ b/src/withdrawal_limit/tests/withdrawal_limit_test.cairo @@ -0,0 +1,227 @@ +use starknet::ContractAddress; +use core::integer::BoundedInt; +use snforge_std as snf; +use snforge_std::{ + ContractClassTrait, EventSpy, EventSpyTrait, EventsFilterTrait, EventSpyAssertionsTrait +}; +use starknet_bridge::bridge::tests::constants::{ + OWNER, L3_BRIDGE_ADDRESS, USDC_MOCK_ADDRESS, DELAY_TIME +}; +use starknet_bridge::mocks::withdrawal_limit_mock::{ + withdrawal_limit_mock, withdrawal_limit_mock::Event::WithdrawalEvent, + IMockWithdrawalLimitDispatcher, IMockWithdrawalLimitDispatcherTrait +}; + + +use starknet_bridge::withdrawal_limit::interface::{ + IWithdrawalLimit, IWithdrawalLimitDispatcher, IWithdrawalLimitDispatcherTrait +}; +use starknet_bridge::withdrawal_limit::component::{ + WithdrawalLimitComponent, + WithdrawalLimitComponent::{RemainingQuotaUpdated, DailyWithdrawalPercentageUpdated} +}; +use openzeppelin::token::erc20::interface::{IERC20, IERC20Dispatcher, IERC20DispatcherTrait}; +use starknet_bridge::bridge::tests::utils::setup::{deploy_erc20, mock_state_testing}; + + +fn deploy_withdrawal_limit() -> (IWithdrawalLimitDispatcher, EventSpy) { + let withdrawal_limit_mock_class_hash = snf::declare("withdrawal_limit_mock").unwrap(); + let (withdrawal_limit_mock_address, _) = withdrawal_limit_mock_class_hash + .deploy(@array![]) + .unwrap(); + let withdrawal_limit_mock = IWithdrawalLimitDispatcher { + contract_address: withdrawal_limit_mock_address + }; + + let mut spy = snf::spy_events(); + (withdrawal_limit_mock, spy) +} + + +#[test] +fn get_remaining_withdrawal_quota_ok() { + let (withdrawal_limit, _) = deploy_withdrawal_limit(); + + let usdc_address = deploy_erc20("USDC", "USDC"); + let usdc = IERC20Dispatcher { contract_address: usdc_address }; + + // Transfering usdc to test address for testing + snf::start_cheat_caller_address(usdc.contract_address, OWNER()); + usdc.transfer(snf::test_address(), 10_000_000); + snf::stop_cheat_caller_address(usdc.contract_address); + + // Mocking deposits with the contract + usdc.transfer(withdrawal_limit.contract_address, 1_000_000); + + let withdrawal_limit_mock = IMockWithdrawalLimitDispatcher { + contract_address: withdrawal_limit.contract_address + }; + + // Should return BoundedInt::max() when withdrawal limit not applied + assert( + withdrawal_limit.get_remaining_withdrawal_quota(usdc_address) == BoundedInt::max(), + 'Quota is not BoundedInt::max()' + ); + withdrawal_limit_mock.toggle_withdrawal_limit_for_token(usdc_address, true); + + // Should return the default 5% of the balance of contract when limit applied + assert( + withdrawal_limit.get_remaining_withdrawal_quota(usdc_address) == 50_000, + 'Quota should not be 0' + ); +} + +#[test] +fn consume_withdrawal_quota_ok() { + let (withdrawal_limit, mut spy) = deploy_withdrawal_limit(); + + let usdc_address = deploy_erc20("USDC", "USDC"); + let usdc = IERC20Dispatcher { contract_address: usdc_address }; + + // Transfering usdc to test address for testing + snf::start_cheat_caller_address(usdc.contract_address, OWNER()); + usdc.transfer(snf::test_address(), 10_000_000); + snf::stop_cheat_caller_address(usdc.contract_address); + + // Mocking deposits with the contract + usdc.transfer(withdrawal_limit.contract_address, 1000_000); + + let withdrawal_limit_mock = IMockWithdrawalLimitDispatcher { + contract_address: withdrawal_limit.contract_address + }; + + withdrawal_limit_mock.toggle_withdrawal_limit_for_token(usdc_address, true); + + assert( + withdrawal_limit.get_remaining_withdrawal_quota(usdc_address) == 5000_0, + 'Quota should not be 0' + ); + withdrawal_limit_mock.consume_quota(usdc_address, 10_000); + + // The daily quota should reduce by the exact amount after consumption + assert( + withdrawal_limit.get_remaining_withdrawal_quota(usdc_address) == 4000_0, + 'Daily quota not updated' + ); + + let expected_event = RemainingQuotaUpdated { token: usdc_address, day: 0, new_quota: 40000 }; + spy + .assert_emitted( + @array![ + ( + withdrawal_limit_mock.contract_address, + WithdrawalLimitComponent::Event::RemainingQuotaUpdated(expected_event) + ) + ] + ); +} + +#[test] +#[should_panic(expected: ('LIMIT_EXCEEDED',))] +fn consume_withdrawal_quota_limit_exceeded() { + let (withdrawal_limit, _) = deploy_withdrawal_limit(); + + let usdc_address = deploy_erc20("USDC", "USDC"); + let usdc = IERC20Dispatcher { contract_address: usdc_address }; + // Transfering usdc to test address for testing + snf::start_cheat_caller_address(usdc.contract_address, OWNER()); + usdc.transfer(snf::test_address(), 10_000_000); + snf::stop_cheat_caller_address(usdc.contract_address); + + // Mocking deposits with the contract + usdc.transfer(withdrawal_limit.contract_address, 1000_000); + + let withdrawal_limit_mock = IMockWithdrawalLimitDispatcher { + contract_address: withdrawal_limit.contract_address + }; + + withdrawal_limit_mock.toggle_withdrawal_limit_for_token(usdc_address, true); + + assert( + withdrawal_limit.get_remaining_withdrawal_quota(usdc_address) == 5000_0, + 'Quota should not be 0' + ); + withdrawal_limit_mock.consume_quota(usdc_address, 1000_00); +} + +#[test] +fn get_remaining_withdrawal_quota_should_reset_after_1_day_ok() { + let (withdrawal_limit, _) = deploy_withdrawal_limit(); + + let usdc_address = deploy_erc20("USDC", "USDC"); + let usdc = IERC20Dispatcher { contract_address: usdc_address }; + + // Transfering usdc to test address for testing + snf::start_cheat_caller_address(usdc.contract_address, OWNER()); + usdc.transfer(snf::test_address(), 10_000_000); + snf::stop_cheat_caller_address(usdc.contract_address); + + // Mocking deposits with the contract + usdc.transfer(withdrawal_limit.contract_address, 1000_000); + let withdrawal_limit_mock = IMockWithdrawalLimitDispatcher { + contract_address: withdrawal_limit.contract_address + }; + + withdrawal_limit_mock.toggle_withdrawal_limit_for_token(usdc_address, true); + + assert( + withdrawal_limit.get_remaining_withdrawal_quota(usdc_address) == 5000_0, + 'Quota should not be 0' + ); + withdrawal_limit_mock.consume_quota(usdc_address, 10000); + + // The daily quota should reduce by the exact amount after consumption + assert( + withdrawal_limit.get_remaining_withdrawal_quota(usdc_address) == 4000_0, + 'Daily quota not updated' + ); + + let current_time = starknet::get_block_timestamp(); + // Forwarding the time by one day + snf::start_cheat_block_timestamp_global(current_time + 86400 + 10); + + assert( + withdrawal_limit.get_remaining_withdrawal_quota(usdc_address) == 5000_0, + 'Daily quota not updated' + ); +} + +#[test] +fn write_daily_withdrawal_limit_pct_ok() { + let (withdrawal_limit, mut spy) = deploy_withdrawal_limit(); + + let withdrawal_limit_mock = IMockWithdrawalLimitDispatcher { + contract_address: withdrawal_limit.contract_address + }; + + assert(withdrawal_limit_mock.get_daily_withdrawal_limit_pct() == 5, 'Limit not set'); + withdrawal_limit_mock.write_daily_withdrawal_limit_pct(10); + + assert(withdrawal_limit_mock.get_daily_withdrawal_limit_pct() == 10, 'Limit not set'); + let expected_event = DailyWithdrawalPercentageUpdated { new_percentage: 10 }; + spy + .assert_emitted( + @array![ + ( + withdrawal_limit_mock.contract_address, + WithdrawalLimitComponent::Event::DailyWithdrawalPercentageUpdated( + expected_event + ) + ) + ] + ); +} + +#[test] +#[should_panic(expected: ('LIMIT_PCT_TOO_HIGH',))] +fn write_daily_withdrawal_limit_pct_too_high() { + let (withdrawal_limit, _) = deploy_withdrawal_limit(); + + let withdrawal_limit_mock = IMockWithdrawalLimitDispatcher { + contract_address: withdrawal_limit.contract_address + }; + + assert(withdrawal_limit_mock.get_daily_withdrawal_limit_pct() == 5, 'Limit not set'); + withdrawal_limit_mock.write_daily_withdrawal_limit_pct(150); +} + diff --git a/tests/deposit_reclaim_test.cairo b/tests/deposit_reclaim_test.cairo index a5805cf..a425b1d 100644 --- a/tests/deposit_reclaim_test.cairo +++ b/tests/deposit_reclaim_test.cairo @@ -28,7 +28,7 @@ use openzeppelin::access::ownable::{ use openzeppelin::token::erc20::interface::{IERC20, IERC20Dispatcher, IERC20DispatcherTrait}; use starknet::contract_address::{contract_address_const}; use super::constants::{OWNER, L3_BRIDGE_ADDRESS, DELAY_TIME}; -use super::setup::{ +use starknet_bridge::bridge::tests::utils::setup::{ deploy_erc20, deploy_token_bridge_with_messaging, deploy_token_bridge, enroll_token_and_settle }; diff --git a/tests/deposit_test.cairo b/tests/deposit_test.cairo index 26ba426..fa7fcfb 100644 --- a/tests/deposit_test.cairo +++ b/tests/deposit_test.cairo @@ -28,7 +28,7 @@ use openzeppelin::access::ownable::{ use openzeppelin::token::erc20::interface::{IERC20, IERC20Dispatcher, IERC20DispatcherTrait}; use starknet::contract_address::{contract_address_const}; use super::constants::{OWNER, L3_BRIDGE_ADDRESS, DELAY_TIME}; -use super::setup::{ +use starknet_bridge::bridge::tests::utils::setup::{ deploy_erc20, deploy_token_bridge_with_messaging, deploy_token_bridge, enroll_token_and_settle }; diff --git a/tests/enroll_token_test.cairo b/tests/enroll_token_test.cairo index 90b7a06..21fe49c 100644 --- a/tests/enroll_token_test.cairo +++ b/tests/enroll_token_test.cairo @@ -22,7 +22,7 @@ use openzeppelin::access::ownable::{ }; use starknet::contract_address::{contract_address_const}; use super::constants::{OWNER, L3_BRIDGE_ADDRESS, USDC_MOCK_ADDRESS, DELAY_TIME}; -use super::setup::{deploy_erc20, deploy_token_bridge}; +use starknet_bridge::bridge::tests::utils::setup::{deploy_erc20, deploy_token_bridge}; use starknet_bridge::bridge::tests::utils::message_payloads; use starknet_bridge::constants; @@ -71,3 +71,34 @@ fn enroll_token_already_enrolled() { token_bridge.enroll_token(usdc_address); } +#[test] +#[should_panic(expected: ('Deployment message inexistent',))] +fn enroll_token_nonce_not_updated() { + // Deploy messaging mock with 5 days cancellation delay + let messaging_mock_class_hash = snf::declare("messaging_malicious").unwrap(); + // Deploying with 5 days as the delay time (5 * 86400 = 432000) + let (messaging_contract_address, _) = messaging_mock_class_hash.deploy(@array![]).unwrap(); + + // Declare l3 bridge address + let appchain_bridge_address = L3_BRIDGE_ADDRESS(); + + // Declare owner + let owner = OWNER(); + + let token_bridge_class_hash = snf::declare("TokenBridge").unwrap(); + + // Deploy the bridge + let mut calldata = ArrayTrait::new(); + appchain_bridge_address.serialize(ref calldata); + messaging_contract_address.serialize(ref calldata); + owner.serialize(ref calldata); + + let (token_bridge_address, _) = token_bridge_class_hash.deploy(@calldata).unwrap(); + + let token_bridge = ITokenBridgeDispatcher { contract_address: token_bridge_address }; + + let usdc_address = deploy_erc20("USDC", "USDC"); + + token_bridge.enroll_token(usdc_address); +} + diff --git a/tests/lib.cairo b/tests/lib.cairo index 6c2b38c..c3a3fbe 100644 --- a/tests/lib.cairo +++ b/tests/lib.cairo @@ -1,6 +1,5 @@ mod token_bridge_test; use starknet_bridge::bridge::tests::constants; -mod setup; mod withdrawal_limit_bridge_test; mod enroll_token_test; mod deposit_test; diff --git a/tests/token_bridge_test.cairo b/tests/token_bridge_test.cairo index 545c960..89c21a7 100644 --- a/tests/token_bridge_test.cairo +++ b/tests/token_bridge_test.cairo @@ -21,7 +21,7 @@ use openzeppelin::access::ownable::{ interface::{IOwnableTwoStepDispatcher, IOwnableTwoStepDispatcherTrait} }; use starknet::contract_address::{contract_address_const}; -use super::setup::{deploy_erc20, deploy_token_bridge}; +use starknet_bridge::bridge::tests::utils::setup::{deploy_erc20, deploy_token_bridge}; use super::constants::{OWNER, L3_BRIDGE_ADDRESS, USDC_MOCK_ADDRESS, DELAY_TIME}; diff --git a/tests/withdraw_test.cairo b/tests/withdraw_test.cairo index 5a248a1..15dc317 100644 --- a/tests/withdraw_test.cairo +++ b/tests/withdraw_test.cairo @@ -28,7 +28,7 @@ use openzeppelin::access::ownable::{ use openzeppelin::token::erc20::interface::{IERC20, IERC20Dispatcher, IERC20DispatcherTrait}; use starknet::contract_address::{contract_address_const}; use super::constants::{OWNER, L3_BRIDGE_ADDRESS, DELAY_TIME}; -use super::setup::{ +use starknet_bridge::bridge::tests::utils::setup::{ deploy_erc20, deploy_token_bridge_with_messaging, deploy_token_bridge, enroll_token_and_settle }; use starknet_bridge::constants; diff --git a/tests/withdrawal_limit_bridge_test.cairo b/tests/withdrawal_limit_bridge_test.cairo index f2a8e24..f504068 100644 --- a/tests/withdrawal_limit_bridge_test.cairo +++ b/tests/withdrawal_limit_bridge_test.cairo @@ -22,7 +22,7 @@ use openzeppelin::access::ownable::{ }; use starknet::contract_address::{contract_address_const}; use super::constants::{OWNER, L3_BRIDGE_ADDRESS, USDC_MOCK_ADDRESS, DELAY_TIME}; -use super::setup::{deploy_erc20, deploy_token_bridge}; +use starknet_bridge::bridge::tests::utils::setup::{deploy_erc20, deploy_token_bridge}; #[test]