From 2e79cf8fe6e9bdde2bf55400949c967d9860f568 Mon Sep 17 00:00:00 2001 From: byteZorvin Date: Mon, 22 Jul 2024 12:19:30 +0530 Subject: [PATCH 01/62] feat: initiliased testcases --- Scarb.toml | 2 +- src/bridge/token_bridge.cairo | 102 +++++++++++++++--------------- src/lib.cairo | 6 ++ tests/lib.cairo | 2 +- tests/token_bridge_test.cairo | 116 +++++++++++++++++++++++----------- 5 files changed, 140 insertions(+), 88 deletions(-) diff --git a/Scarb.toml b/Scarb.toml index d33fb78..44e30c1 100644 --- a/Scarb.toml +++ b/Scarb.toml @@ -15,7 +15,7 @@ snforge_std = { git = "https://github.com/foundry-rs/starknet-foundry", tag = "v [[target.starknet-contract]] casm = true -build-external-contracts = ["piltover::appchain::appchain"] +build-external-contracts = ["piltover::messaging::mock::messaging_mock"] [scripts] test = "snforge test" diff --git a/src/bridge/token_bridge.cairo b/src/bridge/token_bridge.cairo index aa87664..7d04365 100644 --- a/src/bridge/token_bridge.cairo +++ b/src/bridge/token_bridge.cairo @@ -91,7 +91,7 @@ pub mod TokenBridge { #[derive(Drop, starknet::Event)] #[event] - enum Event { + pub enum Event { TokenEnrollmentInitiated: TokenEnrollmentInitiated, TokenDeactivated: TokenDeactivated, TokenBlocked: TokenBlocked, @@ -117,135 +117,137 @@ pub mod TokenBridge { } #[derive(Drop, starknet::Event)] - struct TokenDeactivated { - token: ContractAddress + pub struct TokenDeactivated { + pub token: ContractAddress } #[derive(Drop, starknet::Event)] - struct TokenBlocked { - token: ContractAddress + pub struct TokenBlocked { + pub token: ContractAddress } #[derive(Drop, starknet::Event)] - struct TokenEnrollmentInitiated { + pub struct TokenEnrollmentInitiated { token: ContractAddress, deployment_message_hash: MessageHash } #[derive(Drop, starknet::Event)] - struct Deposit { + pub struct Deposit { #[key] - sender: ContractAddress, + pub sender: ContractAddress, #[key] - token: ContractAddress, - amount: u256, + pub token: ContractAddress, + pub amount: u256, #[key] appchain_recipient: ContractAddress, - nonce: Nonce, + nonce: felt252, } #[derive(Drop, starknet::Event)] - struct DepositWithMessage { + pub struct DepositWithMessage { #[key] - sender: ContractAddress, + pub sender: ContractAddress, #[key] - token: ContractAddress, - amount: u256, + pub token: ContractAddress, + pub amount: u256, #[key] appchain_recipient: ContractAddress, message: Span, - nonce: Nonce, + nonce: felt252, } #[derive(Drop, starknet::Event)] struct DepositCancelRequest { #[key] - sender: ContractAddress, + pub sender: ContractAddress, #[key] - token: ContractAddress, - amount: u256, + pub token: ContractAddress, + pub amount: u256, #[key] appchain_recipient: ContractAddress, - nonce: Nonce, + nonce: felt252, } #[derive(Drop, starknet::Event)] struct DepositWithMessageCancelRequest { #[key] - sender: ContractAddress, + pub sender: ContractAddress, #[key] - token: ContractAddress, - amount: u256, + pub token: ContractAddress, + pub amount: u256, #[key] - appchain_recipient: ContractAddress, - message: Span, - nonce: felt252 + pub appchain_recipient: ContractAddress, + pub message: Span, + pub nonce: felt252 } #[derive(Drop, starknet::Event)] - struct DepositReclaimed { + pub struct DepositReclaimed { #[key] - sender: ContractAddress, + pub sender: ContractAddress, #[key] - token: ContractAddress, - amount: u256, + pub token: ContractAddress, + pub amount: u256, #[key] appchain_recipient: ContractAddress, - nonce: Nonce + nonce: felt252 } #[derive(Drop, starknet::Event)] - struct DepositWithMessageReclaimed { + pub struct DepositWithMessageReclaimed { #[key] - sender: ContractAddress, + pub sender: ContractAddress, #[key] - token: ContractAddress, - amount: u256, + pub token: ContractAddress, + pub amount: u256, #[key] appchain_recipient: ContractAddress, message: Span, - nonce: Nonce + nonce: felt252 } #[derive(Drop, starknet::Event)] - struct Withdrawal { + pub struct Withdrawal { #[key] - recipient: ContractAddress, + pub recipient: ContractAddress, #[key] - token: ContractAddress, - amount: u256, + pub token: ContractAddress, + pub amount: u256, } #[derive(Drop, starknet::Event)] - struct WithdrawalLimitEnabled { + pub struct WithdrawalLimitEnabled { #[key] - sender: ContractAddress, + pub sender: ContractAddress, #[key] - token: ContractAddress, + pub token: ContractAddress, } #[derive(Drop, starknet::Event)] - struct WithdrawalLimitDisabled { + pub struct WithdrawalLimitDisabled { #[key] - sender: ContractAddress, + pub sender: ContractAddress, #[key] - token: ContractAddress, + pub token: ContractAddress, } #[derive(Drop, starknet::Event)] - struct SetMaxTotalBalance { + pub struct SetMaxTotalBalance { #[key] - token: ContractAddress, - value: u256 + pub token: ContractAddress, + pub value: u256 } + #[derive(Drop, starknet::Event)] pub struct SetAppchainBridge { pub appchain_bridge: ContractAddress } + #[constructor] fn constructor( ref self: ContractState, @@ -368,7 +370,7 @@ pub mod TokenBridge { self.ownable.assert_only_owner(); self.appchain_bridge.write(appchain_bridge); - self.emit(SetAppchainBridge { appchain_bridge: appchain_bridge }); + self.emit(SetAppchainBridge { appchain_bridge }); } // @param token The address of the token contract to be deactivated. diff --git a/src/lib.cairo b/src/lib.cairo index abfba84..8c0e2b0 100644 --- a/src/lib.cairo +++ b/src/lib.cairo @@ -2,6 +2,12 @@ pub mod bridge { pub mod token_bridge; pub mod interface; pub mod types; + + pub use token_bridge::TokenBridge; + pub use interface::{ + ITokenBridge, ITokenBridgeAdmin, ITokenBridgeDispatcher, ITokenBridgeAdminDispatcher, + ITokenBridgeDispatcherTrait, ITokenBridgeAdminDispatcherTrait + }; } pub mod withdrawal_limit { diff --git a/tests/lib.cairo b/tests/lib.cairo index 3b7b7da..20c8f63 100644 --- a/tests/lib.cairo +++ b/tests/lib.cairo @@ -1,2 +1,2 @@ -mod token_bridge_test; +pub mod token_bridge_test; diff --git a/tests/token_bridge_test.cairo b/tests/token_bridge_test.cairo index 1d6b9d9..78d2cea 100644 --- a/tests/token_bridge_test.cairo +++ b/tests/token_bridge_test.cairo @@ -1,35 +1,21 @@ #[cfg(test)] mod tests { - use starknet_bridge::bridge::interface::ITokenBridgeDispatcherTrait; + use core::array::ArrayTrait; use core::serde::Serde; use core::result::ResultTrait; use core::option::OptionTrait; use core::traits::TryInto; use snforge_std as snf; - use snforge_std::{ContractClassTrait}; + use snforge_std::{ContractClassTrait, EventSpy, EventSpyTrait, EventSpyAssertionsTrait}; use starknet::{ContractAddress, storage::StorageMemberAccessTrait}; use starknet_bridge::mocks::erc20::ERC20; - use starknet_bridge::bridge::interface::{ - ITokenBridgeAdmin, ITokenBridge, ITokenBridgeDispatcher + use starknet_bridge::bridge::{ + ITokenBridgeDispatcher, ITokenBridgeDispatcherTrait, ITokenBridgeAdminDispatcher, + ITokenBridgeAdminDispatcherTrait, TokenBridge, TokenBridge::Event }; - use starknet::contract_address::{contract_address_const}; - - fn deploy_token_bridge() -> (ITokenBridgeDispatcher, ContractAddress) { - let appchainCH = snf::declare("appchain").unwrap(); - let (appchainContract, _) = appchainCH - .deploy(@array!['owner'.try_into().unwrap(), 0, 0, 0]) - .unwrap(); - let l3_bridge_address = contract_address_const::<'l3_bridge_address'>(); - - let token_bridgeCH = snf::declare("TokenBridge").unwrap(); - let mut calldata = ArrayTrait::new(); - l3_bridge_address.serialize(ref calldata); - appchainContract.serialize(ref calldata); - let (token_bridge_address, _) = token_bridgeCH.deploy(@calldata).unwrap(); + use starknet::contract_address::{contract_address_const}; - (ITokenBridgeDispatcher { contract_address: token_bridge_address }, token_bridge_address) - } fn deploy_erc20(name: ByteArray, symbol: ByteArray) -> ContractAddress { let recipient: felt252 = 'owner'.try_into().unwrap(); @@ -45,21 +31,79 @@ mod tests { let (usdc, _) = erc20Ch.deploy(@constructor_args).unwrap(); return usdc; } -// #[test] -// fn constructor_ok() { -// deploy_token_bridge(); -// } -// -// #[test] -// fn test_enroll_token() { -// let (token_bridge, _) = deploy_token_bridge(); -// let usdc = deploy_erc20("USDC", "USDC"); -// let l3_bridge_address = token_bridge.appchain_bridge(); -// assert( -// l3_bridge_address == contract_address_const::<'l3_bridge_address'>(), -// 'L3 Bridge address incorrect' -// ); -// token_bridge.enroll_token(usdc); -// } + + + fn deploy_token_bridge() -> (ContractAddress, EventSpy) { + // Deploy messaging mock with 5 days cancellation delay + let messaging_mock_class = snf::declare("messaging_mock").unwrap(); + let (messaging_contract_address, _) = messaging_mock_class.deploy(@array![432000]).unwrap(); + + // Declare l3 bridge address + let l3_bridge_address = contract_address_const::<'l3_bridge_address'>(); + + // Declare owner + let owner = contract_address_const::<'owner'>(); + + let token_bridgeCH = snf::declare("TokenBridge").unwrap(); + + let mut calldata = ArrayTrait::new(); + l3_bridge_address.serialize(ref calldata); + messaging_contract_address.serialize(ref calldata); + owner.serialize(ref calldata); + + let (token_bridge_address, _) = token_bridgeCH.deploy(@calldata).unwrap(); + + let mut spy = snf::spy_events(); + + (token_bridge_address, spy) + } + + + /// Returns the state of a component 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. + fn mock_state_testing() -> TokenBridge::ContractState { + TokenBridge::contract_state_for_testing() + } + + #[test] + fn constructor_ok() { + deploy_token_bridge(); + } + + #[test] + fn set_appchain_bridge_ok() { + let (token_bridge_address, mut spy) = deploy_token_bridge(); + let token_bridge_admin = ITokenBridgeAdminDispatcher { + contract_address: token_bridge_address + }; + let token_bridge = ITokenBridgeDispatcher { contract_address: token_bridge_address }; + + // Assert for old bridge address + let old_appchain_bridge_address = token_bridge.appchain_bridge(); + assert( + old_appchain_bridge_address == contract_address_const::<'l3_bridge_address'>(), + 'L3 Bridge address incorrect' + ); + + // Cheat for the owner + snf::start_cheat_caller_address('owner'.try_into().unwrap(), token_bridge_address); + + // Set and check new bridge + let new_appchain_bridge_address = contract_address_const::<'l3_bridge_address_new'>(); + token_bridge_admin.set_appchain_token_bridge(new_appchain_bridge_address); + assert( + token_bridge.appchain_bridge() == new_appchain_bridge_address, 'Appchain bridge not set' + ); + snf::stop_cheat_caller_address(token_bridge_address); + + let expected_event = TokenBridge::SetAppchainBridge { + appchain_bridge: new_appchain_bridge_address + }; + spy + .assert_emitted( + @array![(token_bridge_address, Event::SetAppchainBridge(expected_event))] + ); + } } From 3a0db04bc2d24784ccb80d54874fa74f45f1479d Mon Sep 17 00:00:00 2001 From: byteZorvin Date: Mon, 29 Jul 2024 12:45:36 +0530 Subject: [PATCH 02/62] admin function tests --- src/bridge/token_bridge.cairo | 28 ++++---- tests/token_bridge_test.cairo | 122 ++++++++++++++++++++++++++++++---- 2 files changed, 124 insertions(+), 26 deletions(-) diff --git a/src/bridge/token_bridge.cairo b/src/bridge/token_bridge.cairo index 7d04365..a2e6dee 100644 --- a/src/bridge/token_bridge.cairo +++ b/src/bridge/token_bridge.cairo @@ -128,8 +128,8 @@ pub mod TokenBridge { #[derive(Drop, starknet::Event)] pub struct TokenEnrollmentInitiated { - token: ContractAddress, - deployment_message_hash: MessageHash + pub token: ContractAddress, + pub deployment_message_hash: MessageHash } @@ -141,8 +141,8 @@ pub mod TokenBridge { pub token: ContractAddress, pub amount: u256, #[key] - appchain_recipient: ContractAddress, - nonce: felt252, + pub appchain_recipient: ContractAddress, + pub nonce: felt252, } #[derive(Drop, starknet::Event)] @@ -153,9 +153,9 @@ pub mod TokenBridge { pub token: ContractAddress, pub amount: u256, #[key] - appchain_recipient: ContractAddress, - message: Span, - nonce: felt252, + pub appchain_recipient: ContractAddress, + pub message: Span, + pub nonce: felt252, } #[derive(Drop, starknet::Event)] @@ -166,8 +166,8 @@ pub mod TokenBridge { pub token: ContractAddress, pub amount: u256, #[key] - appchain_recipient: ContractAddress, - nonce: felt252, + pub appchain_recipient: ContractAddress, + pub nonce: felt252, } #[derive(Drop, starknet::Event)] @@ -191,8 +191,8 @@ pub mod TokenBridge { pub token: ContractAddress, pub amount: u256, #[key] - appchain_recipient: ContractAddress, - nonce: felt252 + pub appchain_recipient: ContractAddress, + pub nonce: felt252 } #[derive(Drop, starknet::Event)] @@ -203,9 +203,9 @@ pub mod TokenBridge { pub token: ContractAddress, pub amount: u256, #[key] - appchain_recipient: ContractAddress, - message: Span, - nonce: felt252 + pub appchain_recipient: ContractAddress, + pub message: Span, + pub nonce: felt252 } #[derive(Drop, starknet::Event)] diff --git a/tests/token_bridge_test.cairo b/tests/token_bridge_test.cairo index 78d2cea..550097e 100644 --- a/tests/token_bridge_test.cairo +++ b/tests/token_bridge_test.cairo @@ -1,5 +1,6 @@ #[cfg(test)] mod tests { + use openzeppelin::access::ownable::interface::IOwnableTwoStepDispatcherTrait; use core::array::ArrayTrait; use core::serde::Serde; use core::result::ResultTrait; @@ -11,9 +12,13 @@ mod tests { use starknet_bridge::mocks::erc20::ERC20; use starknet_bridge::bridge::{ ITokenBridgeDispatcher, ITokenBridgeDispatcherTrait, ITokenBridgeAdminDispatcher, - ITokenBridgeAdminDispatcherTrait, TokenBridge, TokenBridge::Event + ITokenBridgeAdminDispatcherTrait, TokenBridge, TokenBridge::Event, + types::{TokenStatus, TokenSettings} + }; + use openzeppelin::access::ownable::{ + OwnableComponent, OwnableComponent::Event as OwnableEvent, + interface::{IOwnableTwoStepDispatcher, IOwnableDispatcherTrait} }; - use starknet::contract_address::{contract_address_const}; @@ -33,29 +38,36 @@ mod tests { } - fn deploy_token_bridge() -> (ContractAddress, EventSpy) { + fn deploy_token_bridge() -> (ITokenBridgeDispatcher, EventSpy) { // Deploy messaging mock with 5 days cancellation delay let messaging_mock_class = snf::declare("messaging_mock").unwrap(); let (messaging_contract_address, _) = messaging_mock_class.deploy(@array![432000]).unwrap(); // Declare l3 bridge address - let l3_bridge_address = contract_address_const::<'l3_bridge_address'>(); + let appchain_bridge_address = contract_address_const::<'l3_bridge_address'>(); // Declare owner let owner = contract_address_const::<'owner'>(); let token_bridgeCH = snf::declare("TokenBridge").unwrap(); + // Deploy the bridge let mut calldata = ArrayTrait::new(); - l3_bridge_address.serialize(ref calldata); + appchain_bridge_address.serialize(ref calldata); messaging_contract_address.serialize(ref calldata); owner.serialize(ref calldata); let (token_bridge_address, _) = token_bridgeCH.deploy(@calldata).unwrap(); + let token_bridge = ITokenBridgeDispatcher { contract_address: token_bridge_address }; + let token_bridge_ownable = IOwnableTwoStepDispatcher { + contract_address: token_bridge_address + }; + let mut spy = snf::spy_events(); + assert(owner == token_bridge_ownable.owner(), 'Incorrect owner'); - (token_bridge_address, spy) + (token_bridge, spy) } @@ -73,11 +85,13 @@ mod tests { #[test] fn set_appchain_bridge_ok() { - let (token_bridge_address, mut spy) = deploy_token_bridge(); + let (token_bridge, mut spy) = deploy_token_bridge(); let token_bridge_admin = ITokenBridgeAdminDispatcher { - contract_address: token_bridge_address + contract_address: token_bridge.contract_address + }; + let token_bridge = ITokenBridgeDispatcher { + contract_address: token_bridge.contract_address }; - let token_bridge = ITokenBridgeDispatcher { contract_address: token_bridge_address }; // Assert for old bridge address let old_appchain_bridge_address = token_bridge.appchain_bridge(); @@ -86,8 +100,9 @@ mod tests { 'L3 Bridge address incorrect' ); + let owner = contract_address_const::<'owner'>(); // Cheat for the owner - snf::start_cheat_caller_address('owner'.try_into().unwrap(), token_bridge_address); + snf::start_cheat_caller_address(token_bridge.contract_address, owner); // Set and check new bridge let new_appchain_bridge_address = contract_address_const::<'l3_bridge_address_new'>(); @@ -95,14 +110,97 @@ mod tests { assert( token_bridge.appchain_bridge() == new_appchain_bridge_address, 'Appchain bridge not set' ); - snf::stop_cheat_caller_address(token_bridge_address); + snf::stop_cheat_caller_address(token_bridge.contract_address); let expected_event = TokenBridge::SetAppchainBridge { appchain_bridge: new_appchain_bridge_address }; spy .assert_emitted( - @array![(token_bridge_address, Event::SetAppchainBridge(expected_event))] + @array![(token_bridge.contract_address, Event::SetAppchainBridge(expected_event))] + ); + } + + #[test] + #[should_panic(expected: ('Caller is not the owner',))] + fn set_appchain_bridge_not_owner() { + let (token_bridge, mut spy) = deploy_token_bridge(); + let token_bridge_admin = ITokenBridgeAdminDispatcher { + contract_address: token_bridge.contract_address + }; + let token_bridge = ITokenBridgeDispatcher { + contract_address: token_bridge.contract_address + }; + + // Assert for old bridge address + let old_appchain_bridge_address = token_bridge.appchain_bridge(); + assert( + old_appchain_bridge_address == contract_address_const::<'l3_bridge_address'>(), + 'L3 Bridge address incorrect' + ); + + // Set and check new bridge + let new_appchain_bridge_address = contract_address_const::<'l3_bridge_address_new'>(); + token_bridge_admin.set_appchain_token_bridge(new_appchain_bridge_address); + assert( + token_bridge.appchain_bridge() == new_appchain_bridge_address, 'Appchain bridge not set' + ); + } + + #[test] + fn enroll_token_ok() { + let (token_bridge, mut spy) = deploy_token_bridge(); + + let usdc_address = deploy_erc20("USDC", "USDC"); + + let old_status = token_bridge.get_status(usdc_address); + assert(old_status == TokenStatus::Unknown, 'Should be unknown before'); + + token_bridge.enroll_token(usdc_address); + + let new_status = token_bridge.get_status(usdc_address); + assert(new_status == TokenStatus::Pending, 'Should be pending now'); + } + + #[test] + #[should_panic(expected: ('Caller is not the owner',))] + fn set_max_total_balance_not_owner() { + let (token_bridge, mut spy) = deploy_token_bridge(); + let token_bridge_admin = ITokenBridgeAdminDispatcher { + contract_address: token_bridge.contract_address + }; + + let usdc_address = deploy_erc20("USDC", "USDC"); + let decimals = 1000_000; + token_bridge_admin.set_max_total_balance(usdc_address, 50 * decimals); + } + + + #[test] + fn set_max_total_balance_ok() { + let (token_bridge, mut spy) = deploy_token_bridge(); + let token_bridge_admin = ITokenBridgeAdminDispatcher { + contract_address: token_bridge.contract_address + }; + + let usdc_address = deploy_erc20("USDC", "USDC"); + + let owner = contract_address_const::<'owner'>(); + // Cheat for the owner + snf::start_cheat_caller_address(token_bridge.contract_address, owner); + + let decimals = 1000_000; + token_bridge_admin.set_max_total_balance(usdc_address, 50 * decimals); + + snf::stop_cheat_caller_address(token_bridge.contract_address); + + let expected_event = TokenBridge::SetMaxTotalBalance { + token: usdc_address, value: 50 * decimals + }; + + spy + .assert_emitted( + @array![(token_bridge.contract_address, Event::SetMaxTotalBalance(expected_event))] ); } } From a2e6adac8ac8d1ed50d3d9ff90298cbbacfc8e91 Mon Sep 17 00:00:00 2001 From: byteZorvin Date: Mon, 29 Jul 2024 13:57:56 +0530 Subject: [PATCH 03/62] fix: max total balance check --- src/bridge/interface.cairo | 1 + src/bridge/token_bridge.cairo | 22 ++++++++++++++++++++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/bridge/interface.cairo b/src/bridge/interface.cairo index 8c8d2ef..34f749c 100644 --- a/src/bridge/interface.cairo +++ b/src/bridge/interface.cairo @@ -74,6 +74,7 @@ pub trait ITokenBridge { nonce: felt252 ); fn get_remaining_intraday_allowance(self: @TContractState, token: ContractAddress) -> u256; + fn get_max_total_balance(self: @TContractState, token: ContractAddress) -> u256; } #[starknet::interface] diff --git a/src/bridge/token_bridge.cairo b/src/bridge/token_bridge.cairo index a2e6dee..889f8a7 100644 --- a/src/bridge/token_bridge.cairo +++ b/src/bridge/token_bridge.cairo @@ -86,6 +86,7 @@ pub mod TokenBridge { pub const CANNOT_DEACTIVATE: felt252 = 'Cannot deactivate and block'; pub const CANNOT_BLOCK: felt252 = 'Cannot block'; pub const INVALID_RECIPIENT: felt252 = 'Invalid recipient'; + pub const MAX_BALANCE_EXCEEDED: felt252 = 'Max Balance Exceeded'; } @@ -327,6 +328,16 @@ pub mod TokenBridge { assert(dispatcher.balance_of(caller) == amount, 'Not enough balance'); dispatcher.transfer_from(caller, get_contract_address(), amount); } + + fn accept_deposit(self: @ContractState, token: ContractAddress, amount: u256) { + let caller = get_caller_address(); + let dispatcher = IERC20Dispatcher { contract_address: token }; + + let currentBalance: u256 = dispatcher.balance_of(get_contract_address()); + let max_total_balance = self.get_max_total_balance(token); + assert(currentBalance + amount < max_total_balance, Errors::MAX_BALANCE_EXCEEDED); + dispatcher.transfer_from(caller, get_contract_address(), amount); + } } @@ -518,8 +529,7 @@ pub mod TokenBridge { appchain_recipient: ContractAddress, message: Span ) { - self.reentrancy_guard.start(); - self.accept_deposit(token, amount); + accept_deposit(token, amount); let nonce = self .send_deposit_message( token, @@ -758,6 +768,14 @@ pub mod TokenBridge { fn is_withdrawal_limit_applied(self: @ContractState, token: ContractAddress) -> bool { self.token_settings.read(token).withdrawal_limit_applied } + + fn get_max_total_balance(self: @ContractState, token: ContractAddress) -> u256 { + let max_total_balance = self.token_settings.read(token).max_total_balance; + if (max_total_balance == 0) { + return core::integer::BoundedInt::max(); + } + return max_total_balance; + } } From ac258c13b46b12e0806d0e1ac121fbc0a72c2417 Mon Sep 17 00:00:00 2001 From: byteZorvin Date: Mon, 29 Jul 2024 15:02:35 +0530 Subject: [PATCH 04/62] feat: block token test --- tests/token_bridge_test.cairo | 48 ++++++++++++++++++++++++++++++++--- 1 file changed, 44 insertions(+), 4 deletions(-) diff --git a/tests/token_bridge_test.cairo b/tests/token_bridge_test.cairo index 550097e..73408c9 100644 --- a/tests/token_bridge_test.cairo +++ b/tests/token_bridge_test.cairo @@ -124,7 +124,7 @@ mod tests { #[test] #[should_panic(expected: ('Caller is not the owner',))] fn set_appchain_bridge_not_owner() { - let (token_bridge, mut spy) = deploy_token_bridge(); + let (token_bridge, _) = deploy_token_bridge(); let token_bridge_admin = ITokenBridgeAdminDispatcher { contract_address: token_bridge.contract_address }; @@ -149,7 +149,7 @@ mod tests { #[test] fn enroll_token_ok() { - let (token_bridge, mut spy) = deploy_token_bridge(); + let (token_bridge, _) = deploy_token_bridge(); let usdc_address = deploy_erc20("USDC", "USDC"); @@ -165,7 +165,7 @@ mod tests { #[test] #[should_panic(expected: ('Caller is not the owner',))] fn set_max_total_balance_not_owner() { - let (token_bridge, mut spy) = deploy_token_bridge(); + let (token_bridge, _) = deploy_token_bridge(); let token_bridge_admin = ITokenBridgeAdminDispatcher { contract_address: token_bridge.contract_address }; @@ -183,7 +183,7 @@ mod tests { contract_address: token_bridge.contract_address }; - let usdc_address = deploy_erc20("USDC", "USDC"); + let usdc_address = deploy_erc20("usdc", "usdc"); let owner = contract_address_const::<'owner'>(); // Cheat for the owner @@ -203,5 +203,45 @@ mod tests { @array![(token_bridge.contract_address, Event::SetMaxTotalBalance(expected_event))] ); } + + + #[test] + fn block_token_ok() { + let (token_bridge, mut spy) = deploy_token_bridge(); + let token_bridge_admin = ITokenBridgeAdminDispatcher { + contract_address: token_bridge.contract_address + }; + + let usdc_address = deploy_erc20("usdc", "usdc"); + + let owner = contract_address_const::<'owner'>(); + // Cheat for the owner + snf::start_cheat_caller_address(token_bridge.contract_address, owner); + token_bridge_admin.block_token(usdc_address); + + let expected_event = TokenBridge::TokenBlocked { token: usdc_address }; + spy + .assert_emitted( + @array![(token_bridge.contract_address, Event::TokenBlocked(expected_event))] + ); + + assert(token_bridge.get_status(usdc_address) == TokenStatus::Blocked, 'Should be blocked'); + + snf::stop_cheat_caller_address(token_bridge.contract_address); + } + + + #[test] + #[should_panic(expected: ('Caller is not the owner',))] + fn block_token_not_owner() { + let (token_bridge, _) = deploy_token_bridge(); + let token_bridge_admin = ITokenBridgeAdminDispatcher { + contract_address: token_bridge.contract_address + }; + + let usdc_address = deploy_erc20("usdc", "usdc"); + + token_bridge_admin.block_token(usdc_address); + } } From d64eb7f64233779fddd6456d465da51edb8d9562 Mon Sep 17 00:00:00 2001 From: byteZorvin Date: Tue, 30 Jul 2024 14:42:45 +0530 Subject: [PATCH 05/62] disable limit test --- src/bridge/interface.cairo | 2 +- src/bridge/token_bridge.cairo | 51 +++++++++---------------- tests/token_bridge_test.cairo | 70 +++++++++++++++++++++++++++++++++++ 3 files changed, 89 insertions(+), 34 deletions(-) diff --git a/src/bridge/interface.cairo b/src/bridge/interface.cairo index 34f749c..90ad94a 100644 --- a/src/bridge/interface.cairo +++ b/src/bridge/interface.cairo @@ -73,7 +73,7 @@ pub trait ITokenBridge { appchain_recipient: ContractAddress, nonce: felt252 ); - fn get_remaining_intraday_allowance(self: @TContractState, token: ContractAddress) -> u256; + // fn get_remaining_intraday_allowance(self: @TContractState, token: ContractAddress) -> u256; fn get_max_total_balance(self: @TContractState, token: ContractAddress) -> u256; } diff --git a/src/bridge/token_bridge.cairo b/src/bridge/token_bridge.cairo index 889f8a7..3390e08 100644 --- a/src/bridge/token_bridge.cairo +++ b/src/bridge/token_bridge.cairo @@ -1,6 +1,6 @@ #[starknet::contract] pub mod TokenBridge { - use openzeppelin::access::ownable::ownable::OwnableComponent::InternalTrait; + use starknet_bridge::withdrawal_limit::component::WithdrawalLimitComponent::InternalTrait; use core::option::OptionTrait; use core::traits::TryInto; use core::starknet::event::EventEmitter; @@ -473,16 +473,19 @@ pub mod TokenBridge { .sn_to_appchain_messages(deployment_message_hash); assert(nonce.is_non_zero(), Errors::DEPLOYMENT_MESSAGE_DOES_NOT_EXIST); - let token_status = TokenSettings { + // Reading existing settings as withdrawal_limit_applied and max_total_balance + // can be set before the token is enrolled. + + let old_settings = self.token_settings.read(token); + let new_settings = TokenSettings { token_status: TokenStatus::Pending, deployment_message_hash: deployment_message_hash, pending_deployment_expiration: get_block_timestamp() + constants::MAX_PENDING_DURATION.try_into().unwrap(), - max_total_balance: core::integer::BoundedInt::max(), - withdrawal_limit_applied: false + ..old_settings }; - self.token_settings.write(token, token_status); + self.token_settings.write(token, new_settings); self.emit(TokenEnrollmentInitiated { token, deployment_message_hash }); } @@ -588,10 +591,11 @@ pub mod TokenBridge { assert(recipient.is_non_zero(), Errors::INVALID_RECIPIENT); self.consume_message(token, amount, recipient); - let settings = self.token_settings.read(token); - // TODO: Consume quota from here - // DEP(byteZorvin): Complete the withdrawal component in cairo - if (settings.withdrawal_limit_applied) {} + + if (self.is_withdrawal_limit_applied(token)) { + self.withdrawal.consume_withdrawal_quota(token, amount); + } + let tokenDispatcher = IERC20Dispatcher { contract_address: token }; tokenDispatcher.transfer(recipient, amount); self.reentrancy_guard.end(); @@ -742,23 +746,12 @@ pub mod TokenBridge { self.token_settings.read(token).token_status == TokenStatus::Active } - // /** - // Returns the remaining amount of withdrawal allowed for this day. - // If the daily allowance was not yet set, it is calculated and returned. - // If the withdraw limit is not enabled for that token - the uint256.max is returned. - // */ - // function getRemainingIntradayAllowance(address token) external view returns (uint256) { - // return - // tokenSettings()[token].withdrawalLimitApplied - // ? WithdrawalLimit.getRemainingIntradayAllowance(token) - // : type(uint256).max; - // } - fn get_remaining_intraday_allowance(self: @ContractState, token: ContractAddress) -> u256 { - if (self.token_settings.read(token).withdrawal_limit_applied) { + fn get_max_total_balance(self: @ContractState, token: ContractAddress) -> u256 { + let max_total_balance = self.token_settings.read(token).max_total_balance; + if (max_total_balance == 0) { return core::integer::BoundedInt::max(); } - // TODO: Write the WithdrawalLimit functionality - return 0; + return max_total_balance; } } @@ -767,15 +760,7 @@ pub mod TokenBridge { impl WithdrawalLimitStatusImpl of IWithdrawalLimitStatus { fn is_withdrawal_limit_applied(self: @ContractState, token: ContractAddress) -> bool { self.token_settings.read(token).withdrawal_limit_applied - } - - fn get_max_total_balance(self: @ContractState, token: ContractAddress) -> u256 { - let max_total_balance = self.token_settings.read(token).max_total_balance; - if (max_total_balance == 0) { - return core::integer::BoundedInt::max(); - } - return max_total_balance; - } + } } diff --git a/tests/token_bridge_test.cairo b/tests/token_bridge_test.cairo index 73408c9..5e11f3e 100644 --- a/tests/token_bridge_test.cairo +++ b/tests/token_bridge_test.cairo @@ -243,5 +243,75 @@ mod tests { token_bridge_admin.block_token(usdc_address); } + + #[test] + #[should_panic(expected: ('Cannot block',))] + fn block_token_pending() { + let (token_bridge, _) = deploy_token_bridge(); + let token_bridge_admin = ITokenBridgeAdminDispatcher { + contract_address: token_bridge.contract_address + }; + + let owner = contract_address_const::<'owner'>(); + let usdc_address = deploy_erc20("usdc", "usdc"); + token_bridge.enroll_token(usdc_address); + + snf::start_cheat_caller_address(token_bridge.contract_address, owner); + token_bridge_admin.block_token(usdc_address); + } + + #[test] + #[should_panic(expected: ('Caller is not the owner',))] + fn enable_withdrawal_limit_not_owner() { + let (token_bridge, _) = deploy_token_bridge(); + let token_bridge_admin = ITokenBridgeAdminDispatcher { + contract_address: token_bridge.contract_address + }; + + let usdc_address = deploy_erc20("USDC", "USDC"); + token_bridge_admin.enable_withdrawal_limit(usdc_address); + } + + #[test] + fn enable_withdrawal_limit_ok() { + let (token_bridge, _) = deploy_token_bridge(); + let token_bridge_admin = ITokenBridgeAdminDispatcher { + contract_address: token_bridge.contract_address + }; + + let owner = contract_address_const::<'owner'>(); + snf::start_cheat_caller_address(token_bridge.contract_address, owner); + + let usdc_address = deploy_erc20("USDC", "USDC"); + token_bridge_admin.enable_withdrawal_limit(usdc_address); + + snf::stop_cheat_caller_address(token_bridge.contract_address); + + assert(token_bridge.is_withdrawal_limit_applied(usdc_address), 'Limit not applied'); + } + + #[test] + fn disable_withdrwal_limit_ok() { + let (token_bridge, _) = deploy_token_bridge(); + let token_bridge_admin = ITokenBridgeAdminDispatcher { + contract_address: token_bridge.contract_address + }; + + let owner = contract_address_const::<'owner'>(); + snf::start_cheat_caller_address(token_bridge.contract_address, owner); + + let usdc_address = deploy_erc20("USDC", "USDC"); + token_bridge_admin.enable_withdrawal_limit(usdc_address); + + // Withdrawal limit is now applied + assert(token_bridge.is_withdrawal_limit_applied(usdc_address), 'Limit not applied'); + + token_bridge_admin.disable_withdrawal_limit(usdc_address); + + assert( + token_bridge.is_withdrawal_limit_applied(usdc_address) == false, 'Limit not applied' + ); + snf::stop_cheat_caller_address(token_bridge.contract_address); + } } From 19d7fb0907ffa27c39d2f9e9fd6e74dd2fcdedf9 Mon Sep 17 00:00:00 2001 From: byteZorvin Date: Tue, 30 Jul 2024 15:24:20 +0530 Subject: [PATCH 06/62] feat: add failing tc for withdraw limit --- tests/token_bridge_test.cairo | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/tests/token_bridge_test.cairo b/tests/token_bridge_test.cairo index 5e11f3e..cc1983c 100644 --- a/tests/token_bridge_test.cairo +++ b/tests/token_bridge_test.cairo @@ -313,5 +313,31 @@ mod tests { ); snf::stop_cheat_caller_address(token_bridge.contract_address); } + + #[test] + #[should_panic(expected: ('Caller is not the owner',))] + fn disable_withdrwal_not_owner() { + let (token_bridge, _) = deploy_token_bridge(); + let token_bridge_admin = ITokenBridgeAdminDispatcher { + contract_address: token_bridge.contract_address + }; + + let owner = contract_address_const::<'owner'>(); + snf::start_cheat_caller_address(token_bridge.contract_address, owner); + + let usdc_address = deploy_erc20("USDC", "USDC"); + token_bridge_admin.enable_withdrawal_limit(usdc_address); + + // Withdrawal limit is now applied + assert(token_bridge.is_withdrawal_limit_applied(usdc_address), 'Limit not applied'); + + snf::stop_cheat_caller_address(token_bridge.contract_address); + + token_bridge_admin.disable_withdrawal_limit(usdc_address); + + assert( + token_bridge.is_withdrawal_limit_applied(usdc_address) == false, 'Limit not applied' + ); + } } From b84a398f6afaa0f67e9b5ee0c1479a9553fff368 Mon Sep 17 00:00:00 2001 From: byteZorvin Date: Tue, 30 Jul 2024 15:58:40 +0530 Subject: [PATCH 07/62] fixed testcases after rebase --- scripts/my_script/Scarb.lock | 14 -------------- scripts/my_script/Scarb.toml | 10 ---------- scripts/my_script/src/lib.cairo | 1 - src/bridge/token_bridge.cairo | 12 ++---------- src/lib.cairo | 6 ++++-- src/withdrawal_limit/component.cairo | 3 +-- tests/token_bridge_test.cairo | 23 +++++++++++++++++------ 7 files changed, 24 insertions(+), 45 deletions(-) delete mode 100644 scripts/my_script/Scarb.lock delete mode 100644 scripts/my_script/Scarb.toml delete mode 100644 scripts/my_script/src/lib.cairo diff --git a/scripts/my_script/Scarb.lock b/scripts/my_script/Scarb.lock deleted file mode 100644 index 8184873..0000000 --- a/scripts/my_script/Scarb.lock +++ /dev/null @@ -1,14 +0,0 @@ -# Code generated by scarb DO NOT EDIT. -version = 1 - -[[package]] -name = "my_script" -version = "0.1.0" -dependencies = [ - "sncast_std", -] - -[[package]] -name = "sncast_std" -version = "0.26.0" -source = "git+https://github.com/foundry-rs/starknet-foundry?tag=v0.26.0#50eb589db65e113efe4f09241feb59b574228c7e" diff --git a/scripts/my_script/Scarb.toml b/scripts/my_script/Scarb.toml deleted file mode 100644 index 1772854..0000000 --- a/scripts/my_script/Scarb.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "my_script" -version = "0.1.0" -edition = "2023_11" - -# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest.html - -[dependencies] -sncast_std = { git = "https://github.com/foundry-rs/starknet-foundry", tag = "v0.26.0" } -starknet = ">=2.6.4" diff --git a/scripts/my_script/src/lib.cairo b/scripts/my_script/src/lib.cairo deleted file mode 100644 index 3276bf6..0000000 --- a/scripts/my_script/src/lib.cairo +++ /dev/null @@ -1 +0,0 @@ -mod my_script; diff --git a/src/bridge/token_bridge.cairo b/src/bridge/token_bridge.cairo index 3390e08..356290d 100644 --- a/src/bridge/token_bridge.cairo +++ b/src/bridge/token_bridge.cairo @@ -248,7 +248,6 @@ pub mod TokenBridge { } - #[constructor] fn constructor( ref self: ContractState, @@ -325,13 +324,6 @@ pub mod TokenBridge { self.is_servicing_token(token); let caller = get_caller_address(); let dispatcher = IERC20Dispatcher { contract_address: token }; - assert(dispatcher.balance_of(caller) == amount, 'Not enough balance'); - dispatcher.transfer_from(caller, get_contract_address(), amount); - } - - fn accept_deposit(self: @ContractState, token: ContractAddress, amount: u256) { - let caller = get_caller_address(); - let dispatcher = IERC20Dispatcher { contract_address: token }; let currentBalance: u256 = dispatcher.balance_of(get_contract_address()); let max_total_balance = self.get_max_total_balance(token); @@ -532,7 +524,7 @@ pub mod TokenBridge { appchain_recipient: ContractAddress, message: Span ) { - accept_deposit(token, amount); + self.accept_deposit(token, amount); let nonce = self .send_deposit_message( token, @@ -760,7 +752,7 @@ pub mod TokenBridge { impl WithdrawalLimitStatusImpl of IWithdrawalLimitStatus { fn is_withdrawal_limit_applied(self: @ContractState, token: ContractAddress) -> bool { self.token_settings.read(token).withdrawal_limit_applied - } + } } diff --git a/src/lib.cairo b/src/lib.cairo index 8c0e2b0..7362755 100644 --- a/src/lib.cairo +++ b/src/lib.cairo @@ -5,8 +5,10 @@ pub mod bridge { pub use token_bridge::TokenBridge; pub use interface::{ - ITokenBridge, ITokenBridgeAdmin, ITokenBridgeDispatcher, ITokenBridgeAdminDispatcher, - ITokenBridgeDispatcherTrait, ITokenBridgeAdminDispatcherTrait + ITokenBridge, ITokenBridgeAdmin, IWithdrawalLimitStatus, ITokenBridgeDispatcher, + ITokenBridgeAdminDispatcher, IWithdrawalLimitStatusDispatcher, + IWithdrawalLimitStatusDispatcherTrait, ITokenBridgeDispatcherTrait, + ITokenBridgeAdminDispatcherTrait }; } diff --git a/src/withdrawal_limit/component.cairo b/src/withdrawal_limit/component.cairo index 7615642..ebf0ab3 100644 --- a/src/withdrawal_limit/component.cairo +++ b/src/withdrawal_limit/component.cairo @@ -1,8 +1,7 @@ #[starknet::component] pub mod WithdrawalLimitComponent { use starknet::{ContractAddress, get_block_timestamp, get_contract_address}; - use starknet_bridge::bridge::interface::IWithdrawalLimitStatus; - use starknet_bridge::constants; + use starknet_bridge::{constants, bridge::IWithdrawalLimitStatus}; use core::integer::BoundedInt; use openzeppelin::token::erc20::interface::{IERC20Dispatcher, IERC20DispatcherTrait}; diff --git a/tests/token_bridge_test.cairo b/tests/token_bridge_test.cairo index cc1983c..8fbb567 100644 --- a/tests/token_bridge_test.cairo +++ b/tests/token_bridge_test.cairo @@ -12,7 +12,8 @@ mod tests { use starknet_bridge::mocks::erc20::ERC20; use starknet_bridge::bridge::{ ITokenBridgeDispatcher, ITokenBridgeDispatcherTrait, ITokenBridgeAdminDispatcher, - ITokenBridgeAdminDispatcherTrait, TokenBridge, TokenBridge::Event, + ITokenBridgeAdminDispatcherTrait, IWithdrawalLimitStatusDispatcher, + IWithdrawalLimitStatusDispatcherTrait, TokenBridge, TokenBridge::Event, types::{TokenStatus, TokenSettings} }; use openzeppelin::access::ownable::{ @@ -278,6 +279,9 @@ mod tests { let token_bridge_admin = ITokenBridgeAdminDispatcher { contract_address: token_bridge.contract_address }; + let withdrawal_limit = IWithdrawalLimitStatusDispatcher { + contract_address: token_bridge.contract_address + }; let owner = contract_address_const::<'owner'>(); snf::start_cheat_caller_address(token_bridge.contract_address, owner); @@ -287,7 +291,7 @@ mod tests { snf::stop_cheat_caller_address(token_bridge.contract_address); - assert(token_bridge.is_withdrawal_limit_applied(usdc_address), 'Limit not applied'); + assert(withdrawal_limit.is_withdrawal_limit_applied(usdc_address), 'Limit not applied'); } #[test] @@ -296,6 +300,9 @@ mod tests { let token_bridge_admin = ITokenBridgeAdminDispatcher { contract_address: token_bridge.contract_address }; + let withdrawal_limit = IWithdrawalLimitStatusDispatcher { + contract_address: token_bridge.contract_address + }; let owner = contract_address_const::<'owner'>(); snf::start_cheat_caller_address(token_bridge.contract_address, owner); @@ -304,12 +311,12 @@ mod tests { token_bridge_admin.enable_withdrawal_limit(usdc_address); // Withdrawal limit is now applied - assert(token_bridge.is_withdrawal_limit_applied(usdc_address), 'Limit not applied'); + assert(withdrawal_limit.is_withdrawal_limit_applied(usdc_address), 'Limit not applied'); token_bridge_admin.disable_withdrawal_limit(usdc_address); assert( - token_bridge.is_withdrawal_limit_applied(usdc_address) == false, 'Limit not applied' + withdrawal_limit.is_withdrawal_limit_applied(usdc_address) == false, 'Limit not applied' ); snf::stop_cheat_caller_address(token_bridge.contract_address); } @@ -322,6 +329,10 @@ mod tests { contract_address: token_bridge.contract_address }; + let withdrawal_limit = IWithdrawalLimitStatusDispatcher { + contract_address: token_bridge.contract_address + }; + let owner = contract_address_const::<'owner'>(); snf::start_cheat_caller_address(token_bridge.contract_address, owner); @@ -329,14 +340,14 @@ mod tests { token_bridge_admin.enable_withdrawal_limit(usdc_address); // Withdrawal limit is now applied - assert(token_bridge.is_withdrawal_limit_applied(usdc_address), 'Limit not applied'); + assert(withdrawal_limit.is_withdrawal_limit_applied(usdc_address), 'Limit not applied'); snf::stop_cheat_caller_address(token_bridge.contract_address); token_bridge_admin.disable_withdrawal_limit(usdc_address); assert( - token_bridge.is_withdrawal_limit_applied(usdc_address) == false, 'Limit not applied' + withdrawal_limit.is_withdrawal_limit_applied(usdc_address) == false, 'Limit not applied' ); } } From c2488505fbbfa5e3f67200472a7262137a067e3b Mon Sep 17 00:00:00 2001 From: byteZorvin Date: Wed, 31 Jul 2024 11:58:57 +0530 Subject: [PATCH 08/62] chore: added messaging mock --- Scarb.toml | 1 - src/lib.cairo | 1 + src/mocks/messaging.cairo | 45 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 src/mocks/messaging.cairo diff --git a/Scarb.toml b/Scarb.toml index 44e30c1..a61e77c 100644 --- a/Scarb.toml +++ b/Scarb.toml @@ -15,7 +15,6 @@ snforge_std = { git = "https://github.com/foundry-rs/starknet-foundry", tag = "v [[target.starknet-contract]] casm = true -build-external-contracts = ["piltover::messaging::mock::messaging_mock"] [scripts] test = "snforge test" diff --git a/src/lib.cairo b/src/lib.cairo index 7362755..35b2563 100644 --- a/src/lib.cairo +++ b/src/lib.cairo @@ -21,5 +21,6 @@ pub mod constants; pub mod mocks { pub mod erc20; + pub mod messaging; } diff --git a/src/mocks/messaging.cairo b/src/mocks/messaging.cairo new file mode 100644 index 0000000..60740aa --- /dev/null +++ b/src/mocks/messaging.cairo @@ -0,0 +1,45 @@ +use piltover::messaging::output_process::MessageToAppchain; +#[starknet::interface] +trait IMockMessaging { + fn update_state(ref self: TState, messages: Span); +} + +#[starknet::contract] +mod messaging_mock { + use piltover::messaging::{ + output_process::MessageToAppchain, messaging_cpt, + messaging_cpt::InternalTrait as MessagingInternal, IMessaging + }; + use starknet::ContractAddress; + use super::IMockMessaging; + + component!(path: messaging_cpt, storage: messaging, event: MessagingEvent); + + #[abi(embed_v0)] + impl MessagingImpl = messaging_cpt::MessagingImpl; + + #[storage] + struct Storage { + #[substorage(v0)] + messaging: messaging_cpt::Storage + } + + #[event] + #[derive(Drop, starknet::Event)] + enum Event { + #[flat] + MessagingEvent: messaging_cpt::Event + } + + #[constructor] + fn constructor(ref self: ContractState, cancellation_delay_secs: u64) { + self.messaging.initialize(cancellation_delay_secs); + } + + #[abi(embed_v0)] + impl MockMessagingImpl of IMockMessaging { + fn update_state(ref self: ContractState, messages: Span) { + self.messaging.process_messages_to_appchain(messages); + } + } +} From 7a3b3f8759780fd1e2ff95be3d955fad8fc2b80e Mon Sep 17 00:00:00 2001 From: Mehul Chauhan Date: Wed, 31 Jul 2024 14:56:20 +0530 Subject: [PATCH 09/62] Update src/bridge/token_bridge.cairo Co-authored-by: Apoorv Sadana <95699312+apoorvsadana@users.noreply.github.com> --- src/bridge/token_bridge.cairo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bridge/token_bridge.cairo b/src/bridge/token_bridge.cairo index 356290d..011b489 100644 --- a/src/bridge/token_bridge.cairo +++ b/src/bridge/token_bridge.cairo @@ -325,7 +325,7 @@ pub mod TokenBridge { let caller = get_caller_address(); let dispatcher = IERC20Dispatcher { contract_address: token }; - let currentBalance: u256 = dispatcher.balance_of(get_contract_address()); + let current_balance: u256 = dispatcher.balance_of(get_contract_address()); let max_total_balance = self.get_max_total_balance(token); assert(currentBalance + amount < max_total_balance, Errors::MAX_BALANCE_EXCEEDED); dispatcher.transfer_from(caller, get_contract_address(), amount); From 4cf51a9bc81cf04951897cf58c787b2bf5210c58 Mon Sep 17 00:00:00 2001 From: byteZorvin Date: Wed, 31 Jul 2024 15:32:40 +0530 Subject: [PATCH 10/62] resolve comments --- src/bridge/interface.cairo | 1 - src/bridge/token_bridge.cairo | 6 +- tests/constants.cairo | 14 + tests/lib.cairo | 1 + tests/token_bridge_test.cairo | 583 +++++++++++++++++----------------- 5 files changed, 302 insertions(+), 303 deletions(-) create mode 100644 tests/constants.cairo diff --git a/src/bridge/interface.cairo b/src/bridge/interface.cairo index 90ad94a..65265b3 100644 --- a/src/bridge/interface.cairo +++ b/src/bridge/interface.cairo @@ -73,7 +73,6 @@ pub trait ITokenBridge { appchain_recipient: ContractAddress, nonce: felt252 ); - // fn get_remaining_intraday_allowance(self: @TContractState, token: ContractAddress) -> u256; fn get_max_total_balance(self: @TContractState, token: ContractAddress) -> u256; } diff --git a/src/bridge/token_bridge.cairo b/src/bridge/token_bridge.cairo index 011b489..7fa8f02 100644 --- a/src/bridge/token_bridge.cairo +++ b/src/bridge/token_bridge.cairo @@ -327,7 +327,7 @@ pub mod TokenBridge { let current_balance: u256 = dispatcher.balance_of(get_contract_address()); let max_total_balance = self.get_max_total_balance(token); - assert(currentBalance + amount < max_total_balance, Errors::MAX_BALANCE_EXCEEDED); + assert(current_balance + amount < max_total_balance, Errors::MAX_BALANCE_EXCEEDED); dispatcher.transfer_from(caller, get_contract_address(), amount); } } @@ -584,9 +584,7 @@ pub mod TokenBridge { self.consume_message(token, amount, recipient); - if (self.is_withdrawal_limit_applied(token)) { - self.withdrawal.consume_withdrawal_quota(token, amount); - } + self.withdrawal.consume_withdrawal_quota(token, amount); let tokenDispatcher = IERC20Dispatcher { contract_address: token }; tokenDispatcher.transfer(recipient, amount); diff --git a/tests/constants.cairo b/tests/constants.cairo new file mode 100644 index 0000000..cb8f018 --- /dev/null +++ b/tests/constants.cairo @@ -0,0 +1,14 @@ +use starknet::{ContractAddress, contract_address_const}; + +pub fn OWNER() -> ContractAddress { + contract_address_const::<'OWNER'>() +} + +pub fn L3_BRIDGE_ADDRESS() -> ContractAddress { + contract_address_const::<'l3_bridge_address'>() +} + + +// 5 days as the delay time (5 * 86400 = 432000) +pub const DELAY_TIME: felt252 = 432000; + diff --git a/tests/lib.cairo b/tests/lib.cairo index 20c8f63..178f4a1 100644 --- a/tests/lib.cairo +++ b/tests/lib.cairo @@ -1,2 +1,3 @@ pub mod token_bridge_test; +pub mod constants; diff --git a/tests/token_bridge_test.cairo b/tests/token_bridge_test.cairo index 8fbb567..f108a04 100644 --- a/tests/token_bridge_test.cairo +++ b/tests/token_bridge_test.cairo @@ -1,354 +1,341 @@ -#[cfg(test)] -mod tests { - use openzeppelin::access::ownable::interface::IOwnableTwoStepDispatcherTrait; - use core::array::ArrayTrait; - use core::serde::Serde; - use core::result::ResultTrait; - use core::option::OptionTrait; - use core::traits::TryInto; - use snforge_std as snf; - use snforge_std::{ContractClassTrait, EventSpy, EventSpyTrait, EventSpyAssertionsTrait}; - use starknet::{ContractAddress, storage::StorageMemberAccessTrait}; - use starknet_bridge::mocks::erc20::ERC20; - use starknet_bridge::bridge::{ - ITokenBridgeDispatcher, ITokenBridgeDispatcherTrait, ITokenBridgeAdminDispatcher, - ITokenBridgeAdminDispatcherTrait, IWithdrawalLimitStatusDispatcher, - IWithdrawalLimitStatusDispatcherTrait, TokenBridge, TokenBridge::Event, - types::{TokenStatus, TokenSettings} - }; - use openzeppelin::access::ownable::{ - OwnableComponent, OwnableComponent::Event as OwnableEvent, - interface::{IOwnableTwoStepDispatcher, IOwnableDispatcherTrait} - }; - use starknet::contract_address::{contract_address_const}; +use openzeppelin::access::ownable::interface::IOwnableTwoStepDispatcherTrait; +use core::array::ArrayTrait; +use core::serde::Serde; +use core::result::ResultTrait; +use core::option::OptionTrait; +use core::traits::TryInto; +use snforge_std as snf; +use snforge_std::{ContractClassTrait, EventSpy, EventSpyTrait, EventSpyAssertionsTrait}; +use starknet::{ContractAddress, storage::StorageMemberAccessTrait}; +use starknet_bridge::mocks::erc20::ERC20; +use starknet_bridge::bridge::{ + ITokenBridgeDispatcher, ITokenBridgeDispatcherTrait, ITokenBridgeAdminDispatcher, + ITokenBridgeAdminDispatcherTrait, IWithdrawalLimitStatusDispatcher, + IWithdrawalLimitStatusDispatcherTrait, TokenBridge, TokenBridge::Event, + types::{TokenStatus, TokenSettings} +}; +use openzeppelin::access::ownable::{ + OwnableComponent, OwnableComponent::Event as OwnableEvent, + interface::{IOwnableTwoStepDispatcher, IOwnableDispatcherTrait} +}; +use starknet::contract_address::{contract_address_const}; +use super::constants::{OWNER, L3_BRIDGE_ADDRESS, DELAY_TIME}; + + +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; +} - fn deploy_erc20(name: ByteArray, symbol: ByteArray) -> ContractAddress { - let recipient: felt252 = 'owner'.try_into().unwrap(); +fn deploy_token_bridge() -> (ITokenBridgeDispatcher, EventSpy) { + // Deploy messaging mock with 5 days cancellation delay + let messaging_mock_class_hash = snf::declare("messaging_mock").unwrap(); + // Deploying with 5 days as the delay time (5 * 86400 = 432000) + let (messaging_contract_address, _) = messaging_mock_class_hash + .deploy(@array![DELAY_TIME]) + .unwrap(); - let erc20Ch = 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); - recipient.serialize(ref constructor_args); + // Declare l3 bridge address + let appchain_bridge_address = L3_BRIDGE_ADDRESS(); - let (usdc, _) = erc20Ch.deploy(@constructor_args).unwrap(); - return usdc; - } + // Declare owner + let owner = OWNER(); + let token_bridge_class_hash = snf::declare("TokenBridge").unwrap(); - fn deploy_token_bridge() -> (ITokenBridgeDispatcher, EventSpy) { - // Deploy messaging mock with 5 days cancellation delay - let messaging_mock_class = snf::declare("messaging_mock").unwrap(); - let (messaging_contract_address, _) = messaging_mock_class.deploy(@array![432000]).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); - // Declare l3 bridge address - let appchain_bridge_address = contract_address_const::<'l3_bridge_address'>(); + let (token_bridge_address, _) = token_bridge_class_hash.deploy(@calldata).unwrap(); - // Declare owner - let owner = contract_address_const::<'owner'>(); + let token_bridge = ITokenBridgeDispatcher { contract_address: token_bridge_address }; + let token_bridge_ownable = IOwnableTwoStepDispatcher { contract_address: token_bridge_address }; - let token_bridgeCH = snf::declare("TokenBridge").unwrap(); + let mut spy = snf::spy_events(); + assert(owner == token_bridge_ownable.owner(), 'Incorrect owner'); - // Deploy the bridge - let mut calldata = ArrayTrait::new(); - appchain_bridge_address.serialize(ref calldata); - messaging_contract_address.serialize(ref calldata); - owner.serialize(ref calldata); + (token_bridge, spy) +} - let (token_bridge_address, _) = token_bridgeCH.deploy(@calldata).unwrap(); - let token_bridge = ITokenBridgeDispatcher { contract_address: token_bridge_address }; - let token_bridge_ownable = IOwnableTwoStepDispatcher { - contract_address: token_bridge_address - }; +/// Returns the state of a component 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. +fn mock_state_testing() -> TokenBridge::ContractState { + TokenBridge::contract_state_for_testing() +} - let mut spy = snf::spy_events(); - assert(owner == token_bridge_ownable.owner(), 'Incorrect owner'); +#[test] +fn constructor_ok() { + deploy_token_bridge(); +} - (token_bridge, spy) - } +#[test] +fn set_appchain_bridge_ok() { + let (token_bridge, mut spy) = deploy_token_bridge(); + let token_bridge_admin = ITokenBridgeAdminDispatcher { + contract_address: token_bridge.contract_address + }; + let token_bridge = ITokenBridgeDispatcher { contract_address: token_bridge.contract_address }; + + // Assert for old bridge address + let old_appchain_bridge_address = token_bridge.appchain_bridge(); + assert(old_appchain_bridge_address == L3_BRIDGE_ADDRESS(), 'L3 Bridge address incorrect'); + + let owner = OWNER(); + // Cheat for the owner + snf::start_cheat_caller_address(token_bridge.contract_address, owner); + + // Set and check new bridge + let new_appchain_bridge_address = contract_address_const::<'l3_bridge_address_new'>(); + token_bridge_admin.set_appchain_token_bridge(new_appchain_bridge_address); + assert( + token_bridge.appchain_bridge() == new_appchain_bridge_address, 'Appchain bridge not set' + ); + snf::stop_cheat_caller_address(token_bridge.contract_address); + + let expected_event = TokenBridge::SetAppchainBridge { + appchain_bridge: new_appchain_bridge_address + }; + spy + .assert_emitted( + @array![(token_bridge.contract_address, Event::SetAppchainBridge(expected_event))] + ); +} +#[test] +#[should_panic(expected: ('Caller is not the owner',))] +fn set_appchain_bridge_not_owner() { + let (token_bridge, _) = deploy_token_bridge(); + let token_bridge_admin = ITokenBridgeAdminDispatcher { + contract_address: token_bridge.contract_address + }; + let token_bridge = ITokenBridgeDispatcher { contract_address: token_bridge.contract_address }; + + // Assert for old bridge address + let old_appchain_bridge_address = token_bridge.appchain_bridge(); + assert(old_appchain_bridge_address == L3_BRIDGE_ADDRESS(), 'L3 Bridge address incorrect'); + + // Set and check new bridge + let new_appchain_bridge_address = contract_address_const::<'l3_bridge_address_new'>(); + token_bridge_admin.set_appchain_token_bridge(new_appchain_bridge_address); + assert( + token_bridge.appchain_bridge() == new_appchain_bridge_address, 'Appchain bridge not set' + ); +} - /// Returns the state of a component 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. - fn mock_state_testing() -> TokenBridge::ContractState { - TokenBridge::contract_state_for_testing() - } +#[test] +fn enroll_token_ok() { + let (token_bridge, _) = deploy_token_bridge(); - #[test] - fn constructor_ok() { - deploy_token_bridge(); - } + let usdc_address = deploy_erc20("USDC", "USDC"); - #[test] - fn set_appchain_bridge_ok() { - let (token_bridge, mut spy) = deploy_token_bridge(); - let token_bridge_admin = ITokenBridgeAdminDispatcher { - contract_address: token_bridge.contract_address - }; - let token_bridge = ITokenBridgeDispatcher { - contract_address: token_bridge.contract_address - }; + let old_status = token_bridge.get_status(usdc_address); + assert(old_status == TokenStatus::Unknown, 'Should be unknown before'); - // Assert for old bridge address - let old_appchain_bridge_address = token_bridge.appchain_bridge(); - assert( - old_appchain_bridge_address == contract_address_const::<'l3_bridge_address'>(), - 'L3 Bridge address incorrect' - ); + token_bridge.enroll_token(usdc_address); - let owner = contract_address_const::<'owner'>(); - // Cheat for the owner - snf::start_cheat_caller_address(token_bridge.contract_address, owner); + let new_status = token_bridge.get_status(usdc_address); + assert(new_status == TokenStatus::Pending, 'Should be pending now'); +} - // Set and check new bridge - let new_appchain_bridge_address = contract_address_const::<'l3_bridge_address_new'>(); - token_bridge_admin.set_appchain_token_bridge(new_appchain_bridge_address); - assert( - token_bridge.appchain_bridge() == new_appchain_bridge_address, 'Appchain bridge not set' - ); - snf::stop_cheat_caller_address(token_bridge.contract_address); - - let expected_event = TokenBridge::SetAppchainBridge { - appchain_bridge: new_appchain_bridge_address - }; - spy - .assert_emitted( - @array![(token_bridge.contract_address, Event::SetAppchainBridge(expected_event))] - ); - } - - #[test] - #[should_panic(expected: ('Caller is not the owner',))] - fn set_appchain_bridge_not_owner() { - let (token_bridge, _) = deploy_token_bridge(); - let token_bridge_admin = ITokenBridgeAdminDispatcher { - contract_address: token_bridge.contract_address - }; - let token_bridge = ITokenBridgeDispatcher { - contract_address: token_bridge.contract_address - }; - - // Assert for old bridge address - let old_appchain_bridge_address = token_bridge.appchain_bridge(); - assert( - old_appchain_bridge_address == contract_address_const::<'l3_bridge_address'>(), - 'L3 Bridge address incorrect' +#[test] +#[should_panic(expected: ('Caller is not the owner',))] +fn set_max_total_balance_not_owner() { + let (token_bridge, _) = deploy_token_bridge(); + let token_bridge_admin = ITokenBridgeAdminDispatcher { + contract_address: token_bridge.contract_address + }; + + let usdc_address = deploy_erc20("USDC", "USDC"); + let decimals = 1000_000; + token_bridge_admin.set_max_total_balance(usdc_address, 50 * decimals); +} + + +#[test] +fn set_max_total_balance_ok() { + let (token_bridge, mut spy) = deploy_token_bridge(); + let token_bridge_admin = ITokenBridgeAdminDispatcher { + contract_address: token_bridge.contract_address + }; + + let usdc_address = deploy_erc20("usdc", "usdc"); + + let owner = OWNER(); + // Cheat for the owner + snf::start_cheat_caller_address(token_bridge.contract_address, owner); + + let decimals = 1000_000; + token_bridge_admin.set_max_total_balance(usdc_address, 50 * decimals); + + snf::stop_cheat_caller_address(token_bridge.contract_address); + + let expected_event = TokenBridge::SetMaxTotalBalance { + token: usdc_address, value: 50 * decimals + }; + + spy + .assert_emitted( + @array![(token_bridge.contract_address, Event::SetMaxTotalBalance(expected_event))] ); +} + + +#[test] +fn block_token_ok() { + let (token_bridge, mut spy) = deploy_token_bridge(); + let token_bridge_admin = ITokenBridgeAdminDispatcher { + contract_address: token_bridge.contract_address + }; + + let usdc_address = deploy_erc20("usdc", "usdc"); - // Set and check new bridge - let new_appchain_bridge_address = contract_address_const::<'l3_bridge_address_new'>(); - token_bridge_admin.set_appchain_token_bridge(new_appchain_bridge_address); - assert( - token_bridge.appchain_bridge() == new_appchain_bridge_address, 'Appchain bridge not set' + let owner = OWNER(); + // Cheat for the owner + snf::start_cheat_caller_address(token_bridge.contract_address, owner); + token_bridge_admin.block_token(usdc_address); + + let expected_event = TokenBridge::TokenBlocked { token: usdc_address }; + spy + .assert_emitted( + @array![(token_bridge.contract_address, Event::TokenBlocked(expected_event))] ); - } - #[test] - fn enroll_token_ok() { - let (token_bridge, _) = deploy_token_bridge(); + assert(token_bridge.get_status(usdc_address) == TokenStatus::Blocked, 'Should be blocked'); - let usdc_address = deploy_erc20("USDC", "USDC"); + snf::stop_cheat_caller_address(token_bridge.contract_address); +} - let old_status = token_bridge.get_status(usdc_address); - assert(old_status == TokenStatus::Unknown, 'Should be unknown before'); - token_bridge.enroll_token(usdc_address); +#[test] +#[should_panic(expected: ('Caller is not the owner',))] +fn block_token_not_owner() { + let (token_bridge, _) = deploy_token_bridge(); + let token_bridge_admin = ITokenBridgeAdminDispatcher { + contract_address: token_bridge.contract_address + }; - let new_status = token_bridge.get_status(usdc_address); - assert(new_status == TokenStatus::Pending, 'Should be pending now'); - } + let usdc_address = deploy_erc20("usdc", "usdc"); - #[test] - #[should_panic(expected: ('Caller is not the owner',))] - fn set_max_total_balance_not_owner() { - let (token_bridge, _) = deploy_token_bridge(); - let token_bridge_admin = ITokenBridgeAdminDispatcher { - contract_address: token_bridge.contract_address - }; + token_bridge_admin.block_token(usdc_address); +} - let usdc_address = deploy_erc20("USDC", "USDC"); - let decimals = 1000_000; - token_bridge_admin.set_max_total_balance(usdc_address, 50 * decimals); - } +#[test] +#[should_panic(expected: ('Cannot block',))] +fn block_token_pending() { + let (token_bridge, _) = deploy_token_bridge(); + let token_bridge_admin = ITokenBridgeAdminDispatcher { + contract_address: token_bridge.contract_address + }; + let owner = OWNER(); + let usdc_address = deploy_erc20("usdc", "usdc"); + token_bridge.enroll_token(usdc_address); - #[test] - fn set_max_total_balance_ok() { - let (token_bridge, mut spy) = deploy_token_bridge(); - let token_bridge_admin = ITokenBridgeAdminDispatcher { - contract_address: token_bridge.contract_address - }; - - let usdc_address = deploy_erc20("usdc", "usdc"); - - let owner = contract_address_const::<'owner'>(); - // Cheat for the owner - snf::start_cheat_caller_address(token_bridge.contract_address, owner); - - let decimals = 1000_000; - token_bridge_admin.set_max_total_balance(usdc_address, 50 * decimals); + snf::start_cheat_caller_address(token_bridge.contract_address, owner); + token_bridge_admin.block_token(usdc_address); +} - snf::stop_cheat_caller_address(token_bridge.contract_address); +#[test] +#[should_panic(expected: ('Caller is not the owner',))] +fn enable_withdrawal_limit_not_owner() { + let (token_bridge, _) = deploy_token_bridge(); + let token_bridge_admin = ITokenBridgeAdminDispatcher { + contract_address: token_bridge.contract_address + }; - let expected_event = TokenBridge::SetMaxTotalBalance { - token: usdc_address, value: 50 * decimals - }; - - spy - .assert_emitted( - @array![(token_bridge.contract_address, Event::SetMaxTotalBalance(expected_event))] - ); - } - - - #[test] - fn block_token_ok() { - let (token_bridge, mut spy) = deploy_token_bridge(); - let token_bridge_admin = ITokenBridgeAdminDispatcher { - contract_address: token_bridge.contract_address - }; + let usdc_address = deploy_erc20("USDC", "USDC"); + token_bridge_admin.enable_withdrawal_limit(usdc_address); +} - let usdc_address = deploy_erc20("usdc", "usdc"); +#[test] +fn enable_withdrawal_limit_ok() { + let (token_bridge, _) = deploy_token_bridge(); + let token_bridge_admin = ITokenBridgeAdminDispatcher { + contract_address: token_bridge.contract_address + }; + let withdrawal_limit = IWithdrawalLimitStatusDispatcher { + contract_address: token_bridge.contract_address + }; - let owner = contract_address_const::<'owner'>(); - // Cheat for the owner - snf::start_cheat_caller_address(token_bridge.contract_address, owner); - token_bridge_admin.block_token(usdc_address); + let owner = OWNER(); + snf::start_cheat_caller_address(token_bridge.contract_address, owner); - let expected_event = TokenBridge::TokenBlocked { token: usdc_address }; - spy - .assert_emitted( - @array![(token_bridge.contract_address, Event::TokenBlocked(expected_event))] - ); + let usdc_address = deploy_erc20("USDC", "USDC"); + token_bridge_admin.enable_withdrawal_limit(usdc_address); - assert(token_bridge.get_status(usdc_address) == TokenStatus::Blocked, 'Should be blocked'); + snf::stop_cheat_caller_address(token_bridge.contract_address); - snf::stop_cheat_caller_address(token_bridge.contract_address); - } + assert(withdrawal_limit.is_withdrawal_limit_applied(usdc_address), 'Limit not applied'); +} +#[test] +fn disable_withdrwal_limit_ok() { + let (token_bridge, _) = deploy_token_bridge(); + let token_bridge_admin = ITokenBridgeAdminDispatcher { + contract_address: token_bridge.contract_address + }; + let withdrawal_limit = IWithdrawalLimitStatusDispatcher { + contract_address: token_bridge.contract_address + }; - #[test] - #[should_panic(expected: ('Caller is not the owner',))] - fn block_token_not_owner() { - let (token_bridge, _) = deploy_token_bridge(); - let token_bridge_admin = ITokenBridgeAdminDispatcher { - contract_address: token_bridge.contract_address - }; + let owner = OWNER(); + snf::start_cheat_caller_address(token_bridge.contract_address, owner); - let usdc_address = deploy_erc20("usdc", "usdc"); + let usdc_address = deploy_erc20("USDC", "USDC"); + token_bridge_admin.enable_withdrawal_limit(usdc_address); - token_bridge_admin.block_token(usdc_address); - } + // Withdrawal limit is now applied + assert(withdrawal_limit.is_withdrawal_limit_applied(usdc_address), 'Limit not applied'); - #[test] - #[should_panic(expected: ('Cannot block',))] - fn block_token_pending() { - let (token_bridge, _) = deploy_token_bridge(); - let token_bridge_admin = ITokenBridgeAdminDispatcher { - contract_address: token_bridge.contract_address - }; - - let owner = contract_address_const::<'owner'>(); - let usdc_address = deploy_erc20("usdc", "usdc"); - token_bridge.enroll_token(usdc_address); - - snf::start_cheat_caller_address(token_bridge.contract_address, owner); - token_bridge_admin.block_token(usdc_address); - } - - #[test] - #[should_panic(expected: ('Caller is not the owner',))] - fn enable_withdrawal_limit_not_owner() { - let (token_bridge, _) = deploy_token_bridge(); - let token_bridge_admin = ITokenBridgeAdminDispatcher { - contract_address: token_bridge.contract_address - }; - - let usdc_address = deploy_erc20("USDC", "USDC"); - token_bridge_admin.enable_withdrawal_limit(usdc_address); - } - - #[test] - fn enable_withdrawal_limit_ok() { - let (token_bridge, _) = deploy_token_bridge(); - let token_bridge_admin = ITokenBridgeAdminDispatcher { - contract_address: token_bridge.contract_address - }; - let withdrawal_limit = IWithdrawalLimitStatusDispatcher { - contract_address: token_bridge.contract_address - }; + token_bridge_admin.disable_withdrawal_limit(usdc_address); - let owner = contract_address_const::<'owner'>(); - snf::start_cheat_caller_address(token_bridge.contract_address, owner); - - let usdc_address = deploy_erc20("USDC", "USDC"); - token_bridge_admin.enable_withdrawal_limit(usdc_address); - - snf::stop_cheat_caller_address(token_bridge.contract_address); - - assert(withdrawal_limit.is_withdrawal_limit_applied(usdc_address), 'Limit not applied'); - } - - #[test] - fn disable_withdrwal_limit_ok() { - let (token_bridge, _) = deploy_token_bridge(); - let token_bridge_admin = ITokenBridgeAdminDispatcher { - contract_address: token_bridge.contract_address - }; - let withdrawal_limit = IWithdrawalLimitStatusDispatcher { - contract_address: token_bridge.contract_address - }; - - let owner = contract_address_const::<'owner'>(); - snf::start_cheat_caller_address(token_bridge.contract_address, owner); - - let usdc_address = deploy_erc20("USDC", "USDC"); - token_bridge_admin.enable_withdrawal_limit(usdc_address); - - // Withdrawal limit is now applied - assert(withdrawal_limit.is_withdrawal_limit_applied(usdc_address), 'Limit not applied'); - - token_bridge_admin.disable_withdrawal_limit(usdc_address); - - assert( - withdrawal_limit.is_withdrawal_limit_applied(usdc_address) == false, 'Limit not applied' - ); - snf::stop_cheat_caller_address(token_bridge.contract_address); - } + assert( + withdrawal_limit.is_withdrawal_limit_applied(usdc_address) == false, 'Limit not applied' + ); + snf::stop_cheat_caller_address(token_bridge.contract_address); +} - #[test] - #[should_panic(expected: ('Caller is not the owner',))] - fn disable_withdrwal_not_owner() { - let (token_bridge, _) = deploy_token_bridge(); - let token_bridge_admin = ITokenBridgeAdminDispatcher { - contract_address: token_bridge.contract_address - }; +#[test] +#[should_panic(expected: ('Caller is not the owner',))] +fn disable_withdrwal_not_owner() { + let (token_bridge, _) = deploy_token_bridge(); + let token_bridge_admin = ITokenBridgeAdminDispatcher { + contract_address: token_bridge.contract_address + }; - let withdrawal_limit = IWithdrawalLimitStatusDispatcher { - contract_address: token_bridge.contract_address - }; + let withdrawal_limit = IWithdrawalLimitStatusDispatcher { + contract_address: token_bridge.contract_address + }; - let owner = contract_address_const::<'owner'>(); - snf::start_cheat_caller_address(token_bridge.contract_address, owner); + let owner = OWNER(); + snf::start_cheat_caller_address(token_bridge.contract_address, owner); - let usdc_address = deploy_erc20("USDC", "USDC"); - token_bridge_admin.enable_withdrawal_limit(usdc_address); + let usdc_address = deploy_erc20("USDC", "USDC"); + token_bridge_admin.enable_withdrawal_limit(usdc_address); - // Withdrawal limit is now applied - assert(withdrawal_limit.is_withdrawal_limit_applied(usdc_address), 'Limit not applied'); + // Withdrawal limit is now applied + assert(withdrawal_limit.is_withdrawal_limit_applied(usdc_address), 'Limit not applied'); - snf::stop_cheat_caller_address(token_bridge.contract_address); + snf::stop_cheat_caller_address(token_bridge.contract_address); - token_bridge_admin.disable_withdrawal_limit(usdc_address); + token_bridge_admin.disable_withdrawal_limit(usdc_address); - assert( - withdrawal_limit.is_withdrawal_limit_applied(usdc_address) == false, 'Limit not applied' - ); - } + assert( + withdrawal_limit.is_withdrawal_limit_applied(usdc_address) == false, 'Limit not applied' + ); } From 091f4d4974fe1831f0250b61d2f215d46cf61406 Mon Sep 17 00:00:00 2001 From: byteZorvin Date: Wed, 31 Jul 2024 14:43:05 +0530 Subject: [PATCH 11/62] add reactivate and unblock --- src/bridge/interface.cairo | 3 +++ src/bridge/token_bridge.cairo | 45 +++++++++++++++++++++++++++++++---- 2 files changed, 43 insertions(+), 5 deletions(-) diff --git a/src/bridge/interface.cairo b/src/bridge/interface.cairo index 90ad94a..4b4e77b 100644 --- a/src/bridge/interface.cairo +++ b/src/bridge/interface.cairo @@ -5,7 +5,10 @@ use starknet_bridge::bridge::types::{TokenStatus, TokenSettings}; pub trait ITokenBridgeAdmin { fn set_appchain_token_bridge(ref self: TContractState, appchain_bridge: ContractAddress); fn block_token(ref self: TContractState, token: ContractAddress); + fn unblock_token(ref self: TContractState, token: ContractAddress); fn deactivate_token(ref self: TContractState, token: ContractAddress); + fn reactivate_token(ref self: TContractState, token: ContractAddress); + fn enable_withdrawal_limit(ref self: TContractState, token: ContractAddress); fn disable_withdrawal_limit(ref self: TContractState, token: ContractAddress); fn set_max_total_balance( diff --git a/src/bridge/token_bridge.cairo b/src/bridge/token_bridge.cairo index 356290d..55432de 100644 --- a/src/bridge/token_bridge.cairo +++ b/src/bridge/token_bridge.cairo @@ -96,6 +96,8 @@ pub mod TokenBridge { TokenEnrollmentInitiated: TokenEnrollmentInitiated, TokenDeactivated: TokenDeactivated, TokenBlocked: TokenBlocked, + TokenReactivated: TokenReactivated, + TokenUnblocked: TokenUnblocked, Deposit: Deposit, DepositWithMessage: DepositWithMessage, DepostiCancelRequest: DepositCancelRequest, @@ -127,6 +129,18 @@ pub mod TokenBridge { pub token: ContractAddress } + + #[derive(Drop, starknet::Event)] + pub struct TokenUnblocked { + pub token: ContractAddress + } + + + #[derive(Drop, starknet::Event)] + pub struct TokenReactivated { + pub token: ContractAddress + } + #[derive(Drop, starknet::Event)] pub struct TokenEnrollmentInitiated { pub token: ContractAddress, @@ -391,14 +405,22 @@ pub mod TokenBridge { self.emit(TokenBlocked { token }); } + fn unblock_token(ref self: ContractState, token: ContractAddress) { + self.ownable.assert_only_owner(); + assert(self.get_status(token) == TokenStatus::Blocked, Errors::CANNOT_BLOCK); + + let new_settings = TokenSettings { + token_status: TokenStatus::Unknown, ..self.token_settings.read(token) + }; + self.token_settings.write(token, new_settings); + self.emit(TokenUnblocked { token }); + } + fn deactivate_token(ref self: ContractState, token: ContractAddress) { self.ownable.assert_only_owner(); let status = self.get_status(token); - assert( - status == TokenStatus::Active || status == TokenStatus::Pending, - Errors::CANNOT_DEACTIVATE - ); + assert(status == TokenStatus::Active, Errors::CANNOT_DEACTIVATE); let new_settings = TokenSettings { token_status: TokenStatus::Deactivated, ..self.token_settings.read(token) @@ -406,9 +428,22 @@ pub mod TokenBridge { self.token_settings.write(token, new_settings); self.emit(TokenDeactivated { token }); - self.emit(TokenBlocked { token }); } + fn reactivate_token(ref self: ContractState, token: ContractAddress) { + self.ownable.assert_only_owner(); + let status = self.get_status(token); + assert(status == TokenStatus::Deactivated, Errors::CANNOT_DEACTIVATE); + + let new_settings = TokenSettings { + token_status: TokenStatus::Active, ..self.token_settings.read(token) + }; + self.token_settings.write(token, new_settings); + + self.emit(TokenReactivated { token }); + } + + fn enable_withdrawal_limit(ref self: ContractState, token: ContractAddress) { self.ownable.assert_only_owner(); let new_settings = TokenSettings { From 2d9e963640e6ba82cec11b28c5bdba556eebc10e Mon Sep 17 00:00:00 2001 From: byteZorvin Date: Wed, 31 Jul 2024 14:43:05 +0530 Subject: [PATCH 12/62] add reactivate and unblock --- src/bridge/interface.cairo | 3 +++ src/bridge/token_bridge.cairo | 45 +++++++++++++++++++++++++++++++---- 2 files changed, 43 insertions(+), 5 deletions(-) diff --git a/src/bridge/interface.cairo b/src/bridge/interface.cairo index 65265b3..6be7ac4 100644 --- a/src/bridge/interface.cairo +++ b/src/bridge/interface.cairo @@ -5,7 +5,10 @@ use starknet_bridge::bridge::types::{TokenStatus, TokenSettings}; pub trait ITokenBridgeAdmin { fn set_appchain_token_bridge(ref self: TContractState, appchain_bridge: ContractAddress); fn block_token(ref self: TContractState, token: ContractAddress); + fn unblock_token(ref self: TContractState, token: ContractAddress); fn deactivate_token(ref self: TContractState, token: ContractAddress); + fn reactivate_token(ref self: TContractState, token: ContractAddress); + fn enable_withdrawal_limit(ref self: TContractState, token: ContractAddress); fn disable_withdrawal_limit(ref self: TContractState, token: ContractAddress); fn set_max_total_balance( diff --git a/src/bridge/token_bridge.cairo b/src/bridge/token_bridge.cairo index 7fa8f02..91ea52a 100644 --- a/src/bridge/token_bridge.cairo +++ b/src/bridge/token_bridge.cairo @@ -96,6 +96,8 @@ pub mod TokenBridge { TokenEnrollmentInitiated: TokenEnrollmentInitiated, TokenDeactivated: TokenDeactivated, TokenBlocked: TokenBlocked, + TokenReactivated: TokenReactivated, + TokenUnblocked: TokenUnblocked, Deposit: Deposit, DepositWithMessage: DepositWithMessage, DepostiCancelRequest: DepositCancelRequest, @@ -127,6 +129,18 @@ pub mod TokenBridge { pub token: ContractAddress } + + #[derive(Drop, starknet::Event)] + pub struct TokenUnblocked { + pub token: ContractAddress + } + + + #[derive(Drop, starknet::Event)] + pub struct TokenReactivated { + pub token: ContractAddress + } + #[derive(Drop, starknet::Event)] pub struct TokenEnrollmentInitiated { pub token: ContractAddress, @@ -391,14 +405,22 @@ pub mod TokenBridge { self.emit(TokenBlocked { token }); } + fn unblock_token(ref self: ContractState, token: ContractAddress) { + self.ownable.assert_only_owner(); + assert(self.get_status(token) == TokenStatus::Blocked, Errors::CANNOT_BLOCK); + + let new_settings = TokenSettings { + token_status: TokenStatus::Unknown, ..self.token_settings.read(token) + }; + self.token_settings.write(token, new_settings); + self.emit(TokenUnblocked { token }); + } + fn deactivate_token(ref self: ContractState, token: ContractAddress) { self.ownable.assert_only_owner(); let status = self.get_status(token); - assert( - status == TokenStatus::Active || status == TokenStatus::Pending, - Errors::CANNOT_DEACTIVATE - ); + assert(status == TokenStatus::Active, Errors::CANNOT_DEACTIVATE); let new_settings = TokenSettings { token_status: TokenStatus::Deactivated, ..self.token_settings.read(token) @@ -406,9 +428,22 @@ pub mod TokenBridge { self.token_settings.write(token, new_settings); self.emit(TokenDeactivated { token }); - self.emit(TokenBlocked { token }); } + fn reactivate_token(ref self: ContractState, token: ContractAddress) { + self.ownable.assert_only_owner(); + let status = self.get_status(token); + assert(status == TokenStatus::Deactivated, Errors::CANNOT_DEACTIVATE); + + let new_settings = TokenSettings { + token_status: TokenStatus::Active, ..self.token_settings.read(token) + }; + self.token_settings.write(token, new_settings); + + self.emit(TokenReactivated { token }); + } + + fn enable_withdrawal_limit(ref self: ContractState, token: ContractAddress) { self.ownable.assert_only_owner(); let new_settings = TokenSettings { From 8523be22e1a193388504513caf4b1634b98157a8 Mon Sep 17 00:00:00 2001 From: byteZorvin Date: Wed, 31 Jul 2024 16:00:49 +0530 Subject: [PATCH 13/62] unblock tests --- tests/token_bridge_test.cairo | 62 +++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/tests/token_bridge_test.cairo b/tests/token_bridge_test.cairo index f108a04..389355c 100644 --- a/tests/token_bridge_test.cairo +++ b/tests/token_bridge_test.cairo @@ -339,3 +339,65 @@ fn disable_withdrwal_not_owner() { ); } +#[test] +fn unblock_token_ok() { + let (token_bridge, mut spy) = deploy_token_bridge(); + let token_bridge_admin = ITokenBridgeAdminDispatcher { + contract_address: token_bridge.contract_address + }; + + let usdc_address = deploy_erc20("usdc", "usdc"); + + let owner = OWNER(); + // Cheat for the owner + snf::start_cheat_caller_address(token_bridge.contract_address, owner); + token_bridge_admin.block_token(usdc_address); + + let expected_token_blocked = TokenBridge::TokenBlocked { token: usdc_address }; + + assert(token_bridge.get_status(usdc_address) == TokenStatus::Blocked, 'Should be blocked'); + + token_bridge_admin.unblock_token(usdc_address); + assert(token_bridge.get_status(usdc_address) == TokenStatus::Unknown, 'Should be unknown'); + + let expected_token_unblocked = TokenBridge::TokenUnblocked { token: usdc_address }; + + snf::stop_cheat_caller_address(token_bridge.contract_address); + + spy + .assert_emitted( + @array![ + (token_bridge.contract_address, Event::TokenBlocked(expected_token_blocked)), + (token_bridge.contract_address, Event::TokenUnblocked(expected_token_unblocked)) + ] + ); +} + +#[test] +#[should_panic(expected: ('Caller is not the owner',))] +fn unblock_token_not_owner() { + let (token_bridge, mut spy) = deploy_token_bridge(); + let token_bridge_admin = ITokenBridgeAdminDispatcher { + contract_address: token_bridge.contract_address + }; + + let usdc_address = deploy_erc20("usdc", "usdc"); + + let owner = OWNER(); + // Cheat for the owner + snf::start_cheat_caller_address(token_bridge.contract_address, owner); + token_bridge_admin.block_token(usdc_address); + + let expected_token_blocked = TokenBridge::TokenBlocked { token: usdc_address }; + + assert(token_bridge.get_status(usdc_address) == TokenStatus::Blocked, 'Should be blocked'); + + spy + .assert_emitted( + @array![(token_bridge.contract_address, Event::TokenBlocked(expected_token_blocked))] + ); + + snf::stop_cheat_caller_address(token_bridge.contract_address); + token_bridge_admin.unblock_token(usdc_address); +} + From ab6e5fde654afba7eb1a976a4c9f4aa3ee5189b3 Mon Sep 17 00:00:00 2001 From: byteZorvin Date: Thu, 1 Aug 2024 11:23:10 +0530 Subject: [PATCH 14/62] reactivate and unblock tests --- src/bridge/token_bridge.cairo | 21 +++++-- src/mocks/messaging.cairo | 8 +-- tests/token_bridge_test.cairo | 109 +++++++++++++++++++++++++++++++--- 3 files changed, 119 insertions(+), 19 deletions(-) diff --git a/src/bridge/token_bridge.cairo b/src/bridge/token_bridge.cairo index 91ea52a..19171d0 100644 --- a/src/bridge/token_bridge.cairo +++ b/src/bridge/token_bridge.cairo @@ -83,8 +83,10 @@ pub mod TokenBridge { pub const ZERO_DEPOSIT: felt252 = 'Zero amount'; pub const ALREADY_ENROLLED: felt252 = 'Already enrolled'; pub const DEPLOYMENT_MESSAGE_DOES_NOT_EXIST: felt252 = 'Deployment message inexistent'; - pub const CANNOT_DEACTIVATE: felt252 = 'Cannot deactivate and block'; - pub const CANNOT_BLOCK: felt252 = 'Cannot block'; + pub const NOT_ACTIVE: felt252 = 'Token not active'; + pub const NOT_DEACTIVATED: felt252 = 'Token not deactivated'; + pub const NOT_BLOCKED: felt252 = 'Token not blocked'; + pub const NOT_UNKNOWN: felt252 = 'Only unknown can be blocked'; pub const INVALID_RECIPIENT: felt252 = 'Invalid recipient'; pub const MAX_BALANCE_EXCEEDED: felt252 = 'Max Balance Exceeded'; } @@ -94,6 +96,7 @@ pub mod TokenBridge { #[event] pub enum Event { TokenEnrollmentInitiated: TokenEnrollmentInitiated, + TokenActivated: TokenActivated, TokenDeactivated: TokenDeactivated, TokenBlocked: TokenBlocked, TokenReactivated: TokenReactivated, @@ -119,6 +122,11 @@ pub mod TokenBridge { ReentrancyGuardEvent: ReentrancyGuardComponent::Event, } + #[derive(Drop, starknet::Event)] + pub struct TokenActivated { + pub token: ContractAddress + } + #[derive(Drop, starknet::Event)] pub struct TokenDeactivated { pub token: ContractAddress @@ -396,7 +404,7 @@ pub mod TokenBridge { // Throws an error if the token is not enrolled or if the sender is not the manager. fn block_token(ref self: ContractState, token: ContractAddress) { self.ownable.assert_only_owner(); - assert(self.get_status(token) == TokenStatus::Unknown, Errors::CANNOT_BLOCK); + assert(self.get_status(token) == TokenStatus::Unknown, Errors::NOT_UNKNOWN); let new_settings = TokenSettings { token_status: TokenStatus::Blocked, ..self.token_settings.read(token) @@ -407,7 +415,7 @@ pub mod TokenBridge { fn unblock_token(ref self: ContractState, token: ContractAddress) { self.ownable.assert_only_owner(); - assert(self.get_status(token) == TokenStatus::Blocked, Errors::CANNOT_BLOCK); + assert(self.get_status(token) == TokenStatus::Blocked, Errors::NOT_BLOCKED); let new_settings = TokenSettings { token_status: TokenStatus::Unknown, ..self.token_settings.read(token) @@ -420,7 +428,7 @@ pub mod TokenBridge { fn deactivate_token(ref self: ContractState, token: ContractAddress) { self.ownable.assert_only_owner(); let status = self.get_status(token); - assert(status == TokenStatus::Active, Errors::CANNOT_DEACTIVATE); + assert(status == TokenStatus::Active, Errors::NOT_ACTIVE); let new_settings = TokenSettings { token_status: TokenStatus::Deactivated, ..self.token_settings.read(token) @@ -433,7 +441,7 @@ pub mod TokenBridge { fn reactivate_token(ref self: ContractState, token: ContractAddress) { self.ownable.assert_only_owner(); let status = self.get_status(token); - assert(status == TokenStatus::Deactivated, Errors::CANNOT_DEACTIVATE); + assert(status == TokenStatus::Deactivated, Errors::NOT_DEACTIVATED); let new_settings = TokenSettings { token_status: TokenStatus::Active, ..self.token_settings.read(token) @@ -601,6 +609,7 @@ pub mod TokenBridge { if (nonce.is_zero()) { let new_settings = TokenSettings { token_status: TokenStatus::Active, ..settings }; self.token_settings.write(token, new_settings); + self.emit(TokenActivated { token }); } else if (get_block_timestamp() > settings.pending_deployment_expiration) { let new_settings = TokenSettings { token_status: TokenStatus::Unknown, ..settings }; self.token_settings.write(token, new_settings); diff --git a/src/mocks/messaging.cairo b/src/mocks/messaging.cairo index 60740aa..f084d44 100644 --- a/src/mocks/messaging.cairo +++ b/src/mocks/messaging.cairo @@ -1,7 +1,7 @@ use piltover::messaging::output_process::MessageToAppchain; #[starknet::interface] -trait IMockMessaging { - fn update_state(ref self: TState, messages: Span); +pub trait IMockMessaging { + fn update_state_for_message(ref self: TState, message_hash: felt252); } #[starknet::contract] @@ -38,8 +38,8 @@ mod messaging_mock { #[abi(embed_v0)] impl MockMessagingImpl of IMockMessaging { - fn update_state(ref self: ContractState, messages: Span) { - self.messaging.process_messages_to_appchain(messages); + fn update_state_for_message(ref self: ContractState, message_hash: felt252) { + self.messaging.sn_to_appc_messages.write(message_hash, 0); } } } diff --git a/tests/token_bridge_test.cairo b/tests/token_bridge_test.cairo index 389355c..36c9ff7 100644 --- a/tests/token_bridge_test.cairo +++ b/tests/token_bridge_test.cairo @@ -1,3 +1,6 @@ +use starknet_bridge::bridge::interface::ITokenBridge; +use starknet_bridge::bridge::interface::ITokenBridgeAdmin; +use starknet_bridge::bridge::token_bridge::TokenBridge::__member_module_token_settings::InternalContractMemberStateTrait; use openzeppelin::access::ownable::interface::IOwnableTwoStepDispatcherTrait; use core::array::ArrayTrait; use core::serde::Serde; @@ -7,7 +10,9 @@ use core::traits::TryInto; use snforge_std as snf; use snforge_std::{ContractClassTrait, EventSpy, EventSpyTrait, EventSpyAssertionsTrait}; use starknet::{ContractAddress, storage::StorageMemberAccessTrait}; -use starknet_bridge::mocks::erc20::ERC20; +use starknet_bridge::mocks::{ + messaging::{IMockMessagingDispatcherTrait, IMockMessagingDispatcher}, erc20::ERC20 +}; use starknet_bridge::bridge::{ ITokenBridgeDispatcher, ITokenBridgeDispatcherTrait, ITokenBridgeAdminDispatcher, ITokenBridgeAdminDispatcherTrait, IWithdrawalLimitStatusDispatcher, @@ -35,8 +40,9 @@ fn deploy_erc20(name: ByteArray, symbol: ByteArray) -> ContractAddress { return usdc; } - -fn deploy_token_bridge() -> (ITokenBridgeDispatcher, EventSpy) { +fn deploy_token_bridge_with_messaging() -> ( + ITokenBridgeDispatcher, EventSpy, IMockMessagingDispatcher +) { // Deploy messaging mock with 5 days cancellation delay let messaging_mock_class_hash = snf::declare("messaging_mock").unwrap(); // Deploying with 5 days as the delay time (5 * 86400 = 432000) @@ -61,16 +67,20 @@ fn deploy_token_bridge() -> (ITokenBridgeDispatcher, EventSpy) { let (token_bridge_address, _) = token_bridge_class_hash.deploy(@calldata).unwrap(); let token_bridge = ITokenBridgeDispatcher { contract_address: token_bridge_address }; - let token_bridge_ownable = IOwnableTwoStepDispatcher { contract_address: token_bridge_address }; + let messaging_mock = IMockMessagingDispatcher { contract_address: messaging_contract_address }; let mut spy = snf::spy_events(); - assert(owner == token_bridge_ownable.owner(), 'Incorrect owner'); + (token_bridge, spy, messaging_mock) +} + +fn deploy_token_bridge() -> (ITokenBridgeDispatcher, EventSpy) { + let (token_bridge, spy, _) = deploy_token_bridge_with_messaging(); (token_bridge, spy) } -/// Returns the state of a component for testing. This must be used +/// 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. fn mock_state_testing() -> TokenBridge::ContractState { @@ -79,7 +89,11 @@ fn mock_state_testing() -> TokenBridge::ContractState { #[test] fn constructor_ok() { - deploy_token_bridge(); + let (token_bridge, _) = deploy_token_bridge(); + let token_bridge_ownable = IOwnableTwoStepDispatcher { + contract_address: token_bridge.contract_address + }; + assert(OWNER() == token_bridge_ownable.owner(), 'Incorrect owner'); } #[test] @@ -234,8 +248,8 @@ fn block_token_not_owner() { } #[test] -#[should_panic(expected: ('Cannot block',))] -fn block_token_pending() { +#[should_panic(expected: ('Only unknown can be blocked',))] +fn block_token_not_unknown() { let (token_bridge, _) = deploy_token_bridge(); let token_bridge_admin = ITokenBridgeAdminDispatcher { contract_address: token_bridge.contract_address @@ -401,3 +415,80 @@ fn unblock_token_not_owner() { token_bridge_admin.unblock_token(usdc_address); } + +#[test] +#[should_panic(expected: ('Token not blocked',))] +fn unblock_token_not_blocked() { + let mut mock = mock_state_testing(); + let usdc_address = deploy_erc20("usdc", "usdc"); + + // Setting the token active + let old_settings = mock.token_settings.read(usdc_address); + mock + .token_settings + .write(usdc_address, TokenSettings { token_status: TokenStatus::Active, ..old_settings }); + + mock.ownable.Ownable_owner.write(OWNER()); + snf::cheat_caller_address_global(OWNER()); + + mock.unblock_token(usdc_address); +} + +#[test] +fn reactivate_token_ok() { + let mut mock = mock_state_testing(); + let usdc_address = deploy_erc20("usdc", "usdc"); + + // Setting the token active + let old_settings = mock.token_settings.read(usdc_address); + mock + .token_settings + .write( + usdc_address, TokenSettings { token_status: TokenStatus::Deactivated, ..old_settings } + ); + + mock.ownable.Ownable_owner.write(OWNER()); + + snf::cheat_caller_address_global(OWNER()); + + mock.reactivate_token(usdc_address); + assert(mock.get_status(usdc_address) == TokenStatus::Active, 'Did not reactivate'); +} + +#[test] +#[should_panic(expected: ('Caller is not the owner',))] +fn reactivate_token_not_owner() { + let mut mock = mock_state_testing(); + let usdc_address = deploy_erc20("usdc", "usdc"); + + // Setting the token active + let old_settings = mock.token_settings.read(usdc_address); + mock + .token_settings + .write( + usdc_address, TokenSettings { token_status: TokenStatus::Deactivated, ..old_settings } + ); + + snf::cheat_caller_address_global(snf::test_address()); + + mock.reactivate_token(usdc_address); +} + +#[test] +#[should_panic(expected: ('Token not deactivated',))] +fn reactivate_token_not_deactivated() { + let mut mock = mock_state_testing(); + let usdc_address = deploy_erc20("usdc", "usdc"); + + // Setting the token active + let old_settings = mock.token_settings.read(usdc_address); + mock + .token_settings + .write(usdc_address, TokenSettings { token_status: TokenStatus::Blocked, ..old_settings }); + + mock.ownable.Ownable_owner.write(OWNER()); + snf::cheat_caller_address_global(OWNER()); + + mock.reactivate_token(usdc_address); +} + From 3b1e08f1dbd05f59dcb83dc1349a5171cfda88af Mon Sep 17 00:00:00 2001 From: byteZorvin Date: Thu, 1 Aug 2024 12:21:07 +0530 Subject: [PATCH 15/62] resolved merge conflicts --- tests/token_bridge_test.cairo | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/token_bridge_test.cairo b/tests/token_bridge_test.cairo index d6a7d95..4cc0e29 100644 --- a/tests/token_bridge_test.cairo +++ b/tests/token_bridge_test.cairo @@ -1,4 +1,4 @@ -use openzeppelin::access::ownable::interface::IOwnableTwoStepDispatcherTrait; +use starknet_bridge::bridge::token_bridge::TokenBridge::__member_module_token_settings::InternalContractMemberStateTrait; use core::array::ArrayTrait; use core::serde::Serde; use core::result::ResultTrait; @@ -11,14 +11,14 @@ use starknet_bridge::mocks::{ messaging::{IMockMessagingDispatcherTrait, IMockMessagingDispatcher}, erc20::ERC20 }; use starknet_bridge::bridge::{ - ITokenBridgeDispatcher, ITokenBridgeDispatcherTrait, ITokenBridgeAdminDispatcher, - ITokenBridgeAdminDispatcherTrait, IWithdrawalLimitStatusDispatcher, + ITokenBridge, ITokenBridgeAdmin, ITokenBridgeDispatcher, ITokenBridgeDispatcherTrait, + ITokenBridgeAdminDispatcher, ITokenBridgeAdminDispatcherTrait, IWithdrawalLimitStatusDispatcher, IWithdrawalLimitStatusDispatcherTrait, TokenBridge, TokenBridge::Event, types::{TokenStatus, TokenSettings} }; use openzeppelin::access::ownable::{ OwnableComponent, OwnableComponent::Event as OwnableEvent, - interface::{IOwnableTwoStepDispatcher, IOwnableDispatcherTrait} + interface::{IOwnableTwoStepDispatcher, IOwnableTwoStepDispatcherTrait} }; use starknet::contract_address::{contract_address_const}; use super::constants::{OWNER, L3_BRIDGE_ADDRESS, DELAY_TIME}; From 91b4c03a8b48852add11cf9ee80562c63e45e446 Mon Sep 17 00:00:00 2001 From: byteZorvin Date: Thu, 1 Aug 2024 13:17:44 +0530 Subject: [PATCH 16/62] restructure testcases --- tests/lib.cairo | 2 + tests/setup.cairo | 78 ++++++++ tests/token_actions_test.cairo | 311 +++++++++++++++++++++++++++++ tests/token_bridge_test.cairo | 346 +-------------------------------- 4 files changed, 392 insertions(+), 345 deletions(-) create mode 100644 tests/setup.cairo create mode 100644 tests/token_actions_test.cairo diff --git a/tests/lib.cairo b/tests/lib.cairo index 178f4a1..910580a 100644 --- a/tests/lib.cairo +++ b/tests/lib.cairo @@ -1,3 +1,5 @@ pub mod token_bridge_test; pub mod constants; +pub mod setup; +pub mod token_actions_test; diff --git a/tests/setup.cairo b/tests/setup.cairo new file mode 100644 index 0000000..9592604 --- /dev/null +++ b/tests/setup.cairo @@ -0,0 +1,78 @@ +use snforge_std as snf; +use snforge_std::{ContractClassTrait, EventSpy, EventSpyTrait, EventSpyAssertionsTrait}; +use starknet::{ContractAddress, storage::StorageMemberAccessTrait}; +use starknet_bridge::mocks::{ + messaging::{IMockMessagingDispatcherTrait, IMockMessagingDispatcher}, erc20::ERC20 +}; +use starknet_bridge::bridge::{ + ITokenBridge, ITokenBridgeAdmin, ITokenBridgeDispatcher, ITokenBridgeDispatcherTrait, + ITokenBridgeAdminDispatcher, ITokenBridgeAdminDispatcherTrait, IWithdrawalLimitStatusDispatcher, + IWithdrawalLimitStatusDispatcherTrait, TokenBridge, TokenBridge::Event, + types::{TokenStatus, TokenSettings} +}; +use openzeppelin::access::ownable::{ + OwnableComponent, OwnableComponent::Event as OwnableEvent, + interface::{IOwnableTwoStepDispatcher, IOwnableTwoStepDispatcherTrait} +}; +use starknet::contract_address::{contract_address_const}; +use super::constants::{OWNER, L3_BRIDGE_ADDRESS, DELAY_TIME}; + +pub 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; +} + +pub fn deploy_token_bridge_with_messaging() -> ( + ITokenBridgeDispatcher, EventSpy, IMockMessagingDispatcher +) { + // Deploy messaging mock with 5 days cancellation delay + let messaging_mock_class_hash = snf::declare("messaging_mock").unwrap(); + // Deploying with 5 days as the delay time (5 * 86400 = 432000) + let (messaging_contract_address, _) = messaging_mock_class_hash + .deploy(@array![DELAY_TIME]) + .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 messaging_mock = IMockMessagingDispatcher { contract_address: messaging_contract_address }; + + let mut spy = snf::spy_events(); + (token_bridge, spy, messaging_mock) +} + + +pub fn deploy_token_bridge() -> (ITokenBridgeDispatcher, EventSpy) { + let (token_bridge, spy, _) = deploy_token_bridge_with_messaging(); + (token_bridge, spy) +} + + +/// 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. +fn mock_state_testing() -> TokenBridge::ContractState { + TokenBridge::contract_state_for_testing() +} diff --git a/tests/token_actions_test.cairo b/tests/token_actions_test.cairo new file mode 100644 index 0000000..2e2e7f2 --- /dev/null +++ b/tests/token_actions_test.cairo @@ -0,0 +1,311 @@ +use starknet_bridge::bridge::token_bridge::TokenBridge::__member_module_token_settings::InternalContractMemberStateTrait; +use core::array::ArrayTrait; +use core::serde::Serde; +use core::result::ResultTrait; +use core::option::OptionTrait; +use core::traits::TryInto; +use snforge_std as snf; +use snforge_std::{ContractClassTrait, EventSpy, EventSpyTrait, EventSpyAssertionsTrait}; +use starknet::{ContractAddress, storage::StorageMemberAccessTrait}; +use starknet_bridge::mocks::{ + messaging::{IMockMessagingDispatcherTrait, IMockMessagingDispatcher}, erc20::ERC20 +}; +use starknet_bridge::bridge::{ + ITokenBridge, ITokenBridgeAdmin, ITokenBridgeDispatcher, ITokenBridgeDispatcherTrait, + ITokenBridgeAdminDispatcher, ITokenBridgeAdminDispatcherTrait, IWithdrawalLimitStatusDispatcher, + IWithdrawalLimitStatusDispatcherTrait, TokenBridge, TokenBridge::Event, + types::{TokenStatus, TokenSettings} +}; +use openzeppelin::access::ownable::{ + OwnableComponent, OwnableComponent::Event as OwnableEvent, + interface::{IOwnableTwoStepDispatcher, IOwnableTwoStepDispatcherTrait} +}; +use starknet::contract_address::{contract_address_const}; +use super::constants::{OWNER, L3_BRIDGE_ADDRESS, DELAY_TIME}; +use super::setup::{deploy_erc20, deploy_token_bridge, mock_state_testing}; + + +#[test] +fn block_token_ok() { + let (token_bridge, mut spy) = deploy_token_bridge(); + let token_bridge_admin = ITokenBridgeAdminDispatcher { + contract_address: token_bridge.contract_address + }; + + let usdc_address = deploy_erc20("usdc", "usdc"); + + let owner = OWNER(); + // Cheat for the owner + snf::start_cheat_caller_address(token_bridge.contract_address, owner); + token_bridge_admin.block_token(usdc_address); + + let expected_event = TokenBridge::TokenBlocked { token: usdc_address }; + spy + .assert_emitted( + @array![(token_bridge.contract_address, Event::TokenBlocked(expected_event))] + ); + + assert(token_bridge.get_status(usdc_address) == TokenStatus::Blocked, 'Should be blocked'); + + snf::stop_cheat_caller_address(token_bridge.contract_address); +} + + +#[test] +#[should_panic(expected: ('Caller is not the owner',))] +fn block_token_not_owner() { + let (token_bridge, _) = deploy_token_bridge(); + let token_bridge_admin = ITokenBridgeAdminDispatcher { + contract_address: token_bridge.contract_address + }; + + let usdc_address = deploy_erc20("usdc", "usdc"); + + token_bridge_admin.block_token(usdc_address); +} + +#[test] +#[should_panic(expected: ('Only unknown can be blocked',))] +fn block_token_not_unknown() { + let (token_bridge, _) = deploy_token_bridge(); + let token_bridge_admin = ITokenBridgeAdminDispatcher { + contract_address: token_bridge.contract_address + }; + + let owner = OWNER(); + let usdc_address = deploy_erc20("usdc", "usdc"); + token_bridge.enroll_token(usdc_address); + + snf::start_cheat_caller_address(token_bridge.contract_address, owner); + token_bridge_admin.block_token(usdc_address); +} + +#[test] +#[should_panic(expected: ('Caller is not the owner',))] +fn enable_withdrawal_limit_not_owner() { + let (token_bridge, _) = deploy_token_bridge(); + let token_bridge_admin = ITokenBridgeAdminDispatcher { + contract_address: token_bridge.contract_address + }; + + let usdc_address = deploy_erc20("USDC", "USDC"); + token_bridge_admin.enable_withdrawal_limit(usdc_address); +} + +#[test] +fn enable_withdrawal_limit_ok() { + let (token_bridge, _) = deploy_token_bridge(); + let token_bridge_admin = ITokenBridgeAdminDispatcher { + contract_address: token_bridge.contract_address + }; + let withdrawal_limit = IWithdrawalLimitStatusDispatcher { + contract_address: token_bridge.contract_address + }; + + let owner = OWNER(); + snf::start_cheat_caller_address(token_bridge.contract_address, owner); + + let usdc_address = deploy_erc20("USDC", "USDC"); + token_bridge_admin.enable_withdrawal_limit(usdc_address); + + snf::stop_cheat_caller_address(token_bridge.contract_address); + + assert(withdrawal_limit.is_withdrawal_limit_applied(usdc_address), 'Limit not applied'); +} + +#[test] +fn disable_withdrwal_limit_ok() { + let (token_bridge, _) = deploy_token_bridge(); + let token_bridge_admin = ITokenBridgeAdminDispatcher { + contract_address: token_bridge.contract_address + }; + let withdrawal_limit = IWithdrawalLimitStatusDispatcher { + contract_address: token_bridge.contract_address + }; + + let owner = OWNER(); + snf::start_cheat_caller_address(token_bridge.contract_address, owner); + + let usdc_address = deploy_erc20("USDC", "USDC"); + token_bridge_admin.enable_withdrawal_limit(usdc_address); + + // Withdrawal limit is now applied + assert(withdrawal_limit.is_withdrawal_limit_applied(usdc_address), 'Limit not applied'); + + token_bridge_admin.disable_withdrawal_limit(usdc_address); + + assert( + withdrawal_limit.is_withdrawal_limit_applied(usdc_address) == false, 'Limit not applied' + ); + snf::stop_cheat_caller_address(token_bridge.contract_address); +} + +#[test] +#[should_panic(expected: ('Caller is not the owner',))] +fn disable_withdrwal_not_owner() { + let (token_bridge, _) = deploy_token_bridge(); + let token_bridge_admin = ITokenBridgeAdminDispatcher { + contract_address: token_bridge.contract_address + }; + + let withdrawal_limit = IWithdrawalLimitStatusDispatcher { + contract_address: token_bridge.contract_address + }; + + let owner = OWNER(); + snf::start_cheat_caller_address(token_bridge.contract_address, owner); + + let usdc_address = deploy_erc20("USDC", "USDC"); + token_bridge_admin.enable_withdrawal_limit(usdc_address); + + // Withdrawal limit is now applied + assert(withdrawal_limit.is_withdrawal_limit_applied(usdc_address), 'Limit not applied'); + + snf::stop_cheat_caller_address(token_bridge.contract_address); + + token_bridge_admin.disable_withdrawal_limit(usdc_address); + + assert( + withdrawal_limit.is_withdrawal_limit_applied(usdc_address) == false, 'Limit not applied' + ); +} + +#[test] +fn unblock_token_ok() { + let (token_bridge, mut spy) = deploy_token_bridge(); + let token_bridge_admin = ITokenBridgeAdminDispatcher { + contract_address: token_bridge.contract_address + }; + + let usdc_address = deploy_erc20("usdc", "usdc"); + + let owner = OWNER(); + // Cheat for the owner + snf::start_cheat_caller_address(token_bridge.contract_address, owner); + token_bridge_admin.block_token(usdc_address); + + let expected_token_blocked = TokenBridge::TokenBlocked { token: usdc_address }; + + assert(token_bridge.get_status(usdc_address) == TokenStatus::Blocked, 'Should be blocked'); + + token_bridge_admin.unblock_token(usdc_address); + assert(token_bridge.get_status(usdc_address) == TokenStatus::Unknown, 'Should be unknown'); + + let expected_token_unblocked = TokenBridge::TokenUnblocked { token: usdc_address }; + + snf::stop_cheat_caller_address(token_bridge.contract_address); + + spy + .assert_emitted( + @array![ + (token_bridge.contract_address, Event::TokenBlocked(expected_token_blocked)), + (token_bridge.contract_address, Event::TokenUnblocked(expected_token_unblocked)) + ] + ); +} + +#[test] +#[should_panic(expected: ('Caller is not the owner',))] +fn unblock_token_not_owner() { + let (token_bridge, mut spy) = deploy_token_bridge(); + let token_bridge_admin = ITokenBridgeAdminDispatcher { + contract_address: token_bridge.contract_address + }; + + let usdc_address = deploy_erc20("usdc", "usdc"); + + let owner = OWNER(); + // Cheat for the owner + snf::start_cheat_caller_address(token_bridge.contract_address, owner); + token_bridge_admin.block_token(usdc_address); + + let expected_token_blocked = TokenBridge::TokenBlocked { token: usdc_address }; + + assert(token_bridge.get_status(usdc_address) == TokenStatus::Blocked, 'Should be blocked'); + + spy + .assert_emitted( + @array![(token_bridge.contract_address, Event::TokenBlocked(expected_token_blocked))] + ); + + snf::stop_cheat_caller_address(token_bridge.contract_address); + token_bridge_admin.unblock_token(usdc_address); +} + + +#[test] +#[should_panic(expected: ('Token not blocked',))] +fn unblock_token_not_blocked() { + let mut mock = mock_state_testing(); + let usdc_address = deploy_erc20("usdc", "usdc"); + + // Setting the token active + let old_settings = mock.token_settings.read(usdc_address); + mock + .token_settings + .write(usdc_address, TokenSettings { token_status: TokenStatus::Active, ..old_settings }); + + mock.ownable.Ownable_owner.write(OWNER()); + snf::cheat_caller_address_global(OWNER()); + + mock.unblock_token(usdc_address); +} + +#[test] +fn reactivate_token_ok() { + let mut mock = mock_state_testing(); + let usdc_address = deploy_erc20("usdc", "usdc"); + + // Setting the token active + let old_settings = mock.token_settings.read(usdc_address); + mock + .token_settings + .write( + usdc_address, TokenSettings { token_status: TokenStatus::Deactivated, ..old_settings } + ); + + mock.ownable.Ownable_owner.write(OWNER()); + + snf::cheat_caller_address_global(OWNER()); + + mock.reactivate_token(usdc_address); + assert(mock.get_status(usdc_address) == TokenStatus::Active, 'Did not reactivate'); +} + +#[test] +#[should_panic(expected: ('Caller is not the owner',))] +fn reactivate_token_not_owner() { + let mut mock = mock_state_testing(); + let usdc_address = deploy_erc20("usdc", "usdc"); + + // Setting the token active + let old_settings = mock.token_settings.read(usdc_address); + mock + .token_settings + .write( + usdc_address, TokenSettings { token_status: TokenStatus::Deactivated, ..old_settings } + ); + + snf::cheat_caller_address_global(snf::test_address()); + + mock.reactivate_token(usdc_address); +} + +#[test] +#[should_panic(expected: ('Token not deactivated',))] +fn reactivate_token_not_deactivated() { + let mut mock = mock_state_testing(); + let usdc_address = deploy_erc20("usdc", "usdc"); + + // Setting the token active + let old_settings = mock.token_settings.read(usdc_address); + mock + .token_settings + .write(usdc_address, TokenSettings { token_status: TokenStatus::Blocked, ..old_settings }); + + mock.ownable.Ownable_owner.write(OWNER()); + snf::cheat_caller_address_global(OWNER()); + + mock.reactivate_token(usdc_address); +} + diff --git a/tests/token_bridge_test.cairo b/tests/token_bridge_test.cairo index 4cc0e29..c543534 100644 --- a/tests/token_bridge_test.cairo +++ b/tests/token_bridge_test.cairo @@ -22,68 +22,9 @@ use openzeppelin::access::ownable::{ }; use starknet::contract_address::{contract_address_const}; use super::constants::{OWNER, L3_BRIDGE_ADDRESS, DELAY_TIME}; +use super::setup::{deploy_erc20, deploy_token_bridge, mock_state_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; -} - -fn deploy_token_bridge_with_messaging() -> ( - ITokenBridgeDispatcher, EventSpy, IMockMessagingDispatcher -) { - // Deploy messaging mock with 5 days cancellation delay - let messaging_mock_class_hash = snf::declare("messaging_mock").unwrap(); - // Deploying with 5 days as the delay time (5 * 86400 = 432000) - let (messaging_contract_address, _) = messaging_mock_class_hash - .deploy(@array![DELAY_TIME]) - .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 messaging_mock = IMockMessagingDispatcher { contract_address: messaging_contract_address }; - - let mut spy = snf::spy_events(); - (token_bridge, spy, messaging_mock) -} - - -fn deploy_token_bridge() -> (ITokenBridgeDispatcher, EventSpy) { - let (token_bridge, spy, _) = deploy_token_bridge_with_messaging(); - (token_bridge, spy) -} - - -/// 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. -fn mock_state_testing() -> TokenBridge::ContractState { - TokenBridge::contract_state_for_testing() -} - #[test] fn constructor_ok() { let (token_bridge, _) = deploy_token_bridge(); @@ -204,288 +145,3 @@ fn set_max_total_balance_ok() { ); } - -#[test] -fn block_token_ok() { - let (token_bridge, mut spy) = deploy_token_bridge(); - let token_bridge_admin = ITokenBridgeAdminDispatcher { - contract_address: token_bridge.contract_address - }; - - let usdc_address = deploy_erc20("usdc", "usdc"); - - let owner = OWNER(); - // Cheat for the owner - snf::start_cheat_caller_address(token_bridge.contract_address, owner); - token_bridge_admin.block_token(usdc_address); - - let expected_event = TokenBridge::TokenBlocked { token: usdc_address }; - spy - .assert_emitted( - @array![(token_bridge.contract_address, Event::TokenBlocked(expected_event))] - ); - - assert(token_bridge.get_status(usdc_address) == TokenStatus::Blocked, 'Should be blocked'); - - snf::stop_cheat_caller_address(token_bridge.contract_address); -} - - -#[test] -#[should_panic(expected: ('Caller is not the owner',))] -fn block_token_not_owner() { - let (token_bridge, _) = deploy_token_bridge(); - let token_bridge_admin = ITokenBridgeAdminDispatcher { - contract_address: token_bridge.contract_address - }; - - let usdc_address = deploy_erc20("usdc", "usdc"); - - token_bridge_admin.block_token(usdc_address); -} - -#[test] -#[should_panic(expected: ('Only unknown can be blocked',))] -fn block_token_not_unknown() { - let (token_bridge, _) = deploy_token_bridge(); - let token_bridge_admin = ITokenBridgeAdminDispatcher { - contract_address: token_bridge.contract_address - }; - - let owner = OWNER(); - let usdc_address = deploy_erc20("usdc", "usdc"); - token_bridge.enroll_token(usdc_address); - - snf::start_cheat_caller_address(token_bridge.contract_address, owner); - token_bridge_admin.block_token(usdc_address); -} - -#[test] -#[should_panic(expected: ('Caller is not the owner',))] -fn enable_withdrawal_limit_not_owner() { - let (token_bridge, _) = deploy_token_bridge(); - let token_bridge_admin = ITokenBridgeAdminDispatcher { - contract_address: token_bridge.contract_address - }; - - let usdc_address = deploy_erc20("USDC", "USDC"); - token_bridge_admin.enable_withdrawal_limit(usdc_address); -} - -#[test] -fn enable_withdrawal_limit_ok() { - let (token_bridge, _) = deploy_token_bridge(); - let token_bridge_admin = ITokenBridgeAdminDispatcher { - contract_address: token_bridge.contract_address - }; - let withdrawal_limit = IWithdrawalLimitStatusDispatcher { - contract_address: token_bridge.contract_address - }; - - let owner = OWNER(); - snf::start_cheat_caller_address(token_bridge.contract_address, owner); - - let usdc_address = deploy_erc20("USDC", "USDC"); - token_bridge_admin.enable_withdrawal_limit(usdc_address); - - snf::stop_cheat_caller_address(token_bridge.contract_address); - - assert(withdrawal_limit.is_withdrawal_limit_applied(usdc_address), 'Limit not applied'); -} - -#[test] -fn disable_withdrwal_limit_ok() { - let (token_bridge, _) = deploy_token_bridge(); - let token_bridge_admin = ITokenBridgeAdminDispatcher { - contract_address: token_bridge.contract_address - }; - let withdrawal_limit = IWithdrawalLimitStatusDispatcher { - contract_address: token_bridge.contract_address - }; - - let owner = OWNER(); - snf::start_cheat_caller_address(token_bridge.contract_address, owner); - - let usdc_address = deploy_erc20("USDC", "USDC"); - token_bridge_admin.enable_withdrawal_limit(usdc_address); - - // Withdrawal limit is now applied - assert(withdrawal_limit.is_withdrawal_limit_applied(usdc_address), 'Limit not applied'); - - token_bridge_admin.disable_withdrawal_limit(usdc_address); - - assert( - withdrawal_limit.is_withdrawal_limit_applied(usdc_address) == false, 'Limit not applied' - ); - snf::stop_cheat_caller_address(token_bridge.contract_address); -} - -#[test] -#[should_panic(expected: ('Caller is not the owner',))] -fn disable_withdrwal_not_owner() { - let (token_bridge, _) = deploy_token_bridge(); - let token_bridge_admin = ITokenBridgeAdminDispatcher { - contract_address: token_bridge.contract_address - }; - - let withdrawal_limit = IWithdrawalLimitStatusDispatcher { - contract_address: token_bridge.contract_address - }; - - let owner = OWNER(); - snf::start_cheat_caller_address(token_bridge.contract_address, owner); - - let usdc_address = deploy_erc20("USDC", "USDC"); - token_bridge_admin.enable_withdrawal_limit(usdc_address); - - // Withdrawal limit is now applied - assert(withdrawal_limit.is_withdrawal_limit_applied(usdc_address), 'Limit not applied'); - - snf::stop_cheat_caller_address(token_bridge.contract_address); - - token_bridge_admin.disable_withdrawal_limit(usdc_address); - - assert( - withdrawal_limit.is_withdrawal_limit_applied(usdc_address) == false, 'Limit not applied' - ); -} - -#[test] -fn unblock_token_ok() { - let (token_bridge, mut spy) = deploy_token_bridge(); - let token_bridge_admin = ITokenBridgeAdminDispatcher { - contract_address: token_bridge.contract_address - }; - - let usdc_address = deploy_erc20("usdc", "usdc"); - - let owner = OWNER(); - // Cheat for the owner - snf::start_cheat_caller_address(token_bridge.contract_address, owner); - token_bridge_admin.block_token(usdc_address); - - let expected_token_blocked = TokenBridge::TokenBlocked { token: usdc_address }; - - assert(token_bridge.get_status(usdc_address) == TokenStatus::Blocked, 'Should be blocked'); - - token_bridge_admin.unblock_token(usdc_address); - assert(token_bridge.get_status(usdc_address) == TokenStatus::Unknown, 'Should be unknown'); - - let expected_token_unblocked = TokenBridge::TokenUnblocked { token: usdc_address }; - - snf::stop_cheat_caller_address(token_bridge.contract_address); - - spy - .assert_emitted( - @array![ - (token_bridge.contract_address, Event::TokenBlocked(expected_token_blocked)), - (token_bridge.contract_address, Event::TokenUnblocked(expected_token_unblocked)) - ] - ); -} - -#[test] -#[should_panic(expected: ('Caller is not the owner',))] -fn unblock_token_not_owner() { - let (token_bridge, mut spy) = deploy_token_bridge(); - let token_bridge_admin = ITokenBridgeAdminDispatcher { - contract_address: token_bridge.contract_address - }; - - let usdc_address = deploy_erc20("usdc", "usdc"); - - let owner = OWNER(); - // Cheat for the owner - snf::start_cheat_caller_address(token_bridge.contract_address, owner); - token_bridge_admin.block_token(usdc_address); - - let expected_token_blocked = TokenBridge::TokenBlocked { token: usdc_address }; - - assert(token_bridge.get_status(usdc_address) == TokenStatus::Blocked, 'Should be blocked'); - - spy - .assert_emitted( - @array![(token_bridge.contract_address, Event::TokenBlocked(expected_token_blocked))] - ); - - snf::stop_cheat_caller_address(token_bridge.contract_address); - token_bridge_admin.unblock_token(usdc_address); -} - - -#[test] -#[should_panic(expected: ('Token not blocked',))] -fn unblock_token_not_blocked() { - let mut mock = mock_state_testing(); - let usdc_address = deploy_erc20("usdc", "usdc"); - - // Setting the token active - let old_settings = mock.token_settings.read(usdc_address); - mock - .token_settings - .write(usdc_address, TokenSettings { token_status: TokenStatus::Active, ..old_settings }); - - mock.ownable.Ownable_owner.write(OWNER()); - snf::cheat_caller_address_global(OWNER()); - - mock.unblock_token(usdc_address); -} - -#[test] -fn reactivate_token_ok() { - let mut mock = mock_state_testing(); - let usdc_address = deploy_erc20("usdc", "usdc"); - - // Setting the token active - let old_settings = mock.token_settings.read(usdc_address); - mock - .token_settings - .write( - usdc_address, TokenSettings { token_status: TokenStatus::Deactivated, ..old_settings } - ); - - mock.ownable.Ownable_owner.write(OWNER()); - - snf::cheat_caller_address_global(OWNER()); - - mock.reactivate_token(usdc_address); - assert(mock.get_status(usdc_address) == TokenStatus::Active, 'Did not reactivate'); -} - -#[test] -#[should_panic(expected: ('Caller is not the owner',))] -fn reactivate_token_not_owner() { - let mut mock = mock_state_testing(); - let usdc_address = deploy_erc20("usdc", "usdc"); - - // Setting the token active - let old_settings = mock.token_settings.read(usdc_address); - mock - .token_settings - .write( - usdc_address, TokenSettings { token_status: TokenStatus::Deactivated, ..old_settings } - ); - - snf::cheat_caller_address_global(snf::test_address()); - - mock.reactivate_token(usdc_address); -} - -#[test] -#[should_panic(expected: ('Token not deactivated',))] -fn reactivate_token_not_deactivated() { - let mut mock = mock_state_testing(); - let usdc_address = deploy_erc20("usdc", "usdc"); - - // Setting the token active - let old_settings = mock.token_settings.read(usdc_address); - mock - .token_settings - .write(usdc_address, TokenSettings { token_status: TokenStatus::Blocked, ..old_settings }); - - mock.ownable.Ownable_owner.write(OWNER()); - snf::cheat_caller_address_global(OWNER()); - - mock.reactivate_token(usdc_address); -} - From 6752ad399851532dc8210203394001a4f6ec44d4 Mon Sep 17 00:00:00 2001 From: byteZorvin Date: Thu, 1 Aug 2024 14:07:25 +0530 Subject: [PATCH 17/62] fix: visibility modifier --- tests/setup.cairo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/setup.cairo b/tests/setup.cairo index 9592604..fefa873 100644 --- a/tests/setup.cairo +++ b/tests/setup.cairo @@ -73,6 +73,6 @@ pub fn deploy_token_bridge() -> (ITokenBridgeDispatcher, EventSpy) { /// 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. -fn mock_state_testing() -> TokenBridge::ContractState { +pub fn mock_state_testing() -> TokenBridge::ContractState { TokenBridge::contract_state_for_testing() } From 5708aa1d74a5e8c5dcba207adbb0721152678978 Mon Sep 17 00:00:00 2001 From: byteZorvin Date: Thu, 1 Aug 2024 15:02:44 +0530 Subject: [PATCH 18/62] deposit tests --- tests/deposit_flow_test.cairo | 44 +++++++++++++++++++++++++++++++++++ tests/lib.cairo | 1 + 2 files changed, 45 insertions(+) create mode 100644 tests/deposit_flow_test.cairo diff --git a/tests/deposit_flow_test.cairo b/tests/deposit_flow_test.cairo new file mode 100644 index 0000000..b180ff9 --- /dev/null +++ b/tests/deposit_flow_test.cairo @@ -0,0 +1,44 @@ +use starknet_bridge::bridge::token_bridge::TokenBridge::__member_module_token_settings::InternalContractMemberStateTrait; +use core::array::ArrayTrait; +use core::serde::Serde; +use core::result::ResultTrait; +use core::option::OptionTrait; +use core::traits::TryInto; +use snforge_std as snf; +use snforge_std::{ContractClassTrait, EventSpy, EventSpyTrait, EventSpyAssertionsTrait}; +use starknet::{ContractAddress, storage::StorageMemberAccessTrait}; +use starknet_bridge::mocks::{ + messaging::{IMockMessagingDispatcherTrait, IMockMessagingDispatcher}, erc20::ERC20 +}; +use starknet_bridge::bridge::{ + ITokenBridge, ITokenBridgeAdmin, ITokenBridgeDispatcher, ITokenBridgeDispatcherTrait, + ITokenBridgeAdminDispatcher, ITokenBridgeAdminDispatcherTrait, IWithdrawalLimitStatusDispatcher, + IWithdrawalLimitStatusDispatcherTrait, TokenBridge, TokenBridge::Event, + types::{TokenStatus, TokenSettings} +}; +use openzeppelin::access::ownable::{ + OwnableComponent, OwnableComponent::Event as OwnableEvent, + interface::{IOwnableTwoStepDispatcher, IOwnableTwoStepDispatcherTrait} +}; +use starknet::contract_address::{contract_address_const}; +use super::constants::{OWNER, L3_BRIDGE_ADDRESS, DELAY_TIME}; +use super::setup::{ + deploy_erc20, deploy_token_bridge_with_messaging, deploy_token_bridge, mock_state_testing +}; + +#[test] +fn deposit_ok() { + let (token_bridge, mut spy, messaging_mock) = deploy_token_bridge_with_messaging(); + let usdc_address = deploy_erc20("usdc", "usdc"); + + token_bridge.enroll_token(usdc_address); + + // Enroll token will emit the event `TokenEnrollmentInitiated` + // Getting the deployment_message_hash from the emitted event + let (_, event) = spy.get_events().events.at(0); + let deployment_message_hash = event.data.at(0); + + messaging_mock.update_state_for_message(*deployment_message_hash); + + assert(token_bridge.get_status(usdc_address) == TokenStatus::Blocked, 'Should be blocked'); +} diff --git a/tests/lib.cairo b/tests/lib.cairo index 910580a..1f1bf18 100644 --- a/tests/lib.cairo +++ b/tests/lib.cairo @@ -2,4 +2,5 @@ pub mod token_bridge_test; pub mod constants; pub mod setup; pub mod token_actions_test; +pub mod deposit_flow_test; From 0c613d0b4e98e71887992b266309c5271b59f87c Mon Sep 17 00:00:00 2001 From: byteZorvin Date: Thu, 1 Aug 2024 15:41:29 +0530 Subject: [PATCH 19/62] make them unit --- tests/token_bridge_test.cairo | 118 ++++++++++++---------------------- 1 file changed, 40 insertions(+), 78 deletions(-) diff --git a/tests/token_bridge_test.cairo b/tests/token_bridge_test.cairo index 4cc0e29..3380c8f 100644 --- a/tests/token_bridge_test.cairo +++ b/tests/token_bridge_test.cairo @@ -207,57 +207,45 @@ fn set_max_total_balance_ok() { #[test] fn block_token_ok() { - let (token_bridge, mut spy) = deploy_token_bridge(); - let token_bridge_admin = ITokenBridgeAdminDispatcher { - contract_address: token_bridge.contract_address - }; - + let mut mock = mock_state_testing(); let usdc_address = deploy_erc20("usdc", "usdc"); - let owner = OWNER(); - // Cheat for the owner - snf::start_cheat_caller_address(token_bridge.contract_address, owner); - token_bridge_admin.block_token(usdc_address); - - let expected_event = TokenBridge::TokenBlocked { token: usdc_address }; - spy - .assert_emitted( - @array![(token_bridge.contract_address, Event::TokenBlocked(expected_event))] - ); - - assert(token_bridge.get_status(usdc_address) == TokenStatus::Blocked, 'Should be blocked'); + mock.ownable.Ownable_owner.write(OWNER()); + snf::cheat_caller_address_global(OWNER()); - snf::stop_cheat_caller_address(token_bridge.contract_address); + mock.block_token(usdc_address); + assert(mock.get_status(usdc_address) == TokenStatus::Blocked, 'Token not blocked'); } #[test] #[should_panic(expected: ('Caller is not the owner',))] fn block_token_not_owner() { - let (token_bridge, _) = deploy_token_bridge(); - let token_bridge_admin = ITokenBridgeAdminDispatcher { - contract_address: token_bridge.contract_address - }; - + let mut mock = mock_state_testing(); let usdc_address = deploy_erc20("usdc", "usdc"); - token_bridge_admin.block_token(usdc_address); + mock.ownable.Ownable_owner.write(OWNER()); + snf::cheat_caller_address_global(snf::test_address()); + + mock.block_token(usdc_address); } #[test] #[should_panic(expected: ('Only unknown can be blocked',))] fn block_token_not_unknown() { - let (token_bridge, _) = deploy_token_bridge(); - let token_bridge_admin = ITokenBridgeAdminDispatcher { - contract_address: token_bridge.contract_address - }; - - let owner = OWNER(); + let mut mock = mock_state_testing(); let usdc_address = deploy_erc20("usdc", "usdc"); - token_bridge.enroll_token(usdc_address); - snf::start_cheat_caller_address(token_bridge.contract_address, owner); - token_bridge_admin.block_token(usdc_address); + // Setting the token active + let old_settings = mock.token_settings.read(usdc_address); + mock + .token_settings + .write(usdc_address, TokenSettings { token_status: TokenStatus::Active, ..old_settings }); + + mock.ownable.Ownable_owner.write(OWNER()); + snf::cheat_caller_address_global(OWNER()); + + mock.block_token(usdc_address); } #[test] @@ -352,64 +340,38 @@ fn disable_withdrwal_not_owner() { #[test] fn unblock_token_ok() { - let (token_bridge, mut spy) = deploy_token_bridge(); - let token_bridge_admin = ITokenBridgeAdminDispatcher { - contract_address: token_bridge.contract_address - }; - + let mut mock = mock_state_testing(); let usdc_address = deploy_erc20("usdc", "usdc"); - let owner = OWNER(); - // Cheat for the owner - snf::start_cheat_caller_address(token_bridge.contract_address, owner); - token_bridge_admin.block_token(usdc_address); - - let expected_token_blocked = TokenBridge::TokenBlocked { token: usdc_address }; - - assert(token_bridge.get_status(usdc_address) == TokenStatus::Blocked, 'Should be blocked'); - - token_bridge_admin.unblock_token(usdc_address); - assert(token_bridge.get_status(usdc_address) == TokenStatus::Unknown, 'Should be unknown'); - - let expected_token_unblocked = TokenBridge::TokenUnblocked { token: usdc_address }; + // Setting the token active + let old_settings = mock.token_settings.read(usdc_address); + mock + .token_settings + .write(usdc_address, TokenSettings { token_status: TokenStatus::Blocked, ..old_settings }); - snf::stop_cheat_caller_address(token_bridge.contract_address); + mock.ownable.Ownable_owner.write(OWNER()); + snf::cheat_caller_address_global(OWNER()); - spy - .assert_emitted( - @array![ - (token_bridge.contract_address, Event::TokenBlocked(expected_token_blocked)), - (token_bridge.contract_address, Event::TokenUnblocked(expected_token_unblocked)) - ] - ); + mock.unblock_token(usdc_address); + assert(mock.get_status(usdc_address) == TokenStatus::Unknown, 'Not unblocked'); } #[test] #[should_panic(expected: ('Caller is not the owner',))] fn unblock_token_not_owner() { - let (token_bridge, mut spy) = deploy_token_bridge(); - let token_bridge_admin = ITokenBridgeAdminDispatcher { - contract_address: token_bridge.contract_address - }; - + let mut mock = mock_state_testing(); let usdc_address = deploy_erc20("usdc", "usdc"); - let owner = OWNER(); - // Cheat for the owner - snf::start_cheat_caller_address(token_bridge.contract_address, owner); - token_bridge_admin.block_token(usdc_address); - - let expected_token_blocked = TokenBridge::TokenBlocked { token: usdc_address }; - - assert(token_bridge.get_status(usdc_address) == TokenStatus::Blocked, 'Should be blocked'); + // Setting the token active + let old_settings = mock.token_settings.read(usdc_address); + mock + .token_settings + .write(usdc_address, TokenSettings { token_status: TokenStatus::Blocked, ..old_settings }); - spy - .assert_emitted( - @array![(token_bridge.contract_address, Event::TokenBlocked(expected_token_blocked))] - ); + mock.ownable.Ownable_owner.write(OWNER()); + snf::cheat_caller_address_global(snf::test_address()); - snf::stop_cheat_caller_address(token_bridge.contract_address); - token_bridge_admin.unblock_token(usdc_address); + mock.unblock_token(usdc_address); } From 0bfb32bcc4949489edc5dba92f6e6b3a9d16f1c4 Mon Sep 17 00:00:00 2001 From: byteZorvin Date: Thu, 1 Aug 2024 15:44:01 +0530 Subject: [PATCH 20/62] make them unit --- tests/token_actions_test.cairo | 118 +++++++++++---------------------- 1 file changed, 40 insertions(+), 78 deletions(-) diff --git a/tests/token_actions_test.cairo b/tests/token_actions_test.cairo index 2e2e7f2..bdd838e 100644 --- a/tests/token_actions_test.cairo +++ b/tests/token_actions_test.cairo @@ -27,57 +27,45 @@ use super::setup::{deploy_erc20, deploy_token_bridge, mock_state_testing}; #[test] fn block_token_ok() { - let (token_bridge, mut spy) = deploy_token_bridge(); - let token_bridge_admin = ITokenBridgeAdminDispatcher { - contract_address: token_bridge.contract_address - }; - + let mut mock = mock_state_testing(); let usdc_address = deploy_erc20("usdc", "usdc"); - let owner = OWNER(); - // Cheat for the owner - snf::start_cheat_caller_address(token_bridge.contract_address, owner); - token_bridge_admin.block_token(usdc_address); - - let expected_event = TokenBridge::TokenBlocked { token: usdc_address }; - spy - .assert_emitted( - @array![(token_bridge.contract_address, Event::TokenBlocked(expected_event))] - ); - - assert(token_bridge.get_status(usdc_address) == TokenStatus::Blocked, 'Should be blocked'); + mock.ownable.Ownable_owner.write(OWNER()); + snf::cheat_caller_address_global(OWNER()); - snf::stop_cheat_caller_address(token_bridge.contract_address); + mock.block_token(usdc_address); + assert(mock.get_status(usdc_address) == TokenStatus::Blocked, 'Token not blocked'); } #[test] #[should_panic(expected: ('Caller is not the owner',))] fn block_token_not_owner() { - let (token_bridge, _) = deploy_token_bridge(); - let token_bridge_admin = ITokenBridgeAdminDispatcher { - contract_address: token_bridge.contract_address - }; - + let mut mock = mock_state_testing(); let usdc_address = deploy_erc20("usdc", "usdc"); - token_bridge_admin.block_token(usdc_address); + mock.ownable.Ownable_owner.write(OWNER()); + snf::cheat_caller_address_global(snf::test_address()); + + mock.block_token(usdc_address); } #[test] #[should_panic(expected: ('Only unknown can be blocked',))] fn block_token_not_unknown() { - let (token_bridge, _) = deploy_token_bridge(); - let token_bridge_admin = ITokenBridgeAdminDispatcher { - contract_address: token_bridge.contract_address - }; - - let owner = OWNER(); + let mut mock = mock_state_testing(); let usdc_address = deploy_erc20("usdc", "usdc"); - token_bridge.enroll_token(usdc_address); - snf::start_cheat_caller_address(token_bridge.contract_address, owner); - token_bridge_admin.block_token(usdc_address); + // Setting the token active + let old_settings = mock.token_settings.read(usdc_address); + mock + .token_settings + .write(usdc_address, TokenSettings { token_status: TokenStatus::Active, ..old_settings }); + + mock.ownable.Ownable_owner.write(OWNER()); + snf::cheat_caller_address_global(OWNER()); + + mock.block_token(usdc_address); } #[test] @@ -172,64 +160,38 @@ fn disable_withdrwal_not_owner() { #[test] fn unblock_token_ok() { - let (token_bridge, mut spy) = deploy_token_bridge(); - let token_bridge_admin = ITokenBridgeAdminDispatcher { - contract_address: token_bridge.contract_address - }; - + let mut mock = mock_state_testing(); let usdc_address = deploy_erc20("usdc", "usdc"); - let owner = OWNER(); - // Cheat for the owner - snf::start_cheat_caller_address(token_bridge.contract_address, owner); - token_bridge_admin.block_token(usdc_address); - - let expected_token_blocked = TokenBridge::TokenBlocked { token: usdc_address }; - - assert(token_bridge.get_status(usdc_address) == TokenStatus::Blocked, 'Should be blocked'); - - token_bridge_admin.unblock_token(usdc_address); - assert(token_bridge.get_status(usdc_address) == TokenStatus::Unknown, 'Should be unknown'); - - let expected_token_unblocked = TokenBridge::TokenUnblocked { token: usdc_address }; + // Setting the token active + let old_settings = mock.token_settings.read(usdc_address); + mock + .token_settings + .write(usdc_address, TokenSettings { token_status: TokenStatus::Blocked, ..old_settings }); - snf::stop_cheat_caller_address(token_bridge.contract_address); + mock.ownable.Ownable_owner.write(OWNER()); + snf::cheat_caller_address_global(OWNER()); - spy - .assert_emitted( - @array![ - (token_bridge.contract_address, Event::TokenBlocked(expected_token_blocked)), - (token_bridge.contract_address, Event::TokenUnblocked(expected_token_unblocked)) - ] - ); + mock.unblock_token(usdc_address); + assert(mock.get_status(usdc_address) == TokenStatus::Unknown, 'Not unblocked'); } #[test] #[should_panic(expected: ('Caller is not the owner',))] fn unblock_token_not_owner() { - let (token_bridge, mut spy) = deploy_token_bridge(); - let token_bridge_admin = ITokenBridgeAdminDispatcher { - contract_address: token_bridge.contract_address - }; - + let mut mock = mock_state_testing(); let usdc_address = deploy_erc20("usdc", "usdc"); - let owner = OWNER(); - // Cheat for the owner - snf::start_cheat_caller_address(token_bridge.contract_address, owner); - token_bridge_admin.block_token(usdc_address); - - let expected_token_blocked = TokenBridge::TokenBlocked { token: usdc_address }; - - assert(token_bridge.get_status(usdc_address) == TokenStatus::Blocked, 'Should be blocked'); + // Setting the token active + let old_settings = mock.token_settings.read(usdc_address); + mock + .token_settings + .write(usdc_address, TokenSettings { token_status: TokenStatus::Blocked, ..old_settings }); - spy - .assert_emitted( - @array![(token_bridge.contract_address, Event::TokenBlocked(expected_token_blocked))] - ); + mock.ownable.Ownable_owner.write(OWNER()); + snf::cheat_caller_address_global(snf::test_address()); - snf::stop_cheat_caller_address(token_bridge.contract_address); - token_bridge_admin.unblock_token(usdc_address); + mock.unblock_token(usdc_address); } From 18690bb943d8060e4beadd8f5d949933ae569460 Mon Sep 17 00:00:00 2001 From: byteZorvin Date: Sat, 3 Aug 2024 16:04:20 +0530 Subject: [PATCH 21/62] deposit flow tests --- .tool-versions | 4 +- Scarb.lock | 4 +- Scarb.toml | 4 +- src/bridge/types.cairo | 2 +- src/mocks/erc20.cairo | 3 +- tests/deposit_flow_test.cairo | 193 +++++++++++++++++++++++++++++- tests/enroll_token_test.cairo | 55 +++++++++ tests/lib.cairo | 7 +- tests/token_actions_test.cairo | 4 +- tests/token_bridge_test.cairo | 18 +-- tests/{ => utils}/constants.cairo | 0 tests/{ => utils}/setup.cairo | 4 +- 12 files changed, 264 insertions(+), 34 deletions(-) create mode 100644 tests/enroll_token_test.cairo rename tests/{ => utils}/constants.cairo (100%) rename tests/{ => utils}/setup.cairo (96%) diff --git a/.tool-versions b/.tool-versions index bdd2d06..67f5ccf 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1,2 +1,2 @@ -scarb 2.6.5 -starknet-foundry 0.26.0 +scarb 2.7.0 +starknet-foundry 0.27.0 diff --git a/Scarb.lock b/Scarb.lock index 597c2e3..aee7da4 100644 --- a/Scarb.lock +++ b/Scarb.lock @@ -16,8 +16,8 @@ dependencies = [ [[package]] name = "snforge_std" -version = "0.26.0" -source = "git+https://github.com/foundry-rs/starknet-foundry?tag=v0.26.0#50eb589db65e113efe4f09241feb59b574228c7e" +version = "0.27.0" +source = "git+https://github.com/foundry-rs/starknet-foundry?tag=v0.27.0#2d99b7c00678ef0363881ee0273550c44a9263de" [[package]] name = "starknet_bridge" diff --git a/Scarb.toml b/Scarb.toml index a61e77c..ef9a4d6 100644 --- a/Scarb.toml +++ b/Scarb.toml @@ -11,10 +11,12 @@ starknet = "2.6.4" piltover = { git = "https://github.com/byteZorvin/piltover", branch="bridge-testing"} [dev-dependencies] -snforge_std = { git = "https://github.com/foundry-rs/starknet-foundry", tag = "v0.26.0" } +snforge_std = { git = "https://github.com/foundry-rs/starknet-foundry", tag = "v0.27.0" } [[target.starknet-contract]] casm = true +allowed-libfuncs-list.name = "experimental" + [scripts] test = "snforge test" diff --git a/src/bridge/types.cairo b/src/bridge/types.cairo index 394608a..8c9ae2d 100644 --- a/src/bridge/types.cairo +++ b/src/bridge/types.cairo @@ -1,6 +1,6 @@ use piltover::messaging::messaging_cpt::{MessageHash, Nonce}; -#[derive(Serde, Drop, starknet::Store, PartialEq)] +#[derive(Serde, Drop, starknet::Store, PartialEq, Display, Debug)] pub enum TokenStatus { #[default] Unknown, diff --git a/src/mocks/erc20.cairo b/src/mocks/erc20.cairo index cdd7656..e28d241 100644 --- a/src/mocks/erc20.cairo +++ b/src/mocks/erc20.cairo @@ -57,8 +57,9 @@ pub mod ERC20 { } #[generate_trait] + #[abi(per_item)] impl IERC20Impl of IERC20Trait { - #[abi(per_item)] + #[external(v0)] fn mint(ref self: ContractState, recipient: ContractAddress, amount: u256) { assert(amount < 100 * DECIMALS, 'Max 100 tokens only.'); self.erc20.mint(recipient, amount); diff --git a/tests/deposit_flow_test.cairo b/tests/deposit_flow_test.cairo index b180ff9..3b006a0 100644 --- a/tests/deposit_flow_test.cairo +++ b/tests/deposit_flow_test.cairo @@ -1,3 +1,4 @@ +use core::num::traits::zero::Zero; use starknet_bridge::bridge::token_bridge::TokenBridge::__member_module_token_settings::InternalContractMemberStateTrait; use core::array::ArrayTrait; use core::serde::Serde; @@ -5,11 +6,14 @@ use core::result::ResultTrait; use core::option::OptionTrait; use core::traits::TryInto; use snforge_std as snf; -use snforge_std::{ContractClassTrait, EventSpy, EventSpyTrait, EventSpyAssertionsTrait}; +use snforge_std::{ + ContractClassTrait, EventSpy, EventSpyTrait, EventsFilterTrait, EventSpyAssertionsTrait +}; use starknet::{ContractAddress, storage::StorageMemberAccessTrait}; use starknet_bridge::mocks::{ messaging::{IMockMessagingDispatcherTrait, IMockMessagingDispatcher}, erc20::ERC20 }; +use piltover::messaging::{IMessaging, IMessagingDispatcher, IMessagingDispatcherTrait}; use starknet_bridge::bridge::{ ITokenBridge, ITokenBridgeAdmin, ITokenBridgeDispatcher, ITokenBridgeDispatcherTrait, ITokenBridgeAdminDispatcher, ITokenBridgeAdminDispatcherTrait, IWithdrawalLimitStatusDispatcher, @@ -20,25 +24,202 @@ use openzeppelin::access::ownable::{ OwnableComponent, OwnableComponent::Event as OwnableEvent, interface::{IOwnableTwoStepDispatcher, IOwnableTwoStepDispatcherTrait} }; + +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 super::utils::constants::{OWNER, L3_BRIDGE_ADDRESS, DELAY_TIME}; +use super::utils::setup::{ deploy_erc20, deploy_token_bridge_with_messaging, deploy_token_bridge, mock_state_testing }; + #[test] fn deposit_ok() { let (token_bridge, mut spy, messaging_mock) = deploy_token_bridge_with_messaging(); let usdc_address = deploy_erc20("usdc", "usdc"); + let usdc = IERC20Dispatcher { contract_address: usdc_address }; + let messaging = IMessagingDispatcher { contract_address: messaging_mock.contract_address }; + + snf::start_cheat_caller_address(usdc_address, OWNER()); + usdc.transfer(snf::test_address(), 100); + snf::stop_cheat_caller_address(usdc_address); + + assert(token_bridge.get_status(usdc_address) == TokenStatus::Unknown, 'Should be Unknown'); + + token_bridge.enroll_token(usdc_address); + assert(token_bridge.get_status(usdc_address) == TokenStatus::Pending, 'Should be Pending'); + + // Enroll token will emit the event `TokenEnrollmentInitiated` + // Getting the deployment_message_hash from the emitted event + let (_, event) = spy.get_events().emitted_by(token_bridge.contract_address).events.at(0); + let deployment_message_hash = event.data.at(1); + + messaging_mock.update_state_for_message(*deployment_message_hash); + + // Successfully updates the nonce + let nonce: felt252 = messaging.sn_to_appchain_messages(*deployment_message_hash); + assert(nonce == 0, 'Nonce no zero'); + + token_bridge.check_deployment_status(usdc_address); + + let final_status = token_bridge.get_status(usdc_address); + assert(final_status == TokenStatus::Active, 'Should be Active'); + + usdc.approve(token_bridge.contract_address, 100); + token_bridge.deposit(usdc_address, 100, snf::test_address()); +} + + +#[test] +#[should_panic(expected: ('ERC20: insufficient balance',))] +fn deposit_issufficient_balance() { + let (token_bridge, mut spy, messaging_mock) = deploy_token_bridge_with_messaging(); + let usdc_address = deploy_erc20("usdc", "usdc"); + let usdc = IERC20Dispatcher { contract_address: usdc_address }; + let messaging = IMessagingDispatcher { contract_address: messaging_mock.contract_address }; + + snf::start_cheat_caller_address(usdc_address, OWNER()); + usdc.transfer(snf::test_address(), 100); + snf::stop_cheat_caller_address(usdc_address); + + assert(token_bridge.get_status(usdc_address) == TokenStatus::Unknown, 'Should be Unknown'); + + token_bridge.enroll_token(usdc_address); + assert(token_bridge.get_status(usdc_address) == TokenStatus::Pending, 'Should be Pending'); + + // Enroll token will emit the event `TokenEnrollmentInitiated` + // Getting the deployment_message_hash from the emitted event + let (_, event) = spy.get_events().emitted_by(token_bridge.contract_address).events.at(0); + let deployment_message_hash = event.data.at(1); + + messaging_mock.update_state_for_message(*deployment_message_hash); + + // Successfully updates the nonce + let nonce: felt252 = messaging.sn_to_appchain_messages(*deployment_message_hash); + assert(nonce == 0, 'Nonce no zero'); + + token_bridge.check_deployment_status(usdc_address); + + let final_status = token_bridge.get_status(usdc_address); + assert(final_status == TokenStatus::Active, 'Should be Active'); + + usdc.approve(token_bridge.contract_address, 200); + token_bridge.deposit(usdc_address, 200, snf::test_address()); +} + +#[test] +#[should_panic(expected: ('ERC20: insufficient allowance',))] +fn deposit_insufficient_allowance() { + let (token_bridge, mut spy, messaging_mock) = deploy_token_bridge_with_messaging(); + let usdc_address = deploy_erc20("usdc", "usdc"); + let usdc = IERC20Dispatcher { contract_address: usdc_address }; + let messaging = IMessagingDispatcher { contract_address: messaging_mock.contract_address }; + + snf::start_cheat_caller_address(usdc_address, OWNER()); + usdc.transfer(snf::test_address(), 100); + snf::stop_cheat_caller_address(usdc_address); + + assert(token_bridge.get_status(usdc_address) == TokenStatus::Unknown, 'Should be Unknown'); + + token_bridge.enroll_token(usdc_address); + assert(token_bridge.get_status(usdc_address) == TokenStatus::Pending, 'Should be Pending'); + + // Enroll token will emit the event `TokenEnrollmentInitiated` + // Getting the deployment_message_hash from the emitted event + let (_, event) = spy.get_events().emitted_by(token_bridge.contract_address).events.at(0); + let deployment_message_hash = event.data.at(1); + + messaging_mock.update_state_for_message(*deployment_message_hash); + + // Successfully updates the nonce + let nonce: felt252 = messaging.sn_to_appchain_messages(*deployment_message_hash); + assert(nonce == 0, 'Nonce no zero'); + + token_bridge.check_deployment_status(usdc_address); + + let final_status = token_bridge.get_status(usdc_address); + assert(final_status == TokenStatus::Active, 'Should be Active'); + + token_bridge.deposit(usdc_address, 100, snf::test_address()); +} + +#[test] +fn deposit_with_message_ok() { + let (token_bridge, mut spy, messaging_mock) = deploy_token_bridge_with_messaging(); + let usdc_address = deploy_erc20("usdc", "usdc"); + let usdc = IERC20Dispatcher { contract_address: usdc_address }; + let messaging = IMessagingDispatcher { contract_address: messaging_mock.contract_address }; + + snf::start_cheat_caller_address(usdc_address, OWNER()); + usdc.transfer(snf::test_address(), 100); + snf::stop_cheat_caller_address(usdc_address); + + assert(token_bridge.get_status(usdc_address) == TokenStatus::Unknown, 'Should be Unknown'); + + token_bridge.enroll_token(usdc_address); + assert(token_bridge.get_status(usdc_address) == TokenStatus::Pending, 'Should be Pending'); + + // Enroll token will emit the event `TokenEnrollmentInitiated` + // Getting the deployment_message_hash from the emitted event + let (_, event) = spy.get_events().emitted_by(token_bridge.contract_address).events.at(0); + let deployment_message_hash = event.data.at(1); + + messaging_mock.update_state_for_message(*deployment_message_hash); + + // Successfully updates the nonce + let nonce: felt252 = messaging.sn_to_appchain_messages(*deployment_message_hash); + assert(nonce == 0, 'Nonce no zero'); + + token_bridge.check_deployment_status(usdc_address); + + let final_status = token_bridge.get_status(usdc_address); + assert(final_status == TokenStatus::Active, 'Should be Active'); + + let mut calldata = ArrayTrait::new(); + 'param1'.serialize(ref calldata); + 'param2'.serialize(ref calldata); + + usdc.approve(token_bridge.contract_address, 100); + token_bridge.deposit_with_message(usdc_address, 100, snf::test_address(), calldata.span()); +} + +#[test] +fn deposit_with_message_empty_message_ok() { + let (token_bridge, mut spy, messaging_mock) = deploy_token_bridge_with_messaging(); + let usdc_address = deploy_erc20("usdc", "usdc"); + let usdc = IERC20Dispatcher { contract_address: usdc_address }; + let messaging = IMessagingDispatcher { contract_address: messaging_mock.contract_address }; + + snf::start_cheat_caller_address(usdc_address, OWNER()); + usdc.transfer(snf::test_address(), 100); + snf::stop_cheat_caller_address(usdc_address); + + assert(token_bridge.get_status(usdc_address) == TokenStatus::Unknown, 'Should be Unknown'); token_bridge.enroll_token(usdc_address); + assert(token_bridge.get_status(usdc_address) == TokenStatus::Pending, 'Should be Pending'); // Enroll token will emit the event `TokenEnrollmentInitiated` // Getting the deployment_message_hash from the emitted event - let (_, event) = spy.get_events().events.at(0); - let deployment_message_hash = event.data.at(0); + let (_, event) = spy.get_events().emitted_by(token_bridge.contract_address).events.at(0); + let deployment_message_hash = event.data.at(1); messaging_mock.update_state_for_message(*deployment_message_hash); - assert(token_bridge.get_status(usdc_address) == TokenStatus::Blocked, 'Should be blocked'); + // Successfully updates the nonce + let nonce: felt252 = messaging.sn_to_appchain_messages(*deployment_message_hash); + assert(nonce == 0, 'Nonce no zero'); + + token_bridge.check_deployment_status(usdc_address); + + let final_status = token_bridge.get_status(usdc_address); + assert(final_status == TokenStatus::Active, 'Should be Active'); + + let mut calldata = ArrayTrait::new(); + 'param1'.serialize(ref calldata); + 'param2'.serialize(ref calldata); + + usdc.approve(token_bridge.contract_address, 100); + token_bridge.deposit_with_message(usdc_address, 100, snf::test_address(), calldata.span()); } + diff --git a/tests/enroll_token_test.cairo b/tests/enroll_token_test.cairo new file mode 100644 index 0000000..114cbdf --- /dev/null +++ b/tests/enroll_token_test.cairo @@ -0,0 +1,55 @@ +use starknet_bridge::bridge::token_bridge::TokenBridge::__member_module_token_settings::InternalContractMemberStateTrait; +use core::array::ArrayTrait; +use core::serde::Serde; +use core::result::ResultTrait; +use core::option::OptionTrait; +use core::traits::TryInto; +use snforge_std as snf; +use snforge_std::{ContractClassTrait, EventSpy, EventSpyTrait, EventSpyAssertionsTrait}; +use starknet::{ContractAddress, storage::StorageMemberAccessTrait}; +use starknet_bridge::mocks::{ + messaging::{IMockMessagingDispatcherTrait, IMockMessagingDispatcher}, erc20::ERC20 +}; +use starknet_bridge::bridge::{ + ITokenBridge, ITokenBridgeAdmin, ITokenBridgeDispatcher, ITokenBridgeDispatcherTrait, + ITokenBridgeAdminDispatcher, ITokenBridgeAdminDispatcherTrait, IWithdrawalLimitStatusDispatcher, + IWithdrawalLimitStatusDispatcherTrait, TokenBridge, TokenBridge::Event, + types::{TokenStatus, TokenSettings} +}; +use openzeppelin::access::ownable::{ + OwnableComponent, OwnableComponent::Event as OwnableEvent, + interface::{IOwnableTwoStepDispatcher, IOwnableTwoStepDispatcherTrait} +}; +use starknet::contract_address::{contract_address_const}; +use super::utils::constants::{OWNER, L3_BRIDGE_ADDRESS, DELAY_TIME}; +use super::utils::setup::{deploy_erc20, deploy_token_bridge, mock_state_testing}; + + +#[test] +fn enroll_token_ok() { + let (token_bridge, _) = deploy_token_bridge(); + + let usdc_address = deploy_erc20("USDC", "USDC"); + + let old_status = token_bridge.get_status(usdc_address); + assert(old_status == TokenStatus::Unknown, 'Should be unknown before'); + + token_bridge.enroll_token(usdc_address); + + let new_status = token_bridge.get_status(usdc_address); + assert(new_status == TokenStatus::Pending, 'Should be pending now'); +} + +#[test] +#[should_panic(expected: ('Already enrolled',))] +fn enroll_token_already_enrolled() { + let (token_bridge, _) = deploy_token_bridge(); + + let usdc_address = deploy_erc20("USDC", "USDC"); + token_bridge.enroll_token(usdc_address); + + let new_status = token_bridge.get_status(usdc_address); + assert(new_status == TokenStatus::Pending, 'Should be pending now'); + + token_bridge.enroll_token(usdc_address); +} diff --git a/tests/lib.cairo b/tests/lib.cairo index 1f1bf18..23ffeeb 100644 --- a/tests/lib.cairo +++ b/tests/lib.cairo @@ -1,6 +1,9 @@ pub mod token_bridge_test; -pub mod constants; -pub mod setup; +mod utils { + pub mod setup; + pub mod constants; +} pub mod token_actions_test; +pub mod enroll_token_test; pub mod deposit_flow_test; diff --git a/tests/token_actions_test.cairo b/tests/token_actions_test.cairo index 2e2e7f2..eb7b4c9 100644 --- a/tests/token_actions_test.cairo +++ b/tests/token_actions_test.cairo @@ -21,8 +21,8 @@ use openzeppelin::access::ownable::{ interface::{IOwnableTwoStepDispatcher, IOwnableTwoStepDispatcherTrait} }; use starknet::contract_address::{contract_address_const}; -use super::constants::{OWNER, L3_BRIDGE_ADDRESS, DELAY_TIME}; -use super::setup::{deploy_erc20, deploy_token_bridge, mock_state_testing}; +use super::utils::constants::{OWNER, L3_BRIDGE_ADDRESS, DELAY_TIME}; +use super::utils::setup::{deploy_erc20, deploy_token_bridge, mock_state_testing}; #[test] diff --git a/tests/token_bridge_test.cairo b/tests/token_bridge_test.cairo index c543534..c5ca810 100644 --- a/tests/token_bridge_test.cairo +++ b/tests/token_bridge_test.cairo @@ -21,8 +21,8 @@ use openzeppelin::access::ownable::{ interface::{IOwnableTwoStepDispatcher, IOwnableTwoStepDispatcherTrait} }; use starknet::contract_address::{contract_address_const}; -use super::constants::{OWNER, L3_BRIDGE_ADDRESS, DELAY_TIME}; -use super::setup::{deploy_erc20, deploy_token_bridge, mock_state_testing}; +use super::utils::constants::{OWNER, L3_BRIDGE_ADDRESS, DELAY_TIME}; +use super::utils::setup::{deploy_erc20, deploy_token_bridge, mock_state_testing}; #[test] @@ -88,20 +88,6 @@ fn set_appchain_bridge_not_owner() { ); } -#[test] -fn enroll_token_ok() { - let (token_bridge, _) = deploy_token_bridge(); - - let usdc_address = deploy_erc20("USDC", "USDC"); - - let old_status = token_bridge.get_status(usdc_address); - assert(old_status == TokenStatus::Unknown, 'Should be unknown before'); - - token_bridge.enroll_token(usdc_address); - - let new_status = token_bridge.get_status(usdc_address); - assert(new_status == TokenStatus::Pending, 'Should be pending now'); -} #[test] #[should_panic(expected: ('Caller is not the owner',))] diff --git a/tests/constants.cairo b/tests/utils/constants.cairo similarity index 100% rename from tests/constants.cairo rename to tests/utils/constants.cairo diff --git a/tests/setup.cairo b/tests/utils/setup.cairo similarity index 96% rename from tests/setup.cairo rename to tests/utils/setup.cairo index fefa873..4028fb0 100644 --- a/tests/setup.cairo +++ b/tests/utils/setup.cairo @@ -1,5 +1,7 @@ use snforge_std as snf; -use snforge_std::{ContractClassTrait, EventSpy, EventSpyTrait, EventSpyAssertionsTrait}; +use snforge_std::{ + ContractClassTrait, EventSpy, EventSpyTrait, EventsFilterTrait, EventSpyAssertionsTrait +}; use starknet::{ContractAddress, storage::StorageMemberAccessTrait}; use starknet_bridge::mocks::{ messaging::{IMockMessagingDispatcherTrait, IMockMessagingDispatcher}, erc20::ERC20 From fc691b50a339fb04ae49e8dac9c0c066de0dbc8e Mon Sep 17 00:00:00 2001 From: byteZorvin Date: Mon, 5 Aug 2024 11:24:40 +0530 Subject: [PATCH 22/62] change to mock usdc address --- .tool-versions | 2 +- tests/enroll_token_test.cairo | 23 ++++++++++++++++++++++- tests/token_actions_test.cairo | 18 +++++++++--------- tests/utils/constants.cairo | 4 ++++ 4 files changed, 36 insertions(+), 11 deletions(-) diff --git a/.tool-versions b/.tool-versions index 67f5ccf..fbe9b81 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1,2 +1,2 @@ -scarb 2.7.0 +scarb 2.6.5 starknet-foundry 0.27.0 diff --git a/tests/enroll_token_test.cairo b/tests/enroll_token_test.cairo index 114cbdf..c79c8a4 100644 --- a/tests/enroll_token_test.cairo +++ b/tests/enroll_token_test.cairo @@ -21,7 +21,7 @@ use openzeppelin::access::ownable::{ interface::{IOwnableTwoStepDispatcher, IOwnableTwoStepDispatcherTrait} }; use starknet::contract_address::{contract_address_const}; -use super::utils::constants::{OWNER, L3_BRIDGE_ADDRESS, DELAY_TIME}; +use super::utils::constants::{OWNER, L3_BRIDGE_ADDRESS, USDC_MOCK_ADDRESS, DELAY_TIME}; use super::utils::setup::{deploy_erc20, deploy_token_bridge, mock_state_testing}; @@ -53,3 +53,24 @@ fn enroll_token_already_enrolled() { token_bridge.enroll_token(usdc_address); } + +#[test] +#[should_panic(expected: ('Already enrolled',))] +fn enroll_token_blocked() { + let mut mock = mock_state_testing(); + + let usdc_address = USDC_MOCK_ADDRESS(); + + // Setting the token active + let old_settings = mock.token_settings.read(usdc_address); + mock + .token_settings + .write(usdc_address, TokenSettings { token_status: TokenStatus::Blocked, ..old_settings }); + + mock.ownable.Ownable_owner.write(OWNER()); + + snf::start_cheat_caller_address_global(OWNER()); + mock.enroll_token(usdc_address); +} + +fn enroll_token_piltover() {} diff --git a/tests/token_actions_test.cairo b/tests/token_actions_test.cairo index eb7b4c9..305c4ee 100644 --- a/tests/token_actions_test.cairo +++ b/tests/token_actions_test.cairo @@ -21,7 +21,7 @@ use openzeppelin::access::ownable::{ interface::{IOwnableTwoStepDispatcher, IOwnableTwoStepDispatcherTrait} }; use starknet::contract_address::{contract_address_const}; -use super::utils::constants::{OWNER, L3_BRIDGE_ADDRESS, DELAY_TIME}; +use super::utils::constants::{OWNER, L3_BRIDGE_ADDRESS, USDC_MOCK_ADDRESS, DELAY_TIME}; use super::utils::setup::{deploy_erc20, deploy_token_bridge, mock_state_testing}; @@ -237,7 +237,7 @@ fn unblock_token_not_owner() { #[should_panic(expected: ('Token not blocked',))] fn unblock_token_not_blocked() { let mut mock = mock_state_testing(); - let usdc_address = deploy_erc20("usdc", "usdc"); + let usdc_address = USDC_MOCK_ADDRESS(); // Setting the token active let old_settings = mock.token_settings.read(usdc_address); @@ -246,7 +246,7 @@ fn unblock_token_not_blocked() { .write(usdc_address, TokenSettings { token_status: TokenStatus::Active, ..old_settings }); mock.ownable.Ownable_owner.write(OWNER()); - snf::cheat_caller_address_global(OWNER()); + snf::start_cheat_caller_address_global(OWNER()); mock.unblock_token(usdc_address); } @@ -254,7 +254,7 @@ fn unblock_token_not_blocked() { #[test] fn reactivate_token_ok() { let mut mock = mock_state_testing(); - let usdc_address = deploy_erc20("usdc", "usdc"); + let usdc_address = USDC_MOCK_ADDRESS(); // Setting the token active let old_settings = mock.token_settings.read(usdc_address); @@ -266,7 +266,7 @@ fn reactivate_token_ok() { mock.ownable.Ownable_owner.write(OWNER()); - snf::cheat_caller_address_global(OWNER()); + snf::start_cheat_caller_address_global(OWNER()); mock.reactivate_token(usdc_address); assert(mock.get_status(usdc_address) == TokenStatus::Active, 'Did not reactivate'); @@ -276,7 +276,7 @@ fn reactivate_token_ok() { #[should_panic(expected: ('Caller is not the owner',))] fn reactivate_token_not_owner() { let mut mock = mock_state_testing(); - let usdc_address = deploy_erc20("usdc", "usdc"); + let usdc_address = USDC_MOCK_ADDRESS(); // Setting the token active let old_settings = mock.token_settings.read(usdc_address); @@ -286,7 +286,7 @@ fn reactivate_token_not_owner() { usdc_address, TokenSettings { token_status: TokenStatus::Deactivated, ..old_settings } ); - snf::cheat_caller_address_global(snf::test_address()); + snf::start_cheat_caller_address_global(snf::test_address()); mock.reactivate_token(usdc_address); } @@ -295,7 +295,7 @@ fn reactivate_token_not_owner() { #[should_panic(expected: ('Token not deactivated',))] fn reactivate_token_not_deactivated() { let mut mock = mock_state_testing(); - let usdc_address = deploy_erc20("usdc", "usdc"); + let usdc_address = USDC_MOCK_ADDRESS(); // Setting the token active let old_settings = mock.token_settings.read(usdc_address); @@ -304,7 +304,7 @@ fn reactivate_token_not_deactivated() { .write(usdc_address, TokenSettings { token_status: TokenStatus::Blocked, ..old_settings }); mock.ownable.Ownable_owner.write(OWNER()); - snf::cheat_caller_address_global(OWNER()); + snf::start_cheat_caller_address_global(OWNER()); mock.reactivate_token(usdc_address); } diff --git a/tests/utils/constants.cairo b/tests/utils/constants.cairo index cb8f018..e19ae54 100644 --- a/tests/utils/constants.cairo +++ b/tests/utils/constants.cairo @@ -8,6 +8,10 @@ pub fn L3_BRIDGE_ADDRESS() -> ContractAddress { contract_address_const::<'l3_bridge_address'>() } +pub fn USDC_MOCK_ADDRESS() -> ContractAddress { + contract_address_const::<'Usdc address'>() +} + // 5 days as the delay time (5 * 86400 = 432000) pub const DELAY_TIME: felt252 = 432000; From 02205bd63ac3bace7f021b28374b3267237ebc26 Mon Sep 17 00:00:00 2001 From: byteZorvin Date: Mon, 5 Aug 2024 11:40:33 +0530 Subject: [PATCH 23/62] improve: not needed to deploy usdc in while mock testing --- tests/constants.cairo | 3 +++ tests/token_bridge_test.cairo | 20 ++++++++++---------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/tests/constants.cairo b/tests/constants.cairo index cb8f018..8f56b1c 100644 --- a/tests/constants.cairo +++ b/tests/constants.cairo @@ -8,6 +8,9 @@ pub fn L3_BRIDGE_ADDRESS() -> ContractAddress { contract_address_const::<'l3_bridge_address'>() } +pub fn USDC_MOCK_ADDRESS() -> ContractAddress { + contract_address_const::<'Usdc address'>() +} // 5 days as the delay time (5 * 86400 = 432000) pub const DELAY_TIME: felt252 = 432000; diff --git a/tests/token_bridge_test.cairo b/tests/token_bridge_test.cairo index 3380c8f..7726ca0 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::constants::{OWNER, L3_BRIDGE_ADDRESS, DELAY_TIME}; +use super::constants::{OWNER, L3_BRIDGE_ADDRESS, USDC_MOCK_ADDRESS, DELAY_TIME}; fn deploy_erc20(name: ByteArray, symbol: ByteArray) -> ContractAddress { @@ -208,7 +208,7 @@ fn set_max_total_balance_ok() { #[test] fn block_token_ok() { let mut mock = mock_state_testing(); - let usdc_address = deploy_erc20("usdc", "usdc"); + let usdc_address = USDC_MOCK_ADDRESS(); mock.ownable.Ownable_owner.write(OWNER()); snf::cheat_caller_address_global(OWNER()); @@ -222,7 +222,7 @@ fn block_token_ok() { #[should_panic(expected: ('Caller is not the owner',))] fn block_token_not_owner() { let mut mock = mock_state_testing(); - let usdc_address = deploy_erc20("usdc", "usdc"); + let usdc_address = USDC_MOCK_ADDRESS(); mock.ownable.Ownable_owner.write(OWNER()); snf::cheat_caller_address_global(snf::test_address()); @@ -234,7 +234,7 @@ fn block_token_not_owner() { #[should_panic(expected: ('Only unknown can be blocked',))] fn block_token_not_unknown() { let mut mock = mock_state_testing(); - let usdc_address = deploy_erc20("usdc", "usdc"); + let usdc_address = USDC_MOCK_ADDRESS(); // Setting the token active let old_settings = mock.token_settings.read(usdc_address); @@ -341,7 +341,7 @@ fn disable_withdrwal_not_owner() { #[test] fn unblock_token_ok() { let mut mock = mock_state_testing(); - let usdc_address = deploy_erc20("usdc", "usdc"); + let usdc_address = USDC_MOCK_ADDRESS(); // Setting the token active let old_settings = mock.token_settings.read(usdc_address); @@ -360,7 +360,7 @@ fn unblock_token_ok() { #[should_panic(expected: ('Caller is not the owner',))] fn unblock_token_not_owner() { let mut mock = mock_state_testing(); - let usdc_address = deploy_erc20("usdc", "usdc"); + let usdc_address = USDC_MOCK_ADDRESS(); // Setting the token active let old_settings = mock.token_settings.read(usdc_address); @@ -379,7 +379,7 @@ fn unblock_token_not_owner() { #[should_panic(expected: ('Token not blocked',))] fn unblock_token_not_blocked() { let mut mock = mock_state_testing(); - let usdc_address = deploy_erc20("usdc", "usdc"); + let usdc_address = USDC_MOCK_ADDRESS(); // Setting the token active let old_settings = mock.token_settings.read(usdc_address); @@ -396,7 +396,7 @@ fn unblock_token_not_blocked() { #[test] fn reactivate_token_ok() { let mut mock = mock_state_testing(); - let usdc_address = deploy_erc20("usdc", "usdc"); + let usdc_address = USDC_MOCK_ADDRESS(); // Setting the token active let old_settings = mock.token_settings.read(usdc_address); @@ -418,7 +418,7 @@ fn reactivate_token_ok() { #[should_panic(expected: ('Caller is not the owner',))] fn reactivate_token_not_owner() { let mut mock = mock_state_testing(); - let usdc_address = deploy_erc20("usdc", "usdc"); + let usdc_address = USDC_MOCK_ADDRESS(); // Setting the token active let old_settings = mock.token_settings.read(usdc_address); @@ -437,7 +437,7 @@ fn reactivate_token_not_owner() { #[should_panic(expected: ('Token not deactivated',))] fn reactivate_token_not_deactivated() { let mut mock = mock_state_testing(); - let usdc_address = deploy_erc20("usdc", "usdc"); + let usdc_address = USDC_MOCK_ADDRESS(); // Setting the token active let old_settings = mock.token_settings.read(usdc_address); From 2b285d370736e918016e22d6c29d9f6fdfca35d7 Mon Sep 17 00:00:00 2001 From: byteZorvin Date: Mon, 5 Aug 2024 14:04:00 +0530 Subject: [PATCH 24/62] unit testcases --- {tests => src/bridge/tests}/constants.cairo | 0 src/bridge/tests/test_bridge.cairo | 143 ++++++++++++++++++++ src/lib.cairo | 6 + tests/lib.cairo | 2 +- 4 files changed, 150 insertions(+), 1 deletion(-) rename {tests => src/bridge/tests}/constants.cairo (100%) create mode 100644 src/bridge/tests/test_bridge.cairo diff --git a/tests/constants.cairo b/src/bridge/tests/constants.cairo similarity index 100% rename from tests/constants.cairo rename to src/bridge/tests/constants.cairo diff --git a/src/bridge/tests/test_bridge.cairo b/src/bridge/tests/test_bridge.cairo new file mode 100644 index 0000000..fa8bb69 --- /dev/null +++ b/src/bridge/tests/test_bridge.cairo @@ -0,0 +1,143 @@ +use starknet_bridge::bridge::token_bridge::TokenBridge::__member_module_token_settings::InternalContractMemberStateTrait; +use snforge_std as snf; +use starknet::{ContractAddress, storage::StorageMemberAccessTrait}; +use starknet_bridge::mocks::{ + messaging::{IMockMessagingDispatcherTrait, IMockMessagingDispatcher}, erc20::ERC20 +}; +use starknet_bridge::bridge::{ + ITokenBridge, ITokenBridgeAdmin, ITokenBridgeDispatcher, ITokenBridgeDispatcherTrait, + ITokenBridgeAdminDispatcher, ITokenBridgeAdminDispatcherTrait, IWithdrawalLimitStatusDispatcher, + IWithdrawalLimitStatusDispatcherTrait, TokenBridge, TokenBridge::Event, + types::{TokenStatus, TokenSettings} +}; +use openzeppelin::access::ownable::{ + OwnableComponent, OwnableComponent::Event as OwnableEvent, + interface::{IOwnableTwoStepDispatcher, IOwnableTwoStepDispatcherTrait} +}; +use starknet::contract_address::{contract_address_const}; + +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() +} + +#[test] +fn unblock_token_ok() { + let mut mock = mock_state_testing(); + let usdc_address = USDC_MOCK_ADDRESS(); + + // Setting the token active + let old_settings = mock.token_settings.read(usdc_address); + mock + .token_settings + .write(usdc_address, TokenSettings { token_status: TokenStatus::Blocked, ..old_settings }); + + mock.ownable.Ownable_owner.write(OWNER()); + snf::cheat_caller_address_global(OWNER()); + + mock.unblock_token(usdc_address); + assert(mock.get_status(usdc_address) == TokenStatus::Unknown, 'Not unblocked'); +} + +#[test] +#[should_panic(expected: ('Caller is not the owner',))] +fn unblock_token_not_owner() { + let mut mock = mock_state_testing(); + let usdc_address = USDC_MOCK_ADDRESS(); + + // Setting the token active + let old_settings = mock.token_settings.read(usdc_address); + mock + .token_settings + .write(usdc_address, TokenSettings { token_status: TokenStatus::Blocked, ..old_settings }); + + mock.ownable.Ownable_owner.write(OWNER()); + snf::cheat_caller_address_global(snf::test_address()); + + mock.unblock_token(usdc_address); +} + + +#[test] +#[should_panic(expected: ('Token not blocked',))] +fn unblock_token_not_blocked() { + let mut mock = mock_state_testing(); + let usdc_address = USDC_MOCK_ADDRESS(); + + // Setting the token active + let old_settings = mock.token_settings.read(usdc_address); + mock + .token_settings + .write(usdc_address, TokenSettings { token_status: TokenStatus::Active, ..old_settings }); + + mock.ownable.Ownable_owner.write(OWNER()); + snf::cheat_caller_address_global(OWNER()); + + mock.unblock_token(usdc_address); +} + +#[test] +fn reactivate_token_ok() { + let mut mock = mock_state_testing(); + let usdc_address = USDC_MOCK_ADDRESS(); + + // Setting the token active + let old_settings = mock.token_settings.read(usdc_address); + mock + .token_settings + .write( + usdc_address, TokenSettings { token_status: TokenStatus::Deactivated, ..old_settings } + ); + + mock.ownable.Ownable_owner.write(OWNER()); + + snf::cheat_caller_address_global(OWNER()); + + mock.reactivate_token(usdc_address); + assert(mock.get_status(usdc_address) == TokenStatus::Active, 'Did not reactivate'); +} + +#[test] +#[should_panic(expected: ('Caller is not the owner',))] +fn reactivate_token_not_owner() { + let mut mock = mock_state_testing(); + let usdc_address = USDC_MOCK_ADDRESS(); + + // Setting the token active + let old_settings = mock.token_settings.read(usdc_address); + mock + .token_settings + .write( + usdc_address, TokenSettings { token_status: TokenStatus::Deactivated, ..old_settings } + ); + + snf::cheat_caller_address_global(snf::test_address()); + + mock.reactivate_token(usdc_address); +} + +#[test] +#[should_panic(expected: ('Token not deactivated',))] +fn reactivate_token_not_deactivated() { + let mut mock = mock_state_testing(); + let usdc_address = USDC_MOCK_ADDRESS(); + + // Setting the token active + let old_settings = mock.token_settings.read(usdc_address); + mock + .token_settings + .write(usdc_address, TokenSettings { token_status: TokenStatus::Blocked, ..old_settings }); + + mock.ownable.Ownable_owner.write(OWNER()); + snf::cheat_caller_address_global(OWNER()); + + mock.reactivate_token(usdc_address); +} + diff --git a/src/lib.cairo b/src/lib.cairo index 35b2563..a70ee19 100644 --- a/src/lib.cairo +++ b/src/lib.cairo @@ -3,6 +3,12 @@ pub mod bridge { pub mod interface; pub mod types; + #[cfg(test)] + pub mod tests { + pub mod constants; + mod test_bridge; + } + pub use token_bridge::TokenBridge; pub use interface::{ ITokenBridge, ITokenBridgeAdmin, IWithdrawalLimitStatus, ITokenBridgeDispatcher, diff --git a/tests/lib.cairo b/tests/lib.cairo index 910580a..212f2d0 100644 --- a/tests/lib.cairo +++ b/tests/lib.cairo @@ -1,5 +1,5 @@ pub mod token_bridge_test; -pub mod constants; +use starknet_bridge::bridge::tests::constants; pub mod setup; pub mod token_actions_test; From e36df0fd7705595374f147bcc1f742376fe6fd32 Mon Sep 17 00:00:00 2001 From: byteZorvin Date: Mon, 5 Aug 2024 16:55:38 +0530 Subject: [PATCH 25/62] add token actions restructure --- src/bridge/tests/token_actions_test.cairo | 186 ++++++++++++++++++++++ src/lib.cairo | 1 + tests/token_actions_test.cairo | 156 ------------------ 3 files changed, 187 insertions(+), 156 deletions(-) create mode 100644 src/bridge/tests/token_actions_test.cairo diff --git a/src/bridge/tests/token_actions_test.cairo b/src/bridge/tests/token_actions_test.cairo new file mode 100644 index 0000000..1895e09 --- /dev/null +++ b/src/bridge/tests/token_actions_test.cairo @@ -0,0 +1,186 @@ +use starknet_bridge::bridge::token_bridge::TokenBridge::__member_module_token_settings::InternalContractMemberStateTrait; +use snforge_std as snf; +use starknet::{ContractAddress, storage::StorageMemberAccessTrait}; +use starknet_bridge::mocks::{ + messaging::{IMockMessagingDispatcherTrait, IMockMessagingDispatcher}, erc20::ERC20 +}; +use starknet_bridge::bridge::{ + ITokenBridge, ITokenBridgeAdmin, ITokenBridgeDispatcher, ITokenBridgeDispatcherTrait, + ITokenBridgeAdminDispatcher, ITokenBridgeAdminDispatcherTrait, IWithdrawalLimitStatusDispatcher, + IWithdrawalLimitStatusDispatcherTrait, TokenBridge, TokenBridge::Event, + types::{TokenStatus, TokenSettings} +}; +use openzeppelin::access::ownable::{ + OwnableComponent, OwnableComponent::Event as OwnableEvent, + interface::{IOwnableTwoStepDispatcher, IOwnableTwoStepDispatcherTrait} +}; +use starknet::contract_address::{contract_address_const}; + +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() +} + +#[test] +fn block_token_ok() { + let mut mock = mock_state_testing(); + let usdc_address = USDC_MOCK_ADDRESS(); + + mock.ownable.Ownable_owner.write(OWNER()); + snf::cheat_caller_address_global(OWNER()); + + mock.block_token(usdc_address); + assert(mock.get_status(usdc_address) == TokenStatus::Blocked, 'Token not blocked'); +} + + +#[test] +#[should_panic(expected: ('Caller is not the owner',))] +fn block_token_not_owner() { + let mut mock = mock_state_testing(); + let usdc_address = USDC_MOCK_ADDRESS(); + + mock.ownable.Ownable_owner.write(OWNER()); + snf::cheat_caller_address_global(snf::test_address()); + + mock.block_token(usdc_address); +} + +#[test] +#[should_panic(expected: ('Only unknown can be blocked',))] +fn block_token_not_unknown() { + let mut mock = mock_state_testing(); + let usdc_address = USDC_MOCK_ADDRESS(); + + // Setting the token active + let old_settings = mock.token_settings.read(usdc_address); + mock + .token_settings + .write(usdc_address, TokenSettings { token_status: TokenStatus::Active, ..old_settings }); + + mock.ownable.Ownable_owner.write(OWNER()); + snf::cheat_caller_address_global(OWNER()); + + mock.block_token(usdc_address); +} + +#[test] +fn unblock_token_ok() { + let mut mock = mock_state_testing(); + let usdc_address = USDC_MOCK_ADDRESS(); + + // Setting the token active + let old_settings = mock.token_settings.read(usdc_address); + mock + .token_settings + .write(usdc_address, TokenSettings { token_status: TokenStatus::Blocked, ..old_settings }); + + mock.ownable.Ownable_owner.write(OWNER()); + snf::cheat_caller_address_global(OWNER()); + + mock.unblock_token(usdc_address); + assert(mock.get_status(usdc_address) == TokenStatus::Unknown, 'Not unblocked'); +} + +#[test] +#[should_panic(expected: ('Caller is not the owner',))] +fn unblock_token_not_owner() { + let mut mock = mock_state_testing(); + let usdc_address = USDC_MOCK_ADDRESS(); + + // Setting the token active + let old_settings = mock.token_settings.read(usdc_address); + mock + .token_settings + .write(usdc_address, TokenSettings { token_status: TokenStatus::Blocked, ..old_settings }); + + mock.ownable.Ownable_owner.write(OWNER()); + snf::cheat_caller_address_global(snf::test_address()); + + mock.unblock_token(usdc_address); +} + + +#[test] +#[should_panic(expected: ('Token not blocked',))] +fn unblock_token_not_blocked() { + let mut mock = mock_state_testing(); + let usdc_address = USDC_MOCK_ADDRESS(); + + // Setting the token active + let old_settings = mock.token_settings.read(usdc_address); + mock + .token_settings + .write(usdc_address, TokenSettings { token_status: TokenStatus::Active, ..old_settings }); + + mock.ownable.Ownable_owner.write(OWNER()); + snf::cheat_caller_address_global(OWNER()); + + mock.unblock_token(usdc_address); +} + +#[test] +fn reactivate_token_ok() { + let mut mock = mock_state_testing(); + let usdc_address = USDC_MOCK_ADDRESS(); + + // Setting the token active + let old_settings = mock.token_settings.read(usdc_address); + mock + .token_settings + .write( + usdc_address, TokenSettings { token_status: TokenStatus::Deactivated, ..old_settings } + ); + + mock.ownable.Ownable_owner.write(OWNER()); + + snf::cheat_caller_address_global(OWNER()); + + mock.reactivate_token(usdc_address); + assert(mock.get_status(usdc_address) == TokenStatus::Active, 'Did not reactivate'); +} + +#[test] +#[should_panic(expected: ('Caller is not the owner',))] +fn reactivate_token_not_owner() { + let mut mock = mock_state_testing(); + let usdc_address = USDC_MOCK_ADDRESS(); + + // Setting the token active + let old_settings = mock.token_settings.read(usdc_address); + mock + .token_settings + .write( + usdc_address, TokenSettings { token_status: TokenStatus::Deactivated, ..old_settings } + ); + + snf::cheat_caller_address_global(snf::test_address()); + + mock.reactivate_token(usdc_address); +} + +#[test] +#[should_panic(expected: ('Token not deactivated',))] +fn reactivate_token_not_deactivated() { + let mut mock = mock_state_testing(); + let usdc_address = USDC_MOCK_ADDRESS(); + + // Setting the token active + let old_settings = mock.token_settings.read(usdc_address); + mock + .token_settings + .write(usdc_address, TokenSettings { token_status: TokenStatus::Blocked, ..old_settings }); + + mock.ownable.Ownable_owner.write(OWNER()); + snf::cheat_caller_address_global(OWNER()); + + mock.reactivate_token(usdc_address); +} + diff --git a/src/lib.cairo b/src/lib.cairo index a70ee19..5ab81a7 100644 --- a/src/lib.cairo +++ b/src/lib.cairo @@ -7,6 +7,7 @@ pub mod bridge { pub mod tests { pub mod constants; mod test_bridge; + mod token_actions_test; } pub use token_bridge::TokenBridge; diff --git a/tests/token_actions_test.cairo b/tests/token_actions_test.cairo index 3cb0598..4aeca8a 100644 --- a/tests/token_actions_test.cairo +++ b/tests/token_actions_test.cairo @@ -25,49 +25,6 @@ use super::constants::{OWNER, L3_BRIDGE_ADDRESS, USDC_MOCK_ADDRESS, DELAY_TIME}; use super::setup::{deploy_erc20, deploy_token_bridge, mock_state_testing}; -#[test] -fn block_token_ok() { - let mut mock = mock_state_testing(); - let usdc_address = USDC_MOCK_ADDRESS(); - - mock.ownable.Ownable_owner.write(OWNER()); - snf::cheat_caller_address_global(OWNER()); - - mock.block_token(usdc_address); - assert(mock.get_status(usdc_address) == TokenStatus::Blocked, 'Token not blocked'); -} - - -#[test] -#[should_panic(expected: ('Caller is not the owner',))] -fn block_token_not_owner() { - let mut mock = mock_state_testing(); - let usdc_address = USDC_MOCK_ADDRESS(); - - mock.ownable.Ownable_owner.write(OWNER()); - snf::cheat_caller_address_global(snf::test_address()); - - mock.block_token(usdc_address); -} - -#[test] -#[should_panic(expected: ('Only unknown can be blocked',))] -fn block_token_not_unknown() { - let mut mock = mock_state_testing(); - let usdc_address = USDC_MOCK_ADDRESS(); - - // Setting the token active - let old_settings = mock.token_settings.read(usdc_address); - mock - .token_settings - .write(usdc_address, TokenSettings { token_status: TokenStatus::Active, ..old_settings }); - - mock.ownable.Ownable_owner.write(OWNER()); - snf::cheat_caller_address_global(OWNER()); - - mock.block_token(usdc_address); -} - #[test] #[should_panic(expected: ('Caller is not the owner',))] fn enable_withdrawal_limit_not_owner() { @@ -157,116 +114,3 @@ fn disable_withdrwal_not_owner() { withdrawal_limit.is_withdrawal_limit_applied(usdc_address) == false, 'Limit not applied' ); } - -#[test] -fn unblock_token_ok() { - let mut mock = mock_state_testing(); - let usdc_address = USDC_MOCK_ADDRESS(); - - // Setting the token active - let old_settings = mock.token_settings.read(usdc_address); - mock - .token_settings - .write(usdc_address, TokenSettings { token_status: TokenStatus::Blocked, ..old_settings }); - - mock.ownable.Ownable_owner.write(OWNER()); - snf::cheat_caller_address_global(OWNER()); - - mock.unblock_token(usdc_address); - assert(mock.get_status(usdc_address) == TokenStatus::Unknown, 'Not unblocked'); -} - -#[test] -#[should_panic(expected: ('Caller is not the owner',))] -fn unblock_token_not_owner() { - let mut mock = mock_state_testing(); - let usdc_address = USDC_MOCK_ADDRESS(); - - // Setting the token active - let old_settings = mock.token_settings.read(usdc_address); - mock - .token_settings - .write(usdc_address, TokenSettings { token_status: TokenStatus::Blocked, ..old_settings }); - - mock.ownable.Ownable_owner.write(OWNER()); - snf::cheat_caller_address_global(snf::test_address()); - - mock.unblock_token(usdc_address); -} - - -#[test] -#[should_panic(expected: ('Token not blocked',))] -fn unblock_token_not_blocked() { - let mut mock = mock_state_testing(); - let usdc_address = USDC_MOCK_ADDRESS(); - - // Setting the token active - let old_settings = mock.token_settings.read(usdc_address); - mock - .token_settings - .write(usdc_address, TokenSettings { token_status: TokenStatus::Active, ..old_settings }); - - mock.ownable.Ownable_owner.write(OWNER()); - snf::cheat_caller_address_global(OWNER()); - - mock.unblock_token(usdc_address); -} - -#[test] -fn reactivate_token_ok() { - let mut mock = mock_state_testing(); - let usdc_address = USDC_MOCK_ADDRESS(); - - // Setting the token active - let old_settings = mock.token_settings.read(usdc_address); - mock - .token_settings - .write( - usdc_address, TokenSettings { token_status: TokenStatus::Deactivated, ..old_settings } - ); - - mock.ownable.Ownable_owner.write(OWNER()); - - snf::cheat_caller_address_global(OWNER()); - - mock.reactivate_token(usdc_address); - assert(mock.get_status(usdc_address) == TokenStatus::Active, 'Did not reactivate'); -} - -#[test] -#[should_panic(expected: ('Caller is not the owner',))] -fn reactivate_token_not_owner() { - let mut mock = mock_state_testing(); - let usdc_address = USDC_MOCK_ADDRESS(); - - // Setting the token active - let old_settings = mock.token_settings.read(usdc_address); - mock - .token_settings - .write( - usdc_address, TokenSettings { token_status: TokenStatus::Deactivated, ..old_settings } - ); - - snf::cheat_caller_address_global(snf::test_address()); - - mock.reactivate_token(usdc_address); -} - -#[test] -#[should_panic(expected: ('Token not deactivated',))] -fn reactivate_token_not_deactivated() { - let mut mock = mock_state_testing(); - let usdc_address = USDC_MOCK_ADDRESS(); - - // Setting the token active - let old_settings = mock.token_settings.read(usdc_address); - mock - .token_settings - .write(usdc_address, TokenSettings { token_status: TokenStatus::Blocked, ..old_settings }); - - mock.ownable.Ownable_owner.write(OWNER()); - snf::cheat_caller_address_global(OWNER()); - - mock.reactivate_token(usdc_address); -} From ae2f0e84f416426af3fa22736132f8b5fded04f2 Mon Sep 17 00:00:00 2001 From: byteZorvin Date: Mon, 5 Aug 2024 17:51:10 +0530 Subject: [PATCH 26/62] migrate to latest foundry --- src/bridge/tests/test_bridge.cairo | 12 ++++++------ src/bridge/tests/token_actions_test.cairo | 18 +++++++++--------- tests/constants.cairo | 0 tests/deposit_flow_test.cairo | 4 ++-- tests/enroll_token_test.cairo | 4 ++-- tests/{utils => }/setup.cairo | 0 tests/utils/constants.cairo | 18 ------------------ 7 files changed, 19 insertions(+), 37 deletions(-) delete mode 100644 tests/constants.cairo rename tests/{utils => }/setup.cairo (100%) delete mode 100644 tests/utils/constants.cairo diff --git a/src/bridge/tests/test_bridge.cairo b/src/bridge/tests/test_bridge.cairo index fa8bb69..f4eed8f 100644 --- a/src/bridge/tests/test_bridge.cairo +++ b/src/bridge/tests/test_bridge.cairo @@ -40,7 +40,7 @@ fn unblock_token_ok() { .write(usdc_address, TokenSettings { token_status: TokenStatus::Blocked, ..old_settings }); mock.ownable.Ownable_owner.write(OWNER()); - snf::cheat_caller_address_global(OWNER()); + snf::start_cheat_caller_address_global(OWNER()); mock.unblock_token(usdc_address); assert(mock.get_status(usdc_address) == TokenStatus::Unknown, 'Not unblocked'); @@ -59,7 +59,7 @@ fn unblock_token_not_owner() { .write(usdc_address, TokenSettings { token_status: TokenStatus::Blocked, ..old_settings }); mock.ownable.Ownable_owner.write(OWNER()); - snf::cheat_caller_address_global(snf::test_address()); + snf::start_cheat_caller_address_global(snf::test_address()); mock.unblock_token(usdc_address); } @@ -78,7 +78,7 @@ fn unblock_token_not_blocked() { .write(usdc_address, TokenSettings { token_status: TokenStatus::Active, ..old_settings }); mock.ownable.Ownable_owner.write(OWNER()); - snf::cheat_caller_address_global(OWNER()); + snf::start_cheat_caller_address_global(OWNER()); mock.unblock_token(usdc_address); } @@ -98,7 +98,7 @@ fn reactivate_token_ok() { mock.ownable.Ownable_owner.write(OWNER()); - snf::cheat_caller_address_global(OWNER()); + snf::start_cheat_caller_address_global(OWNER()); mock.reactivate_token(usdc_address); assert(mock.get_status(usdc_address) == TokenStatus::Active, 'Did not reactivate'); @@ -118,7 +118,7 @@ fn reactivate_token_not_owner() { usdc_address, TokenSettings { token_status: TokenStatus::Deactivated, ..old_settings } ); - snf::cheat_caller_address_global(snf::test_address()); + snf::start_cheat_caller_address_global(snf::test_address()); mock.reactivate_token(usdc_address); } @@ -136,7 +136,7 @@ fn reactivate_token_not_deactivated() { .write(usdc_address, TokenSettings { token_status: TokenStatus::Blocked, ..old_settings }); mock.ownable.Ownable_owner.write(OWNER()); - snf::cheat_caller_address_global(OWNER()); + snf::start_cheat_caller_address_global(OWNER()); mock.reactivate_token(usdc_address); } diff --git a/src/bridge/tests/token_actions_test.cairo b/src/bridge/tests/token_actions_test.cairo index 1895e09..3c4af39 100644 --- a/src/bridge/tests/token_actions_test.cairo +++ b/src/bridge/tests/token_actions_test.cairo @@ -34,7 +34,7 @@ fn block_token_ok() { let usdc_address = USDC_MOCK_ADDRESS(); mock.ownable.Ownable_owner.write(OWNER()); - snf::cheat_caller_address_global(OWNER()); + snf::start_cheat_caller_address_global(OWNER()); mock.block_token(usdc_address); assert(mock.get_status(usdc_address) == TokenStatus::Blocked, 'Token not blocked'); @@ -48,7 +48,7 @@ fn block_token_not_owner() { let usdc_address = USDC_MOCK_ADDRESS(); mock.ownable.Ownable_owner.write(OWNER()); - snf::cheat_caller_address_global(snf::test_address()); + snf::start_cheat_caller_address_global(snf::test_address()); mock.block_token(usdc_address); } @@ -66,7 +66,7 @@ fn block_token_not_unknown() { .write(usdc_address, TokenSettings { token_status: TokenStatus::Active, ..old_settings }); mock.ownable.Ownable_owner.write(OWNER()); - snf::cheat_caller_address_global(OWNER()); + snf::start_cheat_caller_address_global(OWNER()); mock.block_token(usdc_address); } @@ -83,7 +83,7 @@ fn unblock_token_ok() { .write(usdc_address, TokenSettings { token_status: TokenStatus::Blocked, ..old_settings }); mock.ownable.Ownable_owner.write(OWNER()); - snf::cheat_caller_address_global(OWNER()); + snf::start_cheat_caller_address_global(OWNER()); mock.unblock_token(usdc_address); assert(mock.get_status(usdc_address) == TokenStatus::Unknown, 'Not unblocked'); @@ -102,7 +102,7 @@ fn unblock_token_not_owner() { .write(usdc_address, TokenSettings { token_status: TokenStatus::Blocked, ..old_settings }); mock.ownable.Ownable_owner.write(OWNER()); - snf::cheat_caller_address_global(snf::test_address()); + snf::start_cheat_caller_address_global(snf::test_address()); mock.unblock_token(usdc_address); } @@ -121,7 +121,7 @@ fn unblock_token_not_blocked() { .write(usdc_address, TokenSettings { token_status: TokenStatus::Active, ..old_settings }); mock.ownable.Ownable_owner.write(OWNER()); - snf::cheat_caller_address_global(OWNER()); + snf::start_cheat_caller_address_global(OWNER()); mock.unblock_token(usdc_address); } @@ -141,7 +141,7 @@ fn reactivate_token_ok() { mock.ownable.Ownable_owner.write(OWNER()); - snf::cheat_caller_address_global(OWNER()); + snf::start_cheat_caller_address_global(OWNER()); mock.reactivate_token(usdc_address); assert(mock.get_status(usdc_address) == TokenStatus::Active, 'Did not reactivate'); @@ -161,7 +161,7 @@ fn reactivate_token_not_owner() { usdc_address, TokenSettings { token_status: TokenStatus::Deactivated, ..old_settings } ); - snf::cheat_caller_address_global(snf::test_address()); + snf::start_cheat_caller_address_global(snf::test_address()); mock.reactivate_token(usdc_address); } @@ -179,7 +179,7 @@ fn reactivate_token_not_deactivated() { .write(usdc_address, TokenSettings { token_status: TokenStatus::Blocked, ..old_settings }); mock.ownable.Ownable_owner.write(OWNER()); - snf::cheat_caller_address_global(OWNER()); + snf::start_cheat_caller_address_global(OWNER()); mock.reactivate_token(usdc_address); } diff --git a/tests/constants.cairo b/tests/constants.cairo deleted file mode 100644 index e69de29..0000000 diff --git a/tests/deposit_flow_test.cairo b/tests/deposit_flow_test.cairo index 3b006a0..70654cf 100644 --- a/tests/deposit_flow_test.cairo +++ b/tests/deposit_flow_test.cairo @@ -27,8 +27,8 @@ use openzeppelin::access::ownable::{ use openzeppelin::token::erc20::interface::{IERC20, IERC20Dispatcher, IERC20DispatcherTrait}; use starknet::contract_address::{contract_address_const}; -use super::utils::constants::{OWNER, L3_BRIDGE_ADDRESS, DELAY_TIME}; -use super::utils::setup::{ +use super::constants::{OWNER, L3_BRIDGE_ADDRESS, DELAY_TIME}; +use super::setup::{ deploy_erc20, deploy_token_bridge_with_messaging, deploy_token_bridge, mock_state_testing }; diff --git a/tests/enroll_token_test.cairo b/tests/enroll_token_test.cairo index c79c8a4..ad853ac 100644 --- a/tests/enroll_token_test.cairo +++ b/tests/enroll_token_test.cairo @@ -21,8 +21,8 @@ use openzeppelin::access::ownable::{ interface::{IOwnableTwoStepDispatcher, IOwnableTwoStepDispatcherTrait} }; use starknet::contract_address::{contract_address_const}; -use super::utils::constants::{OWNER, L3_BRIDGE_ADDRESS, USDC_MOCK_ADDRESS, DELAY_TIME}; -use super::utils::setup::{deploy_erc20, deploy_token_bridge, mock_state_testing}; +use super::constants::{OWNER, L3_BRIDGE_ADDRESS, USDC_MOCK_ADDRESS, DELAY_TIME}; +use super::setup::{deploy_erc20, deploy_token_bridge, mock_state_testing}; #[test] diff --git a/tests/utils/setup.cairo b/tests/setup.cairo similarity index 100% rename from tests/utils/setup.cairo rename to tests/setup.cairo diff --git a/tests/utils/constants.cairo b/tests/utils/constants.cairo deleted file mode 100644 index e19ae54..0000000 --- a/tests/utils/constants.cairo +++ /dev/null @@ -1,18 +0,0 @@ -use starknet::{ContractAddress, contract_address_const}; - -pub fn OWNER() -> ContractAddress { - contract_address_const::<'OWNER'>() -} - -pub fn L3_BRIDGE_ADDRESS() -> ContractAddress { - contract_address_const::<'l3_bridge_address'>() -} - -pub fn USDC_MOCK_ADDRESS() -> ContractAddress { - contract_address_const::<'Usdc address'>() -} - - -// 5 days as the delay time (5 * 86400 = 432000) -pub const DELAY_TIME: felt252 = 432000; - From 670f679aa31747c8181ff6cf6748b9702d65c647 Mon Sep 17 00:00:00 2001 From: byteZorvin Date: Mon, 5 Aug 2024 18:09:44 +0530 Subject: [PATCH 27/62] restructure --- src/bridge/tests/token_actions_test.cairo | 19 +++++++++++++++++++ tests/deposit_flow_test.cairo | 4 +--- tests/enroll_token_test.cairo | 20 +------------------- tests/token_actions_test.cairo | 2 +- tests/token_bridge_test.cairo | 2 +- 5 files changed, 23 insertions(+), 24 deletions(-) diff --git a/src/bridge/tests/token_actions_test.cairo b/src/bridge/tests/token_actions_test.cairo index 3c4af39..20c0e50 100644 --- a/src/bridge/tests/token_actions_test.cairo +++ b/src/bridge/tests/token_actions_test.cairo @@ -184,3 +184,22 @@ fn reactivate_token_not_deactivated() { mock.reactivate_token(usdc_address); } +#[test] +#[should_panic(expected: ('Already enrolled',))] +fn enroll_token_blocked() { + let mut mock = mock_state_testing(); + + let usdc_address = USDC_MOCK_ADDRESS(); + + // Setting the token active + let old_settings = mock.token_settings.read(usdc_address); + mock + .token_settings + .write(usdc_address, TokenSettings { token_status: TokenStatus::Blocked, ..old_settings }); + + mock.ownable.Ownable_owner.write(OWNER()); + + snf::start_cheat_caller_address_global(OWNER()); + mock.enroll_token(usdc_address); +} + diff --git a/tests/deposit_flow_test.cairo b/tests/deposit_flow_test.cairo index 70654cf..d30d9e5 100644 --- a/tests/deposit_flow_test.cairo +++ b/tests/deposit_flow_test.cairo @@ -28,9 +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::{ - deploy_erc20, deploy_token_bridge_with_messaging, deploy_token_bridge, mock_state_testing -}; +use super::setup::{deploy_erc20, deploy_token_bridge_with_messaging, deploy_token_bridge}; #[test] diff --git a/tests/enroll_token_test.cairo b/tests/enroll_token_test.cairo index ad853ac..4dedcba 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, mock_state_testing}; +use super::setup::{deploy_erc20, deploy_token_bridge}; #[test] @@ -54,23 +54,5 @@ fn enroll_token_already_enrolled() { token_bridge.enroll_token(usdc_address); } -#[test] -#[should_panic(expected: ('Already enrolled',))] -fn enroll_token_blocked() { - let mut mock = mock_state_testing(); - - let usdc_address = USDC_MOCK_ADDRESS(); - - // Setting the token active - let old_settings = mock.token_settings.read(usdc_address); - mock - .token_settings - .write(usdc_address, TokenSettings { token_status: TokenStatus::Blocked, ..old_settings }); - - mock.ownable.Ownable_owner.write(OWNER()); - - snf::start_cheat_caller_address_global(OWNER()); - mock.enroll_token(usdc_address); -} fn enroll_token_piltover() {} diff --git a/tests/token_actions_test.cairo b/tests/token_actions_test.cairo index 4aeca8a..3507495 100644 --- a/tests/token_actions_test.cairo +++ b/tests/token_actions_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, mock_state_testing}; +use super::setup::{deploy_erc20, deploy_token_bridge}; #[test] diff --git a/tests/token_bridge_test.cairo b/tests/token_bridge_test.cairo index 00d51f6..5e95eab 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, mock_state_testing}; +use super::setup::{deploy_erc20, deploy_token_bridge}; use super::constants::{OWNER, L3_BRIDGE_ADDRESS, USDC_MOCK_ADDRESS, DELAY_TIME}; From 6d6b87cbbd1b2beafda5be02f78473fa7f94ff33 Mon Sep 17 00:00:00 2001 From: byteZorvin Date: Tue, 6 Aug 2024 17:31:41 +0530 Subject: [PATCH 28/62] deposit failing tc --- src/bridge/tests/token_actions_test.cairo | 1 + src/bridge/token_bridge.cairo | 5 +- tests/deposit_flow_test.cairo | 152 +++++++++++++++++++--- 3 files changed, 141 insertions(+), 17 deletions(-) diff --git a/src/bridge/tests/token_actions_test.cairo b/src/bridge/tests/token_actions_test.cairo index 20c0e50..a9d3c3b 100644 --- a/src/bridge/tests/token_actions_test.cairo +++ b/src/bridge/tests/token_actions_test.cairo @@ -1,3 +1,4 @@ +use starknet_bridge::bridge::token_bridge::TokenBridge::TokenBridgeInternal; use starknet_bridge::bridge::token_bridge::TokenBridge::__member_module_token_settings::InternalContractMemberStateTrait; use snforge_std as snf; use starknet::{ContractAddress, storage::StorageMemberAccessTrait}; diff --git a/src/bridge/token_bridge.cairo b/src/bridge/token_bridge.cairo index 19171d0..255ee86 100644 --- a/src/bridge/token_bridge.cairo +++ b/src/bridge/token_bridge.cairo @@ -87,6 +87,7 @@ pub mod TokenBridge { pub const NOT_DEACTIVATED: felt252 = 'Token not deactivated'; pub const NOT_BLOCKED: felt252 = 'Token not blocked'; pub const NOT_UNKNOWN: felt252 = 'Only unknown can be blocked'; + pub const NOT_SERVICING: felt252 = 'Only servicing tokens'; pub const INVALID_RECIPIENT: felt252 = 'Invalid recipient'; pub const MAX_BALANCE_EXCEEDED: felt252 = 'Max Balance Exceeded'; } @@ -286,7 +287,7 @@ pub mod TokenBridge { #[generate_trait] - impl TokenBridgeInternalImpl of TokenBridgeInternal { + pub impl TokenBridgeInternalImpl of TokenBridgeInternal { fn send_deploy_message(self: @ContractState, token: ContractAddress) -> felt252 { assert(self.appchain_bridge().is_non_zero(), Errors::APPCHAIN_BRIDGE_NOT_SET); @@ -343,7 +344,7 @@ pub mod TokenBridge { } fn accept_deposit(self: @ContractState, token: ContractAddress, amount: u256) { - self.is_servicing_token(token); + assert(self.is_servicing_token(token), Errors::NOT_SERVICING); let caller = get_caller_address(); let dispatcher = IERC20Dispatcher { contract_address: token }; diff --git a/tests/deposit_flow_test.cairo b/tests/deposit_flow_test.cairo index d30d9e5..dfcbe2e 100644 --- a/tests/deposit_flow_test.cairo +++ b/tests/deposit_flow_test.cairo @@ -50,12 +50,18 @@ fn deposit_ok() { // Enroll token will emit the event `TokenEnrollmentInitiated` // Getting the deployment_message_hash from the emitted event let (_, event) = spy.get_events().emitted_by(token_bridge.contract_address).events.at(0); - let deployment_message_hash = event.data.at(1); + let mut keys = event.keys.span(); + let mut data = event.data.span(); + let token_enrollment_initiated = starknet::Event::< + TokenBridge::TokenEnrollmentInitiated + >::deserialize(ref keys, ref data) + .unwrap(); - messaging_mock.update_state_for_message(*deployment_message_hash); + messaging_mock.update_state_for_message(token_enrollment_initiated.deployment_message_hash); // Successfully updates the nonce - let nonce: felt252 = messaging.sn_to_appchain_messages(*deployment_message_hash); + let nonce: felt252 = messaging + .sn_to_appchain_messages(token_enrollment_initiated.deployment_message_hash); assert(nonce == 0, 'Nonce no zero'); token_bridge.check_deployment_status(usdc_address); @@ -88,12 +94,18 @@ fn deposit_issufficient_balance() { // Enroll token will emit the event `TokenEnrollmentInitiated` // Getting the deployment_message_hash from the emitted event let (_, event) = spy.get_events().emitted_by(token_bridge.contract_address).events.at(0); - let deployment_message_hash = event.data.at(1); + let mut keys = event.keys.span(); + let mut data = event.data.span(); + let token_enrollment_initiated = starknet::Event::< + TokenBridge::TokenEnrollmentInitiated + >::deserialize(ref keys, ref data) + .unwrap(); - messaging_mock.update_state_for_message(*deployment_message_hash); + messaging_mock.update_state_for_message(token_enrollment_initiated.deployment_message_hash); // Successfully updates the nonce - let nonce: felt252 = messaging.sn_to_appchain_messages(*deployment_message_hash); + let nonce: felt252 = messaging + .sn_to_appchain_messages(token_enrollment_initiated.deployment_message_hash); assert(nonce == 0, 'Nonce no zero'); token_bridge.check_deployment_status(usdc_address); @@ -125,12 +137,18 @@ fn deposit_insufficient_allowance() { // Enroll token will emit the event `TokenEnrollmentInitiated` // Getting the deployment_message_hash from the emitted event let (_, event) = spy.get_events().emitted_by(token_bridge.contract_address).events.at(0); - let deployment_message_hash = event.data.at(1); + let mut keys = event.keys.span(); + let mut data = event.data.span(); + let token_enrollment_initiated = starknet::Event::< + TokenBridge::TokenEnrollmentInitiated + >::deserialize(ref keys, ref data) + .unwrap(); - messaging_mock.update_state_for_message(*deployment_message_hash); + messaging_mock.update_state_for_message(token_enrollment_initiated.deployment_message_hash); // Successfully updates the nonce - let nonce: felt252 = messaging.sn_to_appchain_messages(*deployment_message_hash); + let nonce: felt252 = messaging + .sn_to_appchain_messages(token_enrollment_initiated.deployment_message_hash); assert(nonce == 0, 'Nonce no zero'); token_bridge.check_deployment_status(usdc_address); @@ -160,12 +178,18 @@ fn deposit_with_message_ok() { // Enroll token will emit the event `TokenEnrollmentInitiated` // Getting the deployment_message_hash from the emitted event let (_, event) = spy.get_events().emitted_by(token_bridge.contract_address).events.at(0); - let deployment_message_hash = event.data.at(1); + let mut keys = event.keys.span(); + let mut data = event.data.span(); + let token_enrollment_initiated = starknet::Event::< + TokenBridge::TokenEnrollmentInitiated + >::deserialize(ref keys, ref data) + .unwrap(); - messaging_mock.update_state_for_message(*deployment_message_hash); + messaging_mock.update_state_for_message(token_enrollment_initiated.deployment_message_hash); // Successfully updates the nonce - let nonce: felt252 = messaging.sn_to_appchain_messages(*deployment_message_hash); + let nonce: felt252 = messaging + .sn_to_appchain_messages(token_enrollment_initiated.deployment_message_hash); assert(nonce == 0, 'Nonce no zero'); token_bridge.check_deployment_status(usdc_address); @@ -200,12 +224,18 @@ fn deposit_with_message_empty_message_ok() { // Enroll token will emit the event `TokenEnrollmentInitiated` // Getting the deployment_message_hash from the emitted event let (_, event) = spy.get_events().emitted_by(token_bridge.contract_address).events.at(0); - let deployment_message_hash = event.data.at(1); + let mut keys = event.keys.span(); + let mut data = event.data.span(); + let token_enrollment_initiated = starknet::Event::< + TokenBridge::TokenEnrollmentInitiated + >::deserialize(ref keys, ref data) + .unwrap(); - messaging_mock.update_state_for_message(*deployment_message_hash); + messaging_mock.update_state_for_message(token_enrollment_initiated.deployment_message_hash); // Successfully updates the nonce - let nonce: felt252 = messaging.sn_to_appchain_messages(*deployment_message_hash); + let nonce: felt252 = messaging + .sn_to_appchain_messages(token_enrollment_initiated.deployment_message_hash); assert(nonce == 0, 'Nonce no zero'); token_bridge.check_deployment_status(usdc_address); @@ -221,3 +251,95 @@ fn deposit_with_message_empty_message_ok() { token_bridge.deposit_with_message(usdc_address, 100, snf::test_address(), calldata.span()); } +#[test] +#[should_panic(expected: ('Only servicing tokens',))] +fn deposit_deactivated() { + let (token_bridge, mut spy, messaging_mock) = deploy_token_bridge_with_messaging(); + let usdc_address = deploy_erc20("usdc", "usdc"); + let messaging = IMessagingDispatcher { contract_address: messaging_mock.contract_address }; + let token_bridge_admin = ITokenBridgeAdminDispatcher { + contract_address: token_bridge.contract_address + }; + + assert(token_bridge.get_status(usdc_address) == TokenStatus::Unknown, 'Should be Unknown'); + + token_bridge.enroll_token(usdc_address); + assert(token_bridge.get_status(usdc_address) == TokenStatus::Pending, 'Should be Pending'); + + // Enroll token will emit the event `TokenEnrollmentInitiated` + // Getting the deployment_message_hash from the emitted event + let (_, event) = spy.get_events().emitted_by(token_bridge.contract_address).events.at(0); + let mut keys = event.keys.span(); + let mut data = event.data.span(); + let token_enrollment_initiated = starknet::Event::< + TokenBridge::TokenEnrollmentInitiated + >::deserialize(ref keys, ref data) + .unwrap(); + + messaging_mock.update_state_for_message(token_enrollment_initiated.deployment_message_hash); + + // Successfully updates the nonce + let nonce: felt252 = messaging + .sn_to_appchain_messages(token_enrollment_initiated.deployment_message_hash); + + assert(nonce == 0, 'Nonce no zero'); + + token_bridge.check_deployment_status(usdc_address); + + let final_status = token_bridge.get_status(usdc_address); + assert(final_status == TokenStatus::Active, 'Should be Active'); + + snf::start_cheat_caller_address(token_bridge.contract_address, OWNER()); + token_bridge_admin.deactivate_token(usdc_address); + snf::stop_cheat_caller_address(OWNER()); + + token_bridge.deposit(usdc_address, 100, snf::test_address()); +} + +#[test] +#[should_panic(expected: ('Only servicing tokens',))] +fn deposit_with_message_deactivated() { + let (token_bridge, mut spy, messaging_mock) = deploy_token_bridge_with_messaging(); + let usdc_address = deploy_erc20("usdc", "usdc"); + let messaging = IMessagingDispatcher { contract_address: messaging_mock.contract_address }; + let token_bridge_admin = ITokenBridgeAdminDispatcher { + contract_address: token_bridge.contract_address + }; + + assert(token_bridge.get_status(usdc_address) == TokenStatus::Unknown, 'Should be Unknown'); + + token_bridge.enroll_token(usdc_address); + assert(token_bridge.get_status(usdc_address) == TokenStatus::Pending, 'Should be Pending'); + + // Enroll token will emit the event `TokenEnrollmentInitiated` + // Getting the deployment_message_hash from the emitted event + let (_, event) = spy.get_events().emitted_by(token_bridge.contract_address).events.at(0); + let mut keys = event.keys.span(); + let mut data = event.data.span(); + let token_enrollment_initiated = starknet::Event::< + TokenBridge::TokenEnrollmentInitiated + >::deserialize(ref keys, ref data) + .unwrap(); + + messaging_mock.update_state_for_message(token_enrollment_initiated.deployment_message_hash); + + // Successfully updates the nonce + let nonce: felt252 = messaging + .sn_to_appchain_messages(token_enrollment_initiated.deployment_message_hash); + + assert(nonce == 0, 'Nonce no zero'); + + token_bridge.check_deployment_status(usdc_address); + + let final_status = token_bridge.get_status(usdc_address); + assert(final_status == TokenStatus::Active, 'Should be Active'); + + snf::start_cheat_caller_address(token_bridge.contract_address, OWNER()); + token_bridge_admin.deactivate_token(usdc_address); + snf::stop_cheat_caller_address(OWNER()); + + let mut calldata = ArrayTrait::new(); + 'param1'.serialize(ref calldata); + 'param2'.serialize(ref calldata); + token_bridge.deposit_with_message(usdc_address, 100, snf::test_address(), calldata.span()); +} From 1fd11b9d1d09017137bf6a5c68524aef03e4cbbc Mon Sep 17 00:00:00 2001 From: byteZorvin Date: Wed, 7 Aug 2024 15:52:07 +0530 Subject: [PATCH 29/62] test: happy withdraw test --- src/bridge/tests/utils/message_payloads.cairo | 49 +++++++++ src/bridge/token_bridge.cairo | 4 +- src/constants.cairo | 4 +- src/lib.cairo | 4 + src/mocks/erc20.cairo | 1 + src/mocks/hash.cairo | 68 ++++++++++++ src/mocks/messaging.cairo | 34 ++++++ src/withdrawal_limit/component.cairo | 4 +- ...sit_flow_test.cairo => deposit_test.cairo} | 1 + tests/lib.cairo | 11 +- tests/withdraw_test.cairo | 101 ++++++++++++++++++ 11 files changed, 272 insertions(+), 9 deletions(-) create mode 100644 src/bridge/tests/utils/message_payloads.cairo create mode 100644 src/mocks/hash.cairo rename tests/{deposit_flow_test.cairo => deposit_test.cairo} (99%) create mode 100644 tests/withdraw_test.cairo diff --git a/src/bridge/tests/utils/message_payloads.cairo b/src/bridge/tests/utils/message_payloads.cairo new file mode 100644 index 0000000..0c786f2 --- /dev/null +++ b/src/bridge/tests/utils/message_payloads.cairo @@ -0,0 +1,49 @@ +use starknet::ContractAddress; +use starknet_bridge::constants; + +use openzeppelin::token::erc20::interface::{ + IERC20MetadataDispatcher, IERC20MetadataDispatcherTrait +}; + +pub fn deposit_message_payload( + token: ContractAddress, + amount: u256, + caller: ContractAddress, + appchain_recipient: ContractAddress, + is_with_message: bool, + message: Span +) -> Span { + let mut payload = ArrayTrait::new(); + token.serialize(ref payload); + caller.serialize(ref payload); + appchain_recipient.serialize(ref payload); + amount.serialize(ref payload); + if (is_with_message) { + message.serialize(ref payload); + } + + return payload.span(); +} + +pub fn deployment_message_payload(token: ContractAddress) -> Span { + // Create the calldata that will be sent to on_receive. l2_token, amount and + // depositor are the fields from the deposit context. + let mut calldata = ArrayTrait::new(); + let dispatcher = IERC20MetadataDispatcher { contract_address: token }; + token.serialize(ref calldata); + dispatcher.name().serialize(ref calldata); + dispatcher.symbol().serialize(ref calldata); + dispatcher.decimals().serialize(ref calldata); + calldata.span() +} + +pub fn withdraw_message_payload_from_appchain( + token: ContractAddress, amount: u256, recipient: ContractAddress +) -> Span { + let mut message_payload = ArrayTrait::new(); + constants::TRANSFER_FROM_APPCHAIN.serialize(ref message_payload); + recipient.serialize(ref message_payload); + token.serialize(ref message_payload); + amount.serialize(ref message_payload); + message_payload.span() +} diff --git a/src/bridge/token_bridge.cairo b/src/bridge/token_bridge.cairo index 255ee86..e4da643 100644 --- a/src/bridge/token_bridge.cairo +++ b/src/bridge/token_bridge.cairo @@ -324,7 +324,7 @@ pub mod TokenBridge { token, amount, appchain_recipient, is_with_message, message ) ); - return nonce; + nonce } fn consume_message( @@ -333,7 +333,7 @@ pub mod TokenBridge { let appchain_bridge = self.appchain_bridge(); assert(appchain_bridge.is_non_zero(), Errors::APPCHAIN_BRIDGE_NOT_SET); let mut payload = ArrayTrait::new(); - constants::TRANSFER_FROM_STARKNET.serialize(ref payload); + constants::TRANSFER_FROM_APPCHAIN.serialize(ref payload); recipient.serialize(ref payload); token.serialize(ref payload); amount.serialize(ref payload); diff --git a/src/constants.cairo b/src/constants.cairo index e91f272..60f7449 100644 --- a/src/constants.cairo +++ b/src/constants.cairo @@ -10,7 +10,9 @@ pub const HANDLE_DEPOSIT_WITH_MESSAGE_SELECTOR: felt252 = pub const HANDLE_TOKEN_DEPLOYMENT_SELECTOR: felt252 = 1737780302748468118210503507461757847859991634169290761669750067796330642876; pub const MAX_PENDING_DURATION: felt252 = 5 * 86400; -pub const TRANSFER_FROM_STARKNET: felt252 = 0; + +// Renaming from TRANSFER_FROM_STARKNET to TRANSFER_FROM_APPCHAIN. +pub const TRANSFER_FROM_APPCHAIN: felt252 = 0; // Withdrawal limit pub const SECONDS_IN_DAY: u64 = 86400; diff --git a/src/lib.cairo b/src/lib.cairo index 5ab81a7..a85ec28 100644 --- a/src/lib.cairo +++ b/src/lib.cairo @@ -8,6 +8,9 @@ pub mod bridge { pub mod constants; mod test_bridge; mod token_actions_test; + pub mod utils { + pub mod message_payloads; + } } pub use token_bridge::TokenBridge; @@ -29,5 +32,6 @@ pub mod constants; pub mod mocks { pub mod erc20; pub mod messaging; + pub mod hash; } diff --git a/src/mocks/erc20.cairo b/src/mocks/erc20.cairo index e28d241..399c75f 100644 --- a/src/mocks/erc20.cairo +++ b/src/mocks/erc20.cairo @@ -56,6 +56,7 @@ pub mod ERC20 { self.erc20.mint(recipient, fixed_supply); } + #[generate_trait] #[abi(per_item)] impl IERC20Impl of IERC20Trait { diff --git a/src/mocks/hash.cairo b/src/mocks/hash.cairo new file mode 100644 index 0000000..3f9343e --- /dev/null +++ b/src/mocks/hash.cairo @@ -0,0 +1,68 @@ +//! SPDX-License-Identifier: MIT +//! +//! Hash utilities. +use starknet::ContractAddress; + +/// Computes the hash of a message that is sent from Starknet to the Appchain. +/// +/// +/// +/// # Arguments +/// +/// * `nonce` - Nonce of the message. +/// * `to_address` - Contract address to send the message to on the Appchain. +/// * `selector` - The `l1_handler` function selector of the contract on the Appchain +/// to execute. +/// * `payload` - The message payload. +/// +/// # Returns +/// +/// The hash of the message from Starknet to the Appchain. +pub fn compute_message_hash_sn_to_appc( + nonce: felt252, to_address: ContractAddress, selector: felt252, payload: Span +) -> felt252 { + let mut hash_data = array![nonce, to_address.into(), selector,]; + + let mut i = 0_usize; + loop { + if i == payload.len() { + break; + } + hash_data.append((*payload[i])); + i += 1; + }; + + core::poseidon::poseidon_hash_span(hash_data.span()) +} + +/// Computes the hash of a message that is sent from the Appchain to Starknet. +/// +/// +/// +/// # Arguments +/// +/// * `from_address` - Contract address of the message sender on the Appchain. +/// * `to_address` - Contract address to send the message to on the Appchain. +/// * `payload` - The message payload. +/// +/// # Returns +/// +/// The hash of the message from the Appchain to Starknet. +pub fn compute_message_hash_appc_to_sn( + from_address: ContractAddress, to_address: ContractAddress, payload: Span +) -> felt252 { + let mut hash_data: Array = array![ + from_address.into(), to_address.into(), payload.len().into(), + ]; + + let mut i = 0_usize; + loop { + if i == payload.len() { + break; + } + hash_data.append((*payload[i])); + i += 1; + }; + + core::poseidon::poseidon_hash_span(hash_data.span()) +} diff --git a/src/mocks/messaging.cairo b/src/mocks/messaging.cairo index f084d44..b0c8bfa 100644 --- a/src/mocks/messaging.cairo +++ b/src/mocks/messaging.cairo @@ -1,7 +1,14 @@ use piltover::messaging::output_process::MessageToAppchain; +use starknet::ContractAddress; #[starknet::interface] pub trait IMockMessaging { fn update_state_for_message(ref self: TState, message_hash: felt252); + fn process_last_message_to_appchain( + ref self: TState, to_address: ContractAddress, selector: felt252, payload: Span + ); + fn process_message_to_starknet( + ref self: TState, from: ContractAddress, to_address: ContractAddress, payload: Span + ); } #[starknet::contract] @@ -11,6 +18,8 @@ mod messaging_mock { messaging_cpt::InternalTrait as MessagingInternal, IMessaging }; use starknet::ContractAddress; + use starknet_bridge::mocks::hash; + use starknet_bridge::constants; use super::IMockMessaging; component!(path: messaging_cpt, storage: messaging, event: MessagingEvent); @@ -36,10 +45,35 @@ mod messaging_mock { self.messaging.initialize(cancellation_delay_secs); } + #[abi(embed_v0)] impl MockMessagingImpl of IMockMessaging { fn update_state_for_message(ref self: ContractState, message_hash: felt252) { self.messaging.sn_to_appc_messages.write(message_hash, 0); } + + fn process_last_message_to_appchain( + ref self: ContractState, + to_address: ContractAddress, + selector: felt252, + payload: Span + ) { + let nonce = self.messaging.sn_to_appc_nonce.read(); + let message_hash = hash::compute_message_hash_sn_to_appc( + nonce, to_address, selector, payload + ); + self.update_state_for_message(message_hash); + } + + fn process_message_to_starknet( + ref self: ContractState, + from: ContractAddress, + to_address: ContractAddress, + payload: Span + ) { + let message_hash = hash::compute_message_hash_appc_to_sn(from, to_address, payload); + let ref_count = self.messaging.appc_to_sn_messages.read(message_hash); + self.messaging.appc_to_sn_messages.write(message_hash, ref_count + 1); + } } } diff --git a/src/withdrawal_limit/component.cairo b/src/withdrawal_limit/component.cairo index ebf0ab3..e2f600b 100644 --- a/src/withdrawal_limit/component.cairo +++ b/src/withdrawal_limit/component.cairo @@ -83,7 +83,9 @@ pub mod WithdrawalLimitComponent { token: ContractAddress, amount_to_withdraw: u256 ) { - assert(self.get_contract().is_withdrawal_limit_applied(:token), 'LIMIT_NOT_ENABLED'); + if (!self.get_contract().is_withdrawal_limit_applied(:token)) { + return; + } let remaining_withdrawal_quota = self.get_remaining_withdrawal_quota(token); assert(remaining_withdrawal_quota >= amount_to_withdraw, 'LIMIT_EXCEEDED'); diff --git a/tests/deposit_flow_test.cairo b/tests/deposit_test.cairo similarity index 99% rename from tests/deposit_flow_test.cairo rename to tests/deposit_test.cairo index dfcbe2e..82b2ddc 100644 --- a/tests/deposit_flow_test.cairo +++ b/tests/deposit_test.cairo @@ -69,6 +69,7 @@ fn deposit_ok() { let final_status = token_bridge.get_status(usdc_address); assert(final_status == TokenStatus::Active, 'Should be Active'); + assert(snf::test_address() == starknet::get_contract_address(), 'should be equal'); usdc.approve(token_bridge.contract_address, 100); token_bridge.deposit(usdc_address, 100, snf::test_address()); } diff --git a/tests/lib.cairo b/tests/lib.cairo index ffb95d0..a79f2bd 100644 --- a/tests/lib.cairo +++ b/tests/lib.cairo @@ -1,7 +1,8 @@ -pub mod token_bridge_test; +mod token_bridge_test; use starknet_bridge::bridge::tests::constants; -pub mod setup; -pub mod token_actions_test; -pub mod enroll_token_test; -pub mod deposit_flow_test; +mod setup; +mod token_actions_test; +mod enroll_token_test; +mod deposit_test; +mod withdraw_test; diff --git a/tests/withdraw_test.cairo b/tests/withdraw_test.cairo new file mode 100644 index 0000000..05f3911 --- /dev/null +++ b/tests/withdraw_test.cairo @@ -0,0 +1,101 @@ +use core::num::traits::zero::Zero; +use starknet_bridge::bridge::token_bridge::TokenBridge::__member_module_token_settings::InternalContractMemberStateTrait; +use core::array::ArrayTrait; +use core::serde::Serde; +use core::result::ResultTrait; +use core::option::OptionTrait; +use core::traits::TryInto; +use snforge_std as snf; +use snforge_std::{ + ContractClassTrait, EventSpy, EventSpyTrait, EventsFilterTrait, EventSpyAssertionsTrait +}; +use starknet::{ContractAddress, storage::StorageMemberAccessTrait}; +use starknet_bridge::mocks::{ + messaging::{IMockMessagingDispatcherTrait, IMockMessagingDispatcher}, erc20::ERC20 +}; +use piltover::messaging::{IMessaging, IMessagingDispatcher, IMessagingDispatcherTrait}; +use starknet_bridge::bridge::{ + ITokenBridge, ITokenBridgeAdmin, ITokenBridgeDispatcher, ITokenBridgeDispatcherTrait, + ITokenBridgeAdminDispatcher, ITokenBridgeAdminDispatcherTrait, IWithdrawalLimitStatusDispatcher, + IWithdrawalLimitStatusDispatcherTrait, TokenBridge, TokenBridge::Event, + types::{TokenStatus, TokenSettings} +}; +use openzeppelin::access::ownable::{ + OwnableComponent, OwnableComponent::Event as OwnableEvent, + interface::{IOwnableTwoStepDispatcher, IOwnableTwoStepDispatcherTrait} +}; + +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::{deploy_erc20, deploy_token_bridge_with_messaging, deploy_token_bridge}; +use starknet_bridge::constants; +use starknet_bridge::bridge::tests::utils::message_payloads; + +#[test] +fn withdraw_ok() { + let (token_bridge, mut spy, messaging_mock) = deploy_token_bridge_with_messaging(); + let usdc_address = deploy_erc20("usdc", "usdc"); + let usdc = IERC20Dispatcher { contract_address: usdc_address }; + let messaging = IMessagingDispatcher { contract_address: messaging_mock.contract_address }; + + snf::start_cheat_caller_address(usdc_address, OWNER()); + usdc.transfer(snf::test_address(), 100); + snf::stop_cheat_caller_address(usdc_address); + + assert(token_bridge.get_status(usdc_address) == TokenStatus::Unknown, 'Should be Unknown'); + + token_bridge.enroll_token(usdc_address); + assert(token_bridge.get_status(usdc_address) == TokenStatus::Pending, 'Should be Pending'); + + // Enroll token will emit the event `TokenEnrollmentInitiated` + // Getting the deployment_message_hash from the emitted event + let (_, event) = spy.get_events().emitted_by(token_bridge.contract_address).events.at(0); + let mut keys = event.keys.span(); + let mut data = event.data.span(); + let token_enrollment_initiated = starknet::Event::< + TokenBridge::TokenEnrollmentInitiated + >::deserialize(ref keys, ref data) + .unwrap(); + + messaging_mock.update_state_for_message(token_enrollment_initiated.deployment_message_hash); + + // Successfully updates the nonce + let nonce: felt252 = messaging + .sn_to_appchain_messages(token_enrollment_initiated.deployment_message_hash); + assert(nonce == 0, 'Nonce no zero'); + + token_bridge.check_deployment_status(usdc_address); + + let final_status = token_bridge.get_status(usdc_address); + assert(final_status == TokenStatus::Active, 'Should be Active'); + + let amount = 100; + usdc.approve(token_bridge.contract_address, amount); + token_bridge.deposit(usdc_address, amount, snf::test_address()); + messaging_mock + .process_last_message_to_appchain( + L3_BRIDGE_ADDRESS(), + constants::HANDLE_TOKEN_DEPOSIT_SELECTOR, + message_payloads::deposit_message_payload( + usdc_address, + amount, + snf::test_address(), + snf::test_address(), + false, + array![].span() + ) + ); + + // Register a withdraw message from appchain to piltover + messaging_mock + .process_message_to_starknet( + L3_BRIDGE_ADDRESS(), + token_bridge.contract_address, + message_payloads::withdraw_message_payload_from_appchain( + usdc_address, amount, snf::test_address() + ) + ); + token_bridge.withdraw(usdc_address, 100, snf::test_address()); +} + From f38f87760aa617230f0239eb4794d76508d97004 Mon Sep 17 00:00:00 2001 From: byteZorvin Date: Wed, 7 Aug 2024 15:54:04 +0530 Subject: [PATCH 30/62] chore: ran formatter --- tests/deposit_test.cairo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/deposit_test.cairo b/tests/deposit_test.cairo index 82b2ddc..ca16f60 100644 --- a/tests/deposit_test.cairo +++ b/tests/deposit_test.cairo @@ -69,7 +69,7 @@ fn deposit_ok() { let final_status = token_bridge.get_status(usdc_address); assert(final_status == TokenStatus::Active, 'Should be Active'); - assert(snf::test_address() == starknet::get_contract_address(), 'should be equal'); + assert(snf::test_address() == starknet::get_contract_address(), 'should be equal'); usdc.approve(token_bridge.contract_address, 100); token_bridge.deposit(usdc_address, 100, snf::test_address()); } From 6f187f34f1cb02a6a0001eaec3f73b9fb379c511 Mon Sep 17 00:00:00 2001 From: byteZorvin Date: Wed, 7 Aug 2024 16:51:14 +0530 Subject: [PATCH 31/62] fix settlement of message --- tests/withdraw_test.cairo | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/tests/withdraw_test.cairo b/tests/withdraw_test.cairo index 05f3911..67b362c 100644 --- a/tests/withdraw_test.cairo +++ b/tests/withdraw_test.cairo @@ -34,10 +34,9 @@ use starknet_bridge::bridge::tests::utils::message_payloads; #[test] fn withdraw_ok() { - let (token_bridge, mut spy, messaging_mock) = deploy_token_bridge_with_messaging(); + let (token_bridge, _, messaging_mock) = deploy_token_bridge_with_messaging(); let usdc_address = deploy_erc20("usdc", "usdc"); let usdc = IERC20Dispatcher { contract_address: usdc_address }; - let messaging = IMessagingDispatcher { contract_address: messaging_mock.contract_address }; snf::start_cheat_caller_address(usdc_address, OWNER()); usdc.transfer(snf::test_address(), 100); @@ -48,22 +47,13 @@ fn withdraw_ok() { token_bridge.enroll_token(usdc_address); assert(token_bridge.get_status(usdc_address) == TokenStatus::Pending, 'Should be Pending'); - // Enroll token will emit the event `TokenEnrollmentInitiated` - // Getting the deployment_message_hash from the emitted event - let (_, event) = spy.get_events().emitted_by(token_bridge.contract_address).events.at(0); - let mut keys = event.keys.span(); - let mut data = event.data.span(); - let token_enrollment_initiated = starknet::Event::< - TokenBridge::TokenEnrollmentInitiated - >::deserialize(ref keys, ref data) - .unwrap(); - - messaging_mock.update_state_for_message(token_enrollment_initiated.deployment_message_hash); - - // Successfully updates the nonce - let nonce: felt252 = messaging - .sn_to_appchain_messages(token_enrollment_initiated.deployment_message_hash); - assert(nonce == 0, 'Nonce no zero'); + // Settles the message sent to appchain + messaging_mock + .process_last_message_to_appchain( + L3_BRIDGE_ADDRESS(), + constants::HANDLE_TOKEN_DEPLOYMENT_SELECTOR, + message_payloads::deployment_message_payload(usdc_address) + ); token_bridge.check_deployment_status(usdc_address); From b5eedcaa41f74d7bee80c58652fb3886428a07c7 Mon Sep 17 00:00:00 2001 From: byteZorvin Date: Wed, 7 Aug 2024 17:03:25 +0530 Subject: [PATCH 32/62] change deposit tests to use message_payloads --- tests/deposit_test.cairo | 187 ++++++++++++--------------------------- 1 file changed, 58 insertions(+), 129 deletions(-) diff --git a/tests/deposit_test.cairo b/tests/deposit_test.cairo index ca16f60..cc6c98d 100644 --- a/tests/deposit_test.cairo +++ b/tests/deposit_test.cairo @@ -29,14 +29,15 @@ use openzeppelin::token::erc20::interface::{IERC20, IERC20Dispatcher, IERC20Disp use starknet::contract_address::{contract_address_const}; use super::constants::{OWNER, L3_BRIDGE_ADDRESS, DELAY_TIME}; use super::setup::{deploy_erc20, deploy_token_bridge_with_messaging, deploy_token_bridge}; +use starknet_bridge::constants; +use starknet_bridge::bridge::tests::utils::message_payloads; #[test] fn deposit_ok() { - let (token_bridge, mut spy, messaging_mock) = deploy_token_bridge_with_messaging(); + let (token_bridge, _, messaging_mock) = deploy_token_bridge_with_messaging(); let usdc_address = deploy_erc20("usdc", "usdc"); let usdc = IERC20Dispatcher { contract_address: usdc_address }; - let messaging = IMessagingDispatcher { contract_address: messaging_mock.contract_address }; snf::start_cheat_caller_address(usdc_address, OWNER()); usdc.transfer(snf::test_address(), 100); @@ -47,22 +48,13 @@ fn deposit_ok() { token_bridge.enroll_token(usdc_address); assert(token_bridge.get_status(usdc_address) == TokenStatus::Pending, 'Should be Pending'); - // Enroll token will emit the event `TokenEnrollmentInitiated` - // Getting the deployment_message_hash from the emitted event - let (_, event) = spy.get_events().emitted_by(token_bridge.contract_address).events.at(0); - let mut keys = event.keys.span(); - let mut data = event.data.span(); - let token_enrollment_initiated = starknet::Event::< - TokenBridge::TokenEnrollmentInitiated - >::deserialize(ref keys, ref data) - .unwrap(); - - messaging_mock.update_state_for_message(token_enrollment_initiated.deployment_message_hash); - - // Successfully updates the nonce - let nonce: felt252 = messaging - .sn_to_appchain_messages(token_enrollment_initiated.deployment_message_hash); - assert(nonce == 0, 'Nonce no zero'); + // Settles the message sent to appchain + messaging_mock + .process_last_message_to_appchain( + L3_BRIDGE_ADDRESS(), + constants::HANDLE_TOKEN_DEPLOYMENT_SELECTOR, + message_payloads::deployment_message_payload(usdc_address) + ); token_bridge.check_deployment_status(usdc_address); @@ -78,10 +70,9 @@ fn deposit_ok() { #[test] #[should_panic(expected: ('ERC20: insufficient balance',))] fn deposit_issufficient_balance() { - let (token_bridge, mut spy, messaging_mock) = deploy_token_bridge_with_messaging(); + let (token_bridge, _, messaging_mock) = deploy_token_bridge_with_messaging(); let usdc_address = deploy_erc20("usdc", "usdc"); let usdc = IERC20Dispatcher { contract_address: usdc_address }; - let messaging = IMessagingDispatcher { contract_address: messaging_mock.contract_address }; snf::start_cheat_caller_address(usdc_address, OWNER()); usdc.transfer(snf::test_address(), 100); @@ -92,22 +83,13 @@ fn deposit_issufficient_balance() { token_bridge.enroll_token(usdc_address); assert(token_bridge.get_status(usdc_address) == TokenStatus::Pending, 'Should be Pending'); - // Enroll token will emit the event `TokenEnrollmentInitiated` - // Getting the deployment_message_hash from the emitted event - let (_, event) = spy.get_events().emitted_by(token_bridge.contract_address).events.at(0); - let mut keys = event.keys.span(); - let mut data = event.data.span(); - let token_enrollment_initiated = starknet::Event::< - TokenBridge::TokenEnrollmentInitiated - >::deserialize(ref keys, ref data) - .unwrap(); - - messaging_mock.update_state_for_message(token_enrollment_initiated.deployment_message_hash); - - // Successfully updates the nonce - let nonce: felt252 = messaging - .sn_to_appchain_messages(token_enrollment_initiated.deployment_message_hash); - assert(nonce == 0, 'Nonce no zero'); + // Settles the message sent to appchain + messaging_mock + .process_last_message_to_appchain( + L3_BRIDGE_ADDRESS(), + constants::HANDLE_TOKEN_DEPLOYMENT_SELECTOR, + message_payloads::deployment_message_payload(usdc_address) + ); token_bridge.check_deployment_status(usdc_address); @@ -121,10 +103,9 @@ fn deposit_issufficient_balance() { #[test] #[should_panic(expected: ('ERC20: insufficient allowance',))] fn deposit_insufficient_allowance() { - let (token_bridge, mut spy, messaging_mock) = deploy_token_bridge_with_messaging(); + let (token_bridge, _, messaging_mock) = deploy_token_bridge_with_messaging(); let usdc_address = deploy_erc20("usdc", "usdc"); let usdc = IERC20Dispatcher { contract_address: usdc_address }; - let messaging = IMessagingDispatcher { contract_address: messaging_mock.contract_address }; snf::start_cheat_caller_address(usdc_address, OWNER()); usdc.transfer(snf::test_address(), 100); @@ -135,22 +116,13 @@ fn deposit_insufficient_allowance() { token_bridge.enroll_token(usdc_address); assert(token_bridge.get_status(usdc_address) == TokenStatus::Pending, 'Should be Pending'); - // Enroll token will emit the event `TokenEnrollmentInitiated` - // Getting the deployment_message_hash from the emitted event - let (_, event) = spy.get_events().emitted_by(token_bridge.contract_address).events.at(0); - let mut keys = event.keys.span(); - let mut data = event.data.span(); - let token_enrollment_initiated = starknet::Event::< - TokenBridge::TokenEnrollmentInitiated - >::deserialize(ref keys, ref data) - .unwrap(); - - messaging_mock.update_state_for_message(token_enrollment_initiated.deployment_message_hash); - - // Successfully updates the nonce - let nonce: felt252 = messaging - .sn_to_appchain_messages(token_enrollment_initiated.deployment_message_hash); - assert(nonce == 0, 'Nonce no zero'); + // Settles the message sent to appchain + messaging_mock + .process_last_message_to_appchain( + L3_BRIDGE_ADDRESS(), + constants::HANDLE_TOKEN_DEPLOYMENT_SELECTOR, + message_payloads::deployment_message_payload(usdc_address) + ); token_bridge.check_deployment_status(usdc_address); @@ -162,10 +134,9 @@ fn deposit_insufficient_allowance() { #[test] fn deposit_with_message_ok() { - let (token_bridge, mut spy, messaging_mock) = deploy_token_bridge_with_messaging(); + let (token_bridge, _, messaging_mock) = deploy_token_bridge_with_messaging(); let usdc_address = deploy_erc20("usdc", "usdc"); let usdc = IERC20Dispatcher { contract_address: usdc_address }; - let messaging = IMessagingDispatcher { contract_address: messaging_mock.contract_address }; snf::start_cheat_caller_address(usdc_address, OWNER()); usdc.transfer(snf::test_address(), 100); @@ -176,22 +147,13 @@ fn deposit_with_message_ok() { token_bridge.enroll_token(usdc_address); assert(token_bridge.get_status(usdc_address) == TokenStatus::Pending, 'Should be Pending'); - // Enroll token will emit the event `TokenEnrollmentInitiated` - // Getting the deployment_message_hash from the emitted event - let (_, event) = spy.get_events().emitted_by(token_bridge.contract_address).events.at(0); - let mut keys = event.keys.span(); - let mut data = event.data.span(); - let token_enrollment_initiated = starknet::Event::< - TokenBridge::TokenEnrollmentInitiated - >::deserialize(ref keys, ref data) - .unwrap(); - - messaging_mock.update_state_for_message(token_enrollment_initiated.deployment_message_hash); - - // Successfully updates the nonce - let nonce: felt252 = messaging - .sn_to_appchain_messages(token_enrollment_initiated.deployment_message_hash); - assert(nonce == 0, 'Nonce no zero'); + // Settles the message sent to appchain + messaging_mock + .process_last_message_to_appchain( + L3_BRIDGE_ADDRESS(), + constants::HANDLE_TOKEN_DEPLOYMENT_SELECTOR, + message_payloads::deployment_message_payload(usdc_address) + ); token_bridge.check_deployment_status(usdc_address); @@ -208,10 +170,9 @@ fn deposit_with_message_ok() { #[test] fn deposit_with_message_empty_message_ok() { - let (token_bridge, mut spy, messaging_mock) = deploy_token_bridge_with_messaging(); + let (token_bridge, _, messaging_mock) = deploy_token_bridge_with_messaging(); let usdc_address = deploy_erc20("usdc", "usdc"); let usdc = IERC20Dispatcher { contract_address: usdc_address }; - let messaging = IMessagingDispatcher { contract_address: messaging_mock.contract_address }; snf::start_cheat_caller_address(usdc_address, OWNER()); usdc.transfer(snf::test_address(), 100); @@ -222,22 +183,13 @@ fn deposit_with_message_empty_message_ok() { token_bridge.enroll_token(usdc_address); assert(token_bridge.get_status(usdc_address) == TokenStatus::Pending, 'Should be Pending'); - // Enroll token will emit the event `TokenEnrollmentInitiated` - // Getting the deployment_message_hash from the emitted event - let (_, event) = spy.get_events().emitted_by(token_bridge.contract_address).events.at(0); - let mut keys = event.keys.span(); - let mut data = event.data.span(); - let token_enrollment_initiated = starknet::Event::< - TokenBridge::TokenEnrollmentInitiated - >::deserialize(ref keys, ref data) - .unwrap(); - - messaging_mock.update_state_for_message(token_enrollment_initiated.deployment_message_hash); - - // Successfully updates the nonce - let nonce: felt252 = messaging - .sn_to_appchain_messages(token_enrollment_initiated.deployment_message_hash); - assert(nonce == 0, 'Nonce no zero'); + // Settles the message sent to appchain + messaging_mock + .process_last_message_to_appchain( + L3_BRIDGE_ADDRESS(), + constants::HANDLE_TOKEN_DEPLOYMENT_SELECTOR, + message_payloads::deployment_message_payload(usdc_address) + ); token_bridge.check_deployment_status(usdc_address); @@ -255,9 +207,8 @@ fn deposit_with_message_empty_message_ok() { #[test] #[should_panic(expected: ('Only servicing tokens',))] fn deposit_deactivated() { - let (token_bridge, mut spy, messaging_mock) = deploy_token_bridge_with_messaging(); + let (token_bridge, _, messaging_mock) = deploy_token_bridge_with_messaging(); let usdc_address = deploy_erc20("usdc", "usdc"); - let messaging = IMessagingDispatcher { contract_address: messaging_mock.contract_address }; let token_bridge_admin = ITokenBridgeAdminDispatcher { contract_address: token_bridge.contract_address }; @@ -267,24 +218,13 @@ fn deposit_deactivated() { token_bridge.enroll_token(usdc_address); assert(token_bridge.get_status(usdc_address) == TokenStatus::Pending, 'Should be Pending'); - // Enroll token will emit the event `TokenEnrollmentInitiated` - // Getting the deployment_message_hash from the emitted event - let (_, event) = spy.get_events().emitted_by(token_bridge.contract_address).events.at(0); - let mut keys = event.keys.span(); - let mut data = event.data.span(); - let token_enrollment_initiated = starknet::Event::< - TokenBridge::TokenEnrollmentInitiated - >::deserialize(ref keys, ref data) - .unwrap(); - - messaging_mock.update_state_for_message(token_enrollment_initiated.deployment_message_hash); - - // Successfully updates the nonce - let nonce: felt252 = messaging - .sn_to_appchain_messages(token_enrollment_initiated.deployment_message_hash); - - assert(nonce == 0, 'Nonce no zero'); - + // Settles the message sent to appchain + messaging_mock + .process_last_message_to_appchain( + L3_BRIDGE_ADDRESS(), + constants::HANDLE_TOKEN_DEPLOYMENT_SELECTOR, + message_payloads::deployment_message_payload(usdc_address) + ); token_bridge.check_deployment_status(usdc_address); let final_status = token_bridge.get_status(usdc_address); @@ -300,9 +240,8 @@ fn deposit_deactivated() { #[test] #[should_panic(expected: ('Only servicing tokens',))] fn deposit_with_message_deactivated() { - let (token_bridge, mut spy, messaging_mock) = deploy_token_bridge_with_messaging(); + let (token_bridge, _, messaging_mock) = deploy_token_bridge_with_messaging(); let usdc_address = deploy_erc20("usdc", "usdc"); - let messaging = IMessagingDispatcher { contract_address: messaging_mock.contract_address }; let token_bridge_admin = ITokenBridgeAdminDispatcher { contract_address: token_bridge.contract_address }; @@ -312,23 +251,13 @@ fn deposit_with_message_deactivated() { token_bridge.enroll_token(usdc_address); assert(token_bridge.get_status(usdc_address) == TokenStatus::Pending, 'Should be Pending'); - // Enroll token will emit the event `TokenEnrollmentInitiated` - // Getting the deployment_message_hash from the emitted event - let (_, event) = spy.get_events().emitted_by(token_bridge.contract_address).events.at(0); - let mut keys = event.keys.span(); - let mut data = event.data.span(); - let token_enrollment_initiated = starknet::Event::< - TokenBridge::TokenEnrollmentInitiated - >::deserialize(ref keys, ref data) - .unwrap(); - - messaging_mock.update_state_for_message(token_enrollment_initiated.deployment_message_hash); - - // Successfully updates the nonce - let nonce: felt252 = messaging - .sn_to_appchain_messages(token_enrollment_initiated.deployment_message_hash); - - assert(nonce == 0, 'Nonce no zero'); + // Settles the message sent to appchain + messaging_mock + .process_last_message_to_appchain( + L3_BRIDGE_ADDRESS(), + constants::HANDLE_TOKEN_DEPLOYMENT_SELECTOR, + message_payloads::deployment_message_payload(usdc_address) + ); token_bridge.check_deployment_status(usdc_address); From f0d0caf9d1a31908ee582d23d1c76ae9570e4b5c Mon Sep 17 00:00:00 2001 From: byteZorvin Date: Wed, 7 Aug 2024 17:13:45 +0530 Subject: [PATCH 33/62] add assert --- tests/withdraw_test.cairo | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/withdraw_test.cairo b/tests/withdraw_test.cairo index 67b362c..68546c3 100644 --- a/tests/withdraw_test.cairo +++ b/tests/withdraw_test.cairo @@ -86,6 +86,19 @@ fn withdraw_ok() { usdc_address, amount, snf::test_address() ) ); + + let initial_bridge_balance = usdc.balance_of(token_bridge.contract_address); + let initial_recipient_balance = usdc.balance_of(snf::test_address()); token_bridge.withdraw(usdc_address, 100, snf::test_address()); + + assert( + usdc.balance_of(snf::test_address()) == initial_recipient_balance + amount, + 'Incorrect amount recieved' + ); + + assert( + usdc.balance_of(token_bridge.contract_address) == initial_bridge_balance - amount, + 'Incorrect token amount' + ); } From ad0c07380da0b2e0d352303a74cb945aef3430b8 Mon Sep 17 00:00:00 2001 From: byteZorvin Date: Wed, 7 Aug 2024 18:09:07 +0530 Subject: [PATCH 34/62] failing withdraw tc --- tests/withdraw_test.cairo | 187 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 187 insertions(+) diff --git a/tests/withdraw_test.cairo b/tests/withdraw_test.cairo index 68546c3..45eeab8 100644 --- a/tests/withdraw_test.cairo +++ b/tests/withdraw_test.cairo @@ -102,3 +102,190 @@ fn withdraw_ok() { ); } + +#[test] +#[should_panic(expected: ('Invalid recipient',))] +fn withdraw_zero_recipient() { + let (token_bridge, _, messaging_mock) = deploy_token_bridge_with_messaging(); + let usdc_address = deploy_erc20("usdc", "usdc"); + let usdc = IERC20Dispatcher { contract_address: usdc_address }; + + snf::start_cheat_caller_address(usdc_address, OWNER()); + usdc.transfer(snf::test_address(), 100); + snf::stop_cheat_caller_address(usdc_address); + + assert(token_bridge.get_status(usdc_address) == TokenStatus::Unknown, 'Should be Unknown'); + + token_bridge.enroll_token(usdc_address); + assert(token_bridge.get_status(usdc_address) == TokenStatus::Pending, 'Should be Pending'); + + // Settles the message sent to appchain + messaging_mock + .process_last_message_to_appchain( + L3_BRIDGE_ADDRESS(), + constants::HANDLE_TOKEN_DEPLOYMENT_SELECTOR, + message_payloads::deployment_message_payload(usdc_address) + ); + + token_bridge.check_deployment_status(usdc_address); + + let final_status = token_bridge.get_status(usdc_address); + assert(final_status == TokenStatus::Active, 'Should be Active'); + + let amount = 100; + usdc.approve(token_bridge.contract_address, amount); + token_bridge.deposit(usdc_address, amount, snf::test_address()); + messaging_mock + .process_last_message_to_appchain( + L3_BRIDGE_ADDRESS(), + constants::HANDLE_TOKEN_DEPOSIT_SELECTOR, + message_payloads::deposit_message_payload( + usdc_address, + amount, + snf::test_address(), + snf::test_address(), + false, + array![].span() + ) + ); + + // Register a withdraw message from appchain to piltover + messaging_mock + .process_message_to_starknet( + L3_BRIDGE_ADDRESS(), + token_bridge.contract_address, + message_payloads::withdraw_message_payload_from_appchain( + usdc_address, amount, snf::test_address() + ) + ); + + token_bridge.withdraw(usdc_address, 100, contract_address_const::<0>()); +} + +#[test] +#[should_panic(expected: ('INVALID_MESSAGE_TO_CONSUME',))] +fn withdraw_incorrect_recipient() { + let (token_bridge, _, messaging_mock) = deploy_token_bridge_with_messaging(); + let usdc_address = deploy_erc20("usdc", "usdc"); + let usdc = IERC20Dispatcher { contract_address: usdc_address }; + + snf::start_cheat_caller_address(usdc_address, OWNER()); + usdc.transfer(snf::test_address(), 100); + snf::stop_cheat_caller_address(usdc_address); + + assert(token_bridge.get_status(usdc_address) == TokenStatus::Unknown, 'Should be Unknown'); + + token_bridge.enroll_token(usdc_address); + assert(token_bridge.get_status(usdc_address) == TokenStatus::Pending, 'Should be Pending'); + + // Settles the message sent to appchain + messaging_mock + .process_last_message_to_appchain( + L3_BRIDGE_ADDRESS(), + constants::HANDLE_TOKEN_DEPLOYMENT_SELECTOR, + message_payloads::deployment_message_payload(usdc_address) + ); + + token_bridge.check_deployment_status(usdc_address); + + let final_status = token_bridge.get_status(usdc_address); + assert(final_status == TokenStatus::Active, 'Should be Active'); + + let amount = 100; + usdc.approve(token_bridge.contract_address, amount); + token_bridge.deposit(usdc_address, amount, snf::test_address()); + messaging_mock + .process_last_message_to_appchain( + L3_BRIDGE_ADDRESS(), + constants::HANDLE_TOKEN_DEPOSIT_SELECTOR, + message_payloads::deposit_message_payload( + usdc_address, + amount, + snf::test_address(), + snf::test_address(), + false, + array![].span() + ) + ); + + // Register a withdraw message from appchain to piltover + messaging_mock + .process_message_to_starknet( + L3_BRIDGE_ADDRESS(), + token_bridge.contract_address, + message_payloads::withdraw_message_payload_from_appchain( + usdc_address, amount, snf::test_address() + ) + ); + + token_bridge.withdraw(usdc_address, 100, contract_address_const::<'user2'>()); +} + + +#[test] +#[should_panic(expected: ('LIMIT_EXCEEDED',))] +fn withdraw_limit_reached() { + let (token_bridge, _, messaging_mock) = deploy_token_bridge_with_messaging(); + let usdc_address = deploy_erc20("usdc", "usdc"); + let usdc = IERC20Dispatcher { contract_address: usdc_address }; + let token_bridge_admin = ITokenBridgeAdminDispatcher { + contract_address: token_bridge.contract_address + }; + + snf::start_cheat_caller_address(usdc_address, OWNER()); + usdc.transfer(snf::test_address(), 100); + snf::stop_cheat_caller_address(usdc_address); + + assert(token_bridge.get_status(usdc_address) == TokenStatus::Unknown, 'Should be Unknown'); + + token_bridge.enroll_token(usdc_address); + assert(token_bridge.get_status(usdc_address) == TokenStatus::Pending, 'Should be Pending'); + + // Settles the message sent to appchain + messaging_mock + .process_last_message_to_appchain( + L3_BRIDGE_ADDRESS(), + constants::HANDLE_TOKEN_DEPLOYMENT_SELECTOR, + message_payloads::deployment_message_payload(usdc_address) + ); + + token_bridge.check_deployment_status(usdc_address); + + let final_status = token_bridge.get_status(usdc_address); + assert(final_status == TokenStatus::Active, 'Should be Active'); + + let amount = 100; + usdc.approve(token_bridge.contract_address, amount); + token_bridge.deposit(usdc_address, amount, snf::test_address()); + messaging_mock + .process_last_message_to_appchain( + L3_BRIDGE_ADDRESS(), + constants::HANDLE_TOKEN_DEPOSIT_SELECTOR, + message_payloads::deposit_message_payload( + usdc_address, + amount, + snf::test_address(), + snf::test_address(), + false, + array![].span() + ) + ); + + snf::start_cheat_caller_address(token_bridge.contract_address, OWNER()); + token_bridge_admin.enable_withdrawal_limit(usdc_address); + snf::stop_cheat_caller_address(token_bridge.contract_address); + + let withdraw_amount = 50; + + // Register a withdraw message from appchain to piltover + messaging_mock + .process_message_to_starknet( + L3_BRIDGE_ADDRESS(), + token_bridge.contract_address, + message_payloads::withdraw_message_payload_from_appchain( + usdc_address, withdraw_amount, snf::test_address() + ) + ); + + token_bridge.withdraw(usdc_address, withdraw_amount, snf::test_address()); +} From 65dc25804d4981738a0691f9ddf4c2826a483f5d Mon Sep 17 00:00:00 2001 From: byteZorvin Date: Wed, 7 Aug 2024 18:25:21 +0530 Subject: [PATCH 35/62] cancel request --- tests/deposit_test.cairo | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/tests/deposit_test.cairo b/tests/deposit_test.cairo index cc6c98d..b74bc46 100644 --- a/tests/deposit_test.cairo +++ b/tests/deposit_test.cairo @@ -61,7 +61,6 @@ fn deposit_ok() { let final_status = token_bridge.get_status(usdc_address); assert(final_status == TokenStatus::Active, 'Should be Active'); - assert(snf::test_address() == starknet::get_contract_address(), 'should be equal'); usdc.approve(token_bridge.contract_address, 100); token_bridge.deposit(usdc_address, 100, snf::test_address()); } @@ -273,3 +272,38 @@ fn deposit_with_message_deactivated() { 'param2'.serialize(ref calldata); token_bridge.deposit_with_message(usdc_address, 100, snf::test_address(), calldata.span()); } + + +#[test] +fn deposit_cancel_request_ok() { + let (token_bridge, _, messaging_mock) = deploy_token_bridge_with_messaging(); + let usdc_address = deploy_erc20("usdc", "usdc"); + let usdc = IERC20Dispatcher { contract_address: usdc_address }; + + snf::start_cheat_caller_address(usdc_address, OWNER()); + usdc.transfer(snf::test_address(), 100); + snf::stop_cheat_caller_address(usdc_address); + + assert(token_bridge.get_status(usdc_address) == TokenStatus::Unknown, 'Should be Unknown'); + + token_bridge.enroll_token(usdc_address); + assert(token_bridge.get_status(usdc_address) == TokenStatus::Pending, 'Should be Pending'); + + // Settles the message sent to appchain + messaging_mock + .process_last_message_to_appchain( + L3_BRIDGE_ADDRESS(), + constants::HANDLE_TOKEN_DEPLOYMENT_SELECTOR, + message_payloads::deployment_message_payload(usdc_address) + ); + + token_bridge.check_deployment_status(usdc_address); + + let final_status = token_bridge.get_status(usdc_address); + assert(final_status == TokenStatus::Active, 'Should be Active'); + + usdc.approve(token_bridge.contract_address, 100); + token_bridge.deposit(usdc_address, 100, snf::test_address()); + + token_bridge.deposit_cancel_request(usdc_address, 100, snf::test_address(), 2); +} From bfa4a712d58a760146412fb6e6fdce656778f46b Mon Sep 17 00:00:00 2001 From: byteZorvin Date: Wed, 7 Aug 2024 23:16:16 +0530 Subject: [PATCH 36/62] deposit with message cancels --- src/bridge/token_bridge.cairo | 4 +- tests/deposit_test.cairo | 304 +++++++++++++++++++--------------- 2 files changed, 176 insertions(+), 132 deletions(-) diff --git a/src/bridge/token_bridge.cairo b/src/bridge/token_bridge.cairo index e4da643..2fa72f8 100644 --- a/src/bridge/token_bridge.cairo +++ b/src/bridge/token_bridge.cairo @@ -183,7 +183,7 @@ pub mod TokenBridge { } #[derive(Drop, starknet::Event)] - struct DepositCancelRequest { + pub struct DepositCancelRequest { #[key] pub sender: ContractAddress, #[key] @@ -195,7 +195,7 @@ pub mod TokenBridge { } #[derive(Drop, starknet::Event)] - struct DepositWithMessageCancelRequest { + pub struct DepositWithMessageCancelRequest { #[key] pub sender: ContractAddress, #[key] diff --git a/tests/deposit_test.cairo b/tests/deposit_test.cairo index b74bc46..f043e5f 100644 --- a/tests/deposit_test.cairo +++ b/tests/deposit_test.cairo @@ -33,33 +33,42 @@ use starknet_bridge::constants; use starknet_bridge::bridge::tests::utils::message_payloads; -#[test] -fn deposit_ok() { - let (token_bridge, _, messaging_mock) = deploy_token_bridge_with_messaging(); - let usdc_address = deploy_erc20("usdc", "usdc"); - let usdc = IERC20Dispatcher { contract_address: usdc_address }; - - snf::start_cheat_caller_address(usdc_address, OWNER()); - usdc.transfer(snf::test_address(), 100); - snf::stop_cheat_caller_address(usdc_address); +fn enroll_token_and_settle( + token_bridge: ITokenBridgeDispatcher, + messaging_mock: IMockMessagingDispatcher, + token: ContractAddress +) { + assert(token_bridge.get_status(token) == TokenStatus::Unknown, 'Should be Unknown'); - assert(token_bridge.get_status(usdc_address) == TokenStatus::Unknown, 'Should be Unknown'); - - token_bridge.enroll_token(usdc_address); - assert(token_bridge.get_status(usdc_address) == TokenStatus::Pending, 'Should be Pending'); + token_bridge.enroll_token(token); + assert(token_bridge.get_status(token) == TokenStatus::Pending, 'Should be Pending'); // Settles the message sent to appchain messaging_mock .process_last_message_to_appchain( L3_BRIDGE_ADDRESS(), constants::HANDLE_TOKEN_DEPLOYMENT_SELECTOR, - message_payloads::deployment_message_payload(usdc_address) + message_payloads::deployment_message_payload(token) ); - token_bridge.check_deployment_status(usdc_address); + token_bridge.check_deployment_status(token); - let final_status = token_bridge.get_status(usdc_address); + let final_status = token_bridge.get_status(token); assert(final_status == TokenStatus::Active, 'Should be Active'); +} + + +#[test] +fn deposit_ok() { + let (token_bridge, _, messaging_mock) = deploy_token_bridge_with_messaging(); + let usdc_address = deploy_erc20("usdc", "usdc"); + let usdc = IERC20Dispatcher { contract_address: usdc_address }; + + snf::start_cheat_caller_address(usdc_address, OWNER()); + usdc.transfer(snf::test_address(), 100); + snf::stop_cheat_caller_address(usdc_address); + + enroll_token_and_settle(token_bridge, messaging_mock, usdc_address); usdc.approve(token_bridge.contract_address, 100); token_bridge.deposit(usdc_address, 100, snf::test_address()); @@ -77,23 +86,7 @@ fn deposit_issufficient_balance() { usdc.transfer(snf::test_address(), 100); snf::stop_cheat_caller_address(usdc_address); - assert(token_bridge.get_status(usdc_address) == TokenStatus::Unknown, 'Should be Unknown'); - - token_bridge.enroll_token(usdc_address); - assert(token_bridge.get_status(usdc_address) == TokenStatus::Pending, 'Should be Pending'); - - // Settles the message sent to appchain - messaging_mock - .process_last_message_to_appchain( - L3_BRIDGE_ADDRESS(), - constants::HANDLE_TOKEN_DEPLOYMENT_SELECTOR, - message_payloads::deployment_message_payload(usdc_address) - ); - - token_bridge.check_deployment_status(usdc_address); - - let final_status = token_bridge.get_status(usdc_address); - assert(final_status == TokenStatus::Active, 'Should be Active'); + enroll_token_and_settle(token_bridge, messaging_mock, usdc_address); usdc.approve(token_bridge.contract_address, 200); token_bridge.deposit(usdc_address, 200, snf::test_address()); @@ -110,23 +103,7 @@ fn deposit_insufficient_allowance() { usdc.transfer(snf::test_address(), 100); snf::stop_cheat_caller_address(usdc_address); - assert(token_bridge.get_status(usdc_address) == TokenStatus::Unknown, 'Should be Unknown'); - - token_bridge.enroll_token(usdc_address); - assert(token_bridge.get_status(usdc_address) == TokenStatus::Pending, 'Should be Pending'); - - // Settles the message sent to appchain - messaging_mock - .process_last_message_to_appchain( - L3_BRIDGE_ADDRESS(), - constants::HANDLE_TOKEN_DEPLOYMENT_SELECTOR, - message_payloads::deployment_message_payload(usdc_address) - ); - - token_bridge.check_deployment_status(usdc_address); - - let final_status = token_bridge.get_status(usdc_address); - assert(final_status == TokenStatus::Active, 'Should be Active'); + enroll_token_and_settle(token_bridge, messaging_mock, usdc_address); token_bridge.deposit(usdc_address, 100, snf::test_address()); } @@ -141,23 +118,7 @@ fn deposit_with_message_ok() { usdc.transfer(snf::test_address(), 100); snf::stop_cheat_caller_address(usdc_address); - assert(token_bridge.get_status(usdc_address) == TokenStatus::Unknown, 'Should be Unknown'); - - token_bridge.enroll_token(usdc_address); - assert(token_bridge.get_status(usdc_address) == TokenStatus::Pending, 'Should be Pending'); - - // Settles the message sent to appchain - messaging_mock - .process_last_message_to_appchain( - L3_BRIDGE_ADDRESS(), - constants::HANDLE_TOKEN_DEPLOYMENT_SELECTOR, - message_payloads::deployment_message_payload(usdc_address) - ); - - token_bridge.check_deployment_status(usdc_address); - - let final_status = token_bridge.get_status(usdc_address); - assert(final_status == TokenStatus::Active, 'Should be Active'); + enroll_token_and_settle(token_bridge, messaging_mock, usdc_address); let mut calldata = ArrayTrait::new(); 'param1'.serialize(ref calldata); @@ -177,23 +138,7 @@ fn deposit_with_message_empty_message_ok() { usdc.transfer(snf::test_address(), 100); snf::stop_cheat_caller_address(usdc_address); - assert(token_bridge.get_status(usdc_address) == TokenStatus::Unknown, 'Should be Unknown'); - - token_bridge.enroll_token(usdc_address); - assert(token_bridge.get_status(usdc_address) == TokenStatus::Pending, 'Should be Pending'); - - // Settles the message sent to appchain - messaging_mock - .process_last_message_to_appchain( - L3_BRIDGE_ADDRESS(), - constants::HANDLE_TOKEN_DEPLOYMENT_SELECTOR, - message_payloads::deployment_message_payload(usdc_address) - ); - - token_bridge.check_deployment_status(usdc_address); - - let final_status = token_bridge.get_status(usdc_address); - assert(final_status == TokenStatus::Active, 'Should be Active'); + enroll_token_and_settle(token_bridge, messaging_mock, usdc_address); let mut calldata = ArrayTrait::new(); 'param1'.serialize(ref calldata); @@ -212,22 +157,7 @@ fn deposit_deactivated() { contract_address: token_bridge.contract_address }; - assert(token_bridge.get_status(usdc_address) == TokenStatus::Unknown, 'Should be Unknown'); - - token_bridge.enroll_token(usdc_address); - assert(token_bridge.get_status(usdc_address) == TokenStatus::Pending, 'Should be Pending'); - - // Settles the message sent to appchain - messaging_mock - .process_last_message_to_appchain( - L3_BRIDGE_ADDRESS(), - constants::HANDLE_TOKEN_DEPLOYMENT_SELECTOR, - message_payloads::deployment_message_payload(usdc_address) - ); - token_bridge.check_deployment_status(usdc_address); - - let final_status = token_bridge.get_status(usdc_address); - assert(final_status == TokenStatus::Active, 'Should be Active'); + enroll_token_and_settle(token_bridge, messaging_mock, usdc_address); snf::start_cheat_caller_address(token_bridge.contract_address, OWNER()); token_bridge_admin.deactivate_token(usdc_address); @@ -245,23 +175,7 @@ fn deposit_with_message_deactivated() { contract_address: token_bridge.contract_address }; - assert(token_bridge.get_status(usdc_address) == TokenStatus::Unknown, 'Should be Unknown'); - - token_bridge.enroll_token(usdc_address); - assert(token_bridge.get_status(usdc_address) == TokenStatus::Pending, 'Should be Pending'); - - // Settles the message sent to appchain - messaging_mock - .process_last_message_to_appchain( - L3_BRIDGE_ADDRESS(), - constants::HANDLE_TOKEN_DEPLOYMENT_SELECTOR, - message_payloads::deployment_message_payload(usdc_address) - ); - - token_bridge.check_deployment_status(usdc_address); - - let final_status = token_bridge.get_status(usdc_address); - assert(final_status == TokenStatus::Active, 'Should be Active'); + enroll_token_and_settle(token_bridge, messaging_mock, usdc_address); snf::start_cheat_caller_address(token_bridge.contract_address, OWNER()); token_bridge_admin.deactivate_token(usdc_address); @@ -276,7 +190,7 @@ fn deposit_with_message_deactivated() { #[test] fn deposit_cancel_request_ok() { - let (token_bridge, _, messaging_mock) = deploy_token_bridge_with_messaging(); + let (token_bridge, mut spy, messaging_mock) = deploy_token_bridge_with_messaging(); let usdc_address = deploy_erc20("usdc", "usdc"); let usdc = IERC20Dispatcher { contract_address: usdc_address }; @@ -284,26 +198,156 @@ fn deposit_cancel_request_ok() { usdc.transfer(snf::test_address(), 100); snf::stop_cheat_caller_address(usdc_address); - assert(token_bridge.get_status(usdc_address) == TokenStatus::Unknown, 'Should be Unknown'); + enroll_token_and_settle(token_bridge, messaging_mock, usdc_address); - token_bridge.enroll_token(usdc_address); - assert(token_bridge.get_status(usdc_address) == TokenStatus::Pending, 'Should be Pending'); + usdc.approve(token_bridge.contract_address, 100); + token_bridge.deposit(usdc_address, 100, snf::test_address()); - // Settles the message sent to appchain - messaging_mock - .process_last_message_to_appchain( - L3_BRIDGE_ADDRESS(), - constants::HANDLE_TOKEN_DEPLOYMENT_SELECTOR, - message_payloads::deployment_message_payload(usdc_address) + token_bridge.deposit_cancel_request(usdc_address, 100, snf::test_address(), 2); + + let expected_deposit_cancel = TokenBridge::DepositCancelRequest { + sender: snf::test_address(), + token: usdc_address, + amount: 100, + appchain_recipient: snf::test_address(), + nonce: 2 + }; + + spy + .assert_emitted( + @array![ + ( + token_bridge.contract_address, + Event::DepostiCancelRequest(expected_deposit_cancel) + ) + ] ); +} - token_bridge.check_deployment_status(usdc_address); - let final_status = token_bridge.get_status(usdc_address); - assert(final_status == TokenStatus::Active, 'Should be Active'); +#[test] +#[should_panic(expected: ('NO_MESSAGE_TO_CANCEL',))] +fn deposit_cancel_request_no_deposit() { + let (token_bridge, _, messaging_mock) = deploy_token_bridge_with_messaging(); + let usdc_address = deploy_erc20("usdc", "usdc"); + + enroll_token_and_settle(token_bridge, messaging_mock, usdc_address); + + token_bridge.deposit_cancel_request(usdc_address, 100, snf::test_address(), 2); +} + +#[test] +#[should_panic(expected: ('NO_MESSAGE_TO_CANCEL',))] +fn deposit_cancel_request_different_user() { + let (token_bridge, _, messaging_mock) = deploy_token_bridge_with_messaging(); + let usdc_address = deploy_erc20("usdc", "usdc"); + let usdc = IERC20Dispatcher { contract_address: usdc_address }; + + snf::start_cheat_caller_address(usdc_address, OWNER()); + usdc.transfer(snf::test_address(), 100); + snf::stop_cheat_caller_address(usdc_address); + + enroll_token_and_settle(token_bridge, messaging_mock, usdc_address); usdc.approve(token_bridge.contract_address, 100); token_bridge.deposit(usdc_address, 100, snf::test_address()); + snf::start_cheat_caller_address( + token_bridge.contract_address, contract_address_const::<'user2'>() + ); token_bridge.deposit_cancel_request(usdc_address, 100, snf::test_address(), 2); } + + +#[test] +fn deposit_with_message_cancel_request_ok() { + let (token_bridge, mut spy, messaging_mock) = deploy_token_bridge_with_messaging(); + let usdc_address = deploy_erc20("usdc", "usdc"); + let usdc = IERC20Dispatcher { contract_address: usdc_address }; + + snf::start_cheat_caller_address(usdc_address, OWNER()); + usdc.transfer(snf::test_address(), 100); + snf::stop_cheat_caller_address(usdc_address); + + enroll_token_and_settle(token_bridge, messaging_mock, usdc_address); + + let mut calldata = ArrayTrait::new(); + 'param1'.serialize(ref calldata); + 'param2'.serialize(ref calldata); + + usdc.approve(token_bridge.contract_address, 100); + token_bridge.deposit_with_message(usdc_address, 100, snf::test_address(), calldata.span()); + + token_bridge + .deposit_with_message_cancel_request( + usdc_address, 100, snf::test_address(), calldata.span(), 2 + ); + + let expected_deposit_cancel = TokenBridge::DepositWithMessageCancelRequest { + sender: snf::test_address(), + token: usdc_address, + amount: 100, + appchain_recipient: snf::test_address(), + message: calldata.span(), + nonce: 2 + }; + + spy + .assert_emitted( + @array![ + ( + token_bridge.contract_address, + Event::DepositWithMessageCancelRequest(expected_deposit_cancel) + ) + ] + ); +} + + +#[test] +#[should_panic(expected: ('NO_MESSAGE_TO_CANCEL',))] +fn deposit_with_message_cancel_request_no_deposit() { + let (token_bridge, _, messaging_mock) = deploy_token_bridge_with_messaging(); + let usdc_address = deploy_erc20("usdc", "usdc"); + + enroll_token_and_settle(token_bridge, messaging_mock, usdc_address); + + let mut calldata = ArrayTrait::new(); + 'param1'.serialize(ref calldata); + 'param2'.serialize(ref calldata); + + token_bridge + .deposit_with_message_cancel_request( + usdc_address, 100, snf::test_address(), calldata.span(), 2 + ); +} + +#[test] +#[should_panic(expected: ('NO_MESSAGE_TO_CANCEL',))] +fn deposit_with_message_cancel_request_different_user() { + let (token_bridge, _, messaging_mock) = deploy_token_bridge_with_messaging(); + let usdc_address = deploy_erc20("usdc", "usdc"); + let usdc = IERC20Dispatcher { contract_address: usdc_address }; + + snf::start_cheat_caller_address(usdc_address, OWNER()); + usdc.transfer(snf::test_address(), 100); + snf::stop_cheat_caller_address(usdc_address); + + enroll_token_and_settle(token_bridge, messaging_mock, usdc_address); + + let mut calldata = ArrayTrait::new(); + 'param1'.serialize(ref calldata); + 'param2'.serialize(ref calldata); + + usdc.approve(token_bridge.contract_address, 100); + token_bridge.deposit_with_message(usdc_address, 100, snf::test_address(), calldata.span()); + + snf::start_cheat_caller_address( + token_bridge.contract_address, contract_address_const::<'user2'>() + ); + token_bridge + .deposit_with_message_cancel_request( + usdc_address, 100, snf::test_address(), calldata.span(), 2 + ); +} + From d130cacb444a816f80149cefb7fcaf02b89f0b90 Mon Sep 17 00:00:00 2001 From: Mehul Chauhan Date: Thu, 8 Aug 2024 16:45:39 +0530 Subject: [PATCH 37/62] Update tests/deposit_test.cairo Co-authored-by: Apoorv Sadana <95699312+apoorvsadana@users.noreply.github.com> --- tests/deposit_test.cairo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/deposit_test.cairo b/tests/deposit_test.cairo index f043e5f..2b1b033 100644 --- a/tests/deposit_test.cairo +++ b/tests/deposit_test.cairo @@ -77,7 +77,7 @@ fn deposit_ok() { #[test] #[should_panic(expected: ('ERC20: insufficient balance',))] -fn deposit_issufficient_balance() { +fn deposit_insufficient_balance() { let (token_bridge, _, messaging_mock) = deploy_token_bridge_with_messaging(); let usdc_address = deploy_erc20("usdc", "usdc"); let usdc = IERC20Dispatcher { contract_address: usdc_address }; From eb0280fb1b0e6f7df969f28302e1a0ea8cb2f30a Mon Sep 17 00:00:00 2001 From: byteZorvin Date: Fri, 9 Aug 2024 09:49:45 +0530 Subject: [PATCH 38/62] resolved comments --- Scarb.toml | 1 - src/bridge/tests/token_actions_test.cairo | 10 +- src/bridge/token_bridge.cairo | 14 +-- tests/deposit_test.cairo | 140 +++++++++++----------- tests/enroll_token_test.cairo | 25 +++- tests/setup.cairo | 36 ++++++ tests/withdraw_test.cairo | 118 +----------------- 7 files changed, 145 insertions(+), 199 deletions(-) diff --git a/Scarb.toml b/Scarb.toml index ef9a4d6..34967a1 100644 --- a/Scarb.toml +++ b/Scarb.toml @@ -15,7 +15,6 @@ snforge_std = { git = "https://github.com/foundry-rs/starknet-foundry", tag = "v [[target.starknet-contract]] casm = true -allowed-libfuncs-list.name = "experimental" [scripts] diff --git a/src/bridge/tests/token_actions_test.cairo b/src/bridge/tests/token_actions_test.cairo index a9d3c3b..0f0ded4 100644 --- a/src/bridge/tests/token_actions_test.cairo +++ b/src/bridge/tests/token_actions_test.cairo @@ -186,7 +186,7 @@ fn reactivate_token_not_deactivated() { } #[test] -#[should_panic(expected: ('Already enrolled',))] +#[should_panic(expected: ('Incorrect token status',))] fn enroll_token_blocked() { let mut mock = mock_state_testing(); @@ -204,3 +204,11 @@ fn enroll_token_blocked() { mock.enroll_token(usdc_address); } +#[test] +#[should_panic(expected: ('Invalid recipient',))] +fn consume_message_zero_recipient() { + let mut mock = mock_state_testing(); + let usdc_address = USDC_MOCK_ADDRESS(); + + mock.consume_message(usdc_address, 100, contract_address_const::<0>()); +} diff --git a/src/bridge/token_bridge.cairo b/src/bridge/token_bridge.cairo index 2fa72f8..76160eb 100644 --- a/src/bridge/token_bridge.cairo +++ b/src/bridge/token_bridge.cairo @@ -81,7 +81,7 @@ pub mod TokenBridge { pub mod Errors { pub const APPCHAIN_BRIDGE_NOT_SET: felt252 = 'L3 bridge not set'; pub const ZERO_DEPOSIT: felt252 = 'Zero amount'; - pub const ALREADY_ENROLLED: felt252 = 'Already enrolled'; + pub const ALREADY_ENROLLED: felt252 = 'Incorrect token status'; pub const DEPLOYMENT_MESSAGE_DOES_NOT_EXIST: felt252 = 'Deployment message inexistent'; pub const NOT_ACTIVE: felt252 = 'Token not active'; pub const NOT_DEACTIVATED: felt252 = 'Token not deactivated'; @@ -544,17 +544,7 @@ pub mod TokenBridge { ); let caller = get_caller_address(); - self - .emit( - DepositWithMessage { - sender: caller, - token, - amount, - appchain_recipient, - message: no_message, - nonce, - } - ); + self.emit(Deposit { sender: caller, token, amount, appchain_recipient, nonce }); self.check_deployment_status(token); self.reentrancy_guard.end(); diff --git a/tests/deposit_test.cairo b/tests/deposit_test.cairo index f043e5f..3d336da 100644 --- a/tests/deposit_test.cairo +++ b/tests/deposit_test.cairo @@ -28,50 +28,37 @@ 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::{deploy_erc20, deploy_token_bridge_with_messaging, deploy_token_bridge}; -use starknet_bridge::constants; -use starknet_bridge::bridge::tests::utils::message_payloads; - - -fn enroll_token_and_settle( - token_bridge: ITokenBridgeDispatcher, - messaging_mock: IMockMessagingDispatcher, - token: ContractAddress -) { - assert(token_bridge.get_status(token) == TokenStatus::Unknown, 'Should be Unknown'); - - token_bridge.enroll_token(token); - assert(token_bridge.get_status(token) == TokenStatus::Pending, 'Should be Pending'); - - // Settles the message sent to appchain - messaging_mock - .process_last_message_to_appchain( - L3_BRIDGE_ADDRESS(), - constants::HANDLE_TOKEN_DEPLOYMENT_SELECTOR, - message_payloads::deployment_message_payload(token) - ); - - token_bridge.check_deployment_status(token); - - let final_status = token_bridge.get_status(token); - assert(final_status == TokenStatus::Active, 'Should be Active'); -} +use super::setup::{ + deploy_erc20, deploy_token_bridge_with_messaging, deploy_token_bridge, enroll_token_and_settle +}; #[test] fn deposit_ok() { - let (token_bridge, _, messaging_mock) = deploy_token_bridge_with_messaging(); + let (token_bridge, mut spy, messaging_mock) = deploy_token_bridge_with_messaging(); let usdc_address = deploy_erc20("usdc", "usdc"); let usdc = IERC20Dispatcher { contract_address: usdc_address }; - snf::start_cheat_caller_address(usdc_address, OWNER()); - usdc.transfer(snf::test_address(), 100); - snf::stop_cheat_caller_address(usdc_address); - enroll_token_and_settle(token_bridge, messaging_mock, usdc_address); + let initial_bridge_balance = usdc.balance_of(token_bridge.contract_address); usdc.approve(token_bridge.contract_address, 100); token_bridge.deposit(usdc_address, 100, snf::test_address()); + + assert( + usdc.balance_of(token_bridge.contract_address) == initial_bridge_balance + 100, + 'incorrect amount recieved' + ); + + let expected_deposit = TokenBridge::Deposit { + sender: snf::test_address(), + token: usdc_address, + amount: 100, + appchain_recipient: snf::test_address(), + nonce: 2 + }; + + spy.assert_emitted(@array![(token_bridge.contract_address, Event::Deposit(expected_deposit))]); } @@ -82,10 +69,6 @@ fn deposit_issufficient_balance() { let usdc_address = deploy_erc20("usdc", "usdc"); let usdc = IERC20Dispatcher { contract_address: usdc_address }; - snf::start_cheat_caller_address(usdc_address, OWNER()); - usdc.transfer(snf::test_address(), 100); - snf::stop_cheat_caller_address(usdc_address); - enroll_token_and_settle(token_bridge, messaging_mock, usdc_address); usdc.approve(token_bridge.contract_address, 200); @@ -97,11 +80,6 @@ fn deposit_issufficient_balance() { fn deposit_insufficient_allowance() { let (token_bridge, _, messaging_mock) = deploy_token_bridge_with_messaging(); let usdc_address = deploy_erc20("usdc", "usdc"); - let usdc = IERC20Dispatcher { contract_address: usdc_address }; - - snf::start_cheat_caller_address(usdc_address, OWNER()); - usdc.transfer(snf::test_address(), 100); - snf::stop_cheat_caller_address(usdc_address); enroll_token_and_settle(token_bridge, messaging_mock, usdc_address); @@ -110,42 +88,84 @@ fn deposit_insufficient_allowance() { #[test] fn deposit_with_message_ok() { - let (token_bridge, _, messaging_mock) = deploy_token_bridge_with_messaging(); + let (token_bridge, mut spy, messaging_mock) = deploy_token_bridge_with_messaging(); let usdc_address = deploy_erc20("usdc", "usdc"); let usdc = IERC20Dispatcher { contract_address: usdc_address }; - snf::start_cheat_caller_address(usdc_address, OWNER()); - usdc.transfer(snf::test_address(), 100); - snf::stop_cheat_caller_address(usdc_address); - enroll_token_and_settle(token_bridge, messaging_mock, usdc_address); let mut calldata = ArrayTrait::new(); 'param1'.serialize(ref calldata); 'param2'.serialize(ref calldata); + let initial_bridge_balance = usdc.balance_of(token_bridge.contract_address); usdc.approve(token_bridge.contract_address, 100); token_bridge.deposit_with_message(usdc_address, 100, snf::test_address(), calldata.span()); + + assert( + usdc.balance_of(token_bridge.contract_address) == initial_bridge_balance + 100, + 'incorrect amount recieved' + ); + + let expected_deposit_with_message = TokenBridge::DepositWithMessage { + sender: snf::test_address(), + token: usdc_address, + amount: 100, + appchain_recipient: snf::test_address(), + message: calldata.span(), + nonce: 2 + }; + + spy + .assert_emitted( + @array![ + ( + token_bridge.contract_address, + Event::DepositWithMessage(expected_deposit_with_message) + ) + ] + ); } #[test] fn deposit_with_message_empty_message_ok() { - let (token_bridge, _, messaging_mock) = deploy_token_bridge_with_messaging(); + let (token_bridge, mut spy, messaging_mock) = deploy_token_bridge_with_messaging(); let usdc_address = deploy_erc20("usdc", "usdc"); let usdc = IERC20Dispatcher { contract_address: usdc_address }; - snf::start_cheat_caller_address(usdc_address, OWNER()); - usdc.transfer(snf::test_address(), 100); - snf::stop_cheat_caller_address(usdc_address); - enroll_token_and_settle(token_bridge, messaging_mock, usdc_address); let mut calldata = ArrayTrait::new(); 'param1'.serialize(ref calldata); 'param2'.serialize(ref calldata); + let initial_bridge_balance = usdc.balance_of(token_bridge.contract_address); usdc.approve(token_bridge.contract_address, 100); token_bridge.deposit_with_message(usdc_address, 100, snf::test_address(), calldata.span()); + + assert( + usdc.balance_of(token_bridge.contract_address) == initial_bridge_balance + 100, + 'incorrect amount recieved' + ); + + let expected_deposit_with_message = TokenBridge::DepositWithMessage { + sender: snf::test_address(), + token: usdc_address, + amount: 100, + appchain_recipient: snf::test_address(), + message: calldata.span(), + nonce: 2 + }; + + spy + .assert_emitted( + @array![ + ( + token_bridge.contract_address, + Event::DepositWithMessage(expected_deposit_with_message) + ) + ] + ); } #[test] @@ -194,10 +214,6 @@ fn deposit_cancel_request_ok() { let usdc_address = deploy_erc20("usdc", "usdc"); let usdc = IERC20Dispatcher { contract_address: usdc_address }; - snf::start_cheat_caller_address(usdc_address, OWNER()); - usdc.transfer(snf::test_address(), 100); - snf::stop_cheat_caller_address(usdc_address); - enroll_token_and_settle(token_bridge, messaging_mock, usdc_address); usdc.approve(token_bridge.contract_address, 100); @@ -243,10 +259,6 @@ fn deposit_cancel_request_different_user() { let usdc_address = deploy_erc20("usdc", "usdc"); let usdc = IERC20Dispatcher { contract_address: usdc_address }; - snf::start_cheat_caller_address(usdc_address, OWNER()); - usdc.transfer(snf::test_address(), 100); - snf::stop_cheat_caller_address(usdc_address); - enroll_token_and_settle(token_bridge, messaging_mock, usdc_address); usdc.approve(token_bridge.contract_address, 100); @@ -265,10 +277,6 @@ fn deposit_with_message_cancel_request_ok() { let usdc_address = deploy_erc20("usdc", "usdc"); let usdc = IERC20Dispatcher { contract_address: usdc_address }; - snf::start_cheat_caller_address(usdc_address, OWNER()); - usdc.transfer(snf::test_address(), 100); - snf::stop_cheat_caller_address(usdc_address); - enroll_token_and_settle(token_bridge, messaging_mock, usdc_address); let mut calldata = ArrayTrait::new(); @@ -329,10 +337,6 @@ fn deposit_with_message_cancel_request_different_user() { let usdc_address = deploy_erc20("usdc", "usdc"); let usdc = IERC20Dispatcher { contract_address: usdc_address }; - snf::start_cheat_caller_address(usdc_address, OWNER()); - usdc.transfer(snf::test_address(), 100); - snf::stop_cheat_caller_address(usdc_address); - enroll_token_and_settle(token_bridge, messaging_mock, usdc_address); let mut calldata = ArrayTrait::new(); diff --git a/tests/enroll_token_test.cairo b/tests/enroll_token_test.cairo index 4dedcba..90b7a06 100644 --- a/tests/enroll_token_test.cairo +++ b/tests/enroll_token_test.cairo @@ -8,7 +8,7 @@ use snforge_std as snf; use snforge_std::{ContractClassTrait, EventSpy, EventSpyTrait, EventSpyAssertionsTrait}; use starknet::{ContractAddress, storage::StorageMemberAccessTrait}; use starknet_bridge::mocks::{ - messaging::{IMockMessagingDispatcherTrait, IMockMessagingDispatcher}, erc20::ERC20 + messaging::{IMockMessagingDispatcherTrait, IMockMessagingDispatcher}, erc20::ERC20, hash }; use starknet_bridge::bridge::{ ITokenBridge, ITokenBridgeAdmin, ITokenBridgeDispatcher, ITokenBridgeDispatcherTrait, @@ -23,11 +23,13 @@ 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::message_payloads; +use starknet_bridge::constants; #[test] fn enroll_token_ok() { - let (token_bridge, _) = deploy_token_bridge(); + let (token_bridge, mut spy) = deploy_token_bridge(); let usdc_address = deploy_erc20("USDC", "USDC"); @@ -36,12 +38,27 @@ fn enroll_token_ok() { token_bridge.enroll_token(usdc_address); + let payload = message_payloads::deployment_message_payload(usdc_address); + let message_hash = hash::compute_message_hash_sn_to_appc( + 1, L3_BRIDGE_ADDRESS(), constants::HANDLE_TOKEN_DEPLOYMENT_SELECTOR, payload + ); + + let expected_event = TokenBridge::TokenEnrollmentInitiated { + token: usdc_address, deployment_message_hash: message_hash + }; + let new_status = token_bridge.get_status(usdc_address); assert(new_status == TokenStatus::Pending, 'Should be pending now'); + spy + .assert_emitted( + @array![ + (token_bridge.contract_address, Event::TokenEnrollmentInitiated(expected_event)) + ] + ); } #[test] -#[should_panic(expected: ('Already enrolled',))] +#[should_panic(expected: ('Incorrect token status',))] fn enroll_token_already_enrolled() { let (token_bridge, _) = deploy_token_bridge(); @@ -54,5 +71,3 @@ fn enroll_token_already_enrolled() { token_bridge.enroll_token(usdc_address); } - -fn enroll_token_piltover() {} diff --git a/tests/setup.cairo b/tests/setup.cairo index 4028fb0..8ccaede 100644 --- a/tests/setup.cairo +++ b/tests/setup.cairo @@ -16,8 +16,12 @@ use openzeppelin::access::ownable::{ OwnableComponent, OwnableComponent::Event as OwnableEvent, interface::{IOwnableTwoStepDispatcher, IOwnableTwoStepDispatcherTrait} }; +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::constants; +use starknet_bridge::bridge::tests::utils::message_payloads; + pub fn deploy_erc20(name: ByteArray, symbol: ByteArray) -> ContractAddress { let erc20_class_hash = snf::declare("ERC20").unwrap(); @@ -29,6 +33,14 @@ pub fn deploy_erc20(name: ByteArray, symbol: ByteArray) -> ContractAddress { OWNER().serialize(ref constructor_args); let (usdc, _) = erc20_class_hash.deploy(@constructor_args).unwrap(); + + let usdc_token = IERC20Dispatcher { contract_address: usdc }; + + // Transfering usdc to test address for testing + snf::start_cheat_caller_address(usdc, OWNER()); + usdc_token.transfer(snf::test_address(), 100); + snf::stop_cheat_caller_address(usdc); + return usdc; } @@ -78,3 +90,27 @@ pub fn deploy_token_bridge() -> (ITokenBridgeDispatcher, EventSpy) { pub fn mock_state_testing() -> TokenBridge::ContractState { TokenBridge::contract_state_for_testing() } + +pub fn enroll_token_and_settle( + token_bridge: ITokenBridgeDispatcher, + messaging_mock: IMockMessagingDispatcher, + token: ContractAddress +) { + assert(token_bridge.get_status(token) == TokenStatus::Unknown, 'Should be Unknown'); + + token_bridge.enroll_token(token); + assert(token_bridge.get_status(token) == TokenStatus::Pending, 'Should be Pending'); + + // Settles the message sent to appchain + messaging_mock + .process_last_message_to_appchain( + L3_BRIDGE_ADDRESS(), + constants::HANDLE_TOKEN_DEPLOYMENT_SELECTOR, + message_payloads::deployment_message_payload(token) + ); + + token_bridge.check_deployment_status(token); + + let final_status = token_bridge.get_status(token); + assert(final_status == TokenStatus::Active, 'Should be Active'); +} diff --git a/tests/withdraw_test.cairo b/tests/withdraw_test.cairo index 45eeab8..e6911ae 100644 --- a/tests/withdraw_test.cairo +++ b/tests/withdraw_test.cairo @@ -28,7 +28,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 super::setup::{deploy_erc20, deploy_token_bridge_with_messaging, deploy_token_bridge}; +use super::setup::{ + deploy_erc20, deploy_token_bridge_with_messaging, deploy_token_bridge, enroll_token_and_settle +}; use starknet_bridge::constants; use starknet_bridge::bridge::tests::utils::message_payloads; @@ -42,23 +44,7 @@ fn withdraw_ok() { usdc.transfer(snf::test_address(), 100); snf::stop_cheat_caller_address(usdc_address); - assert(token_bridge.get_status(usdc_address) == TokenStatus::Unknown, 'Should be Unknown'); - - token_bridge.enroll_token(usdc_address); - assert(token_bridge.get_status(usdc_address) == TokenStatus::Pending, 'Should be Pending'); - - // Settles the message sent to appchain - messaging_mock - .process_last_message_to_appchain( - L3_BRIDGE_ADDRESS(), - constants::HANDLE_TOKEN_DEPLOYMENT_SELECTOR, - message_payloads::deployment_message_payload(usdc_address) - ); - - token_bridge.check_deployment_status(usdc_address); - - let final_status = token_bridge.get_status(usdc_address); - assert(final_status == TokenStatus::Active, 'Should be Active'); + enroll_token_and_settle(token_bridge, messaging_mock, usdc_address); let amount = 100; usdc.approve(token_bridge.contract_address, amount); @@ -102,66 +88,6 @@ fn withdraw_ok() { ); } - -#[test] -#[should_panic(expected: ('Invalid recipient',))] -fn withdraw_zero_recipient() { - let (token_bridge, _, messaging_mock) = deploy_token_bridge_with_messaging(); - let usdc_address = deploy_erc20("usdc", "usdc"); - let usdc = IERC20Dispatcher { contract_address: usdc_address }; - - snf::start_cheat_caller_address(usdc_address, OWNER()); - usdc.transfer(snf::test_address(), 100); - snf::stop_cheat_caller_address(usdc_address); - - assert(token_bridge.get_status(usdc_address) == TokenStatus::Unknown, 'Should be Unknown'); - - token_bridge.enroll_token(usdc_address); - assert(token_bridge.get_status(usdc_address) == TokenStatus::Pending, 'Should be Pending'); - - // Settles the message sent to appchain - messaging_mock - .process_last_message_to_appchain( - L3_BRIDGE_ADDRESS(), - constants::HANDLE_TOKEN_DEPLOYMENT_SELECTOR, - message_payloads::deployment_message_payload(usdc_address) - ); - - token_bridge.check_deployment_status(usdc_address); - - let final_status = token_bridge.get_status(usdc_address); - assert(final_status == TokenStatus::Active, 'Should be Active'); - - let amount = 100; - usdc.approve(token_bridge.contract_address, amount); - token_bridge.deposit(usdc_address, amount, snf::test_address()); - messaging_mock - .process_last_message_to_appchain( - L3_BRIDGE_ADDRESS(), - constants::HANDLE_TOKEN_DEPOSIT_SELECTOR, - message_payloads::deposit_message_payload( - usdc_address, - amount, - snf::test_address(), - snf::test_address(), - false, - array![].span() - ) - ); - - // Register a withdraw message from appchain to piltover - messaging_mock - .process_message_to_starknet( - L3_BRIDGE_ADDRESS(), - token_bridge.contract_address, - message_payloads::withdraw_message_payload_from_appchain( - usdc_address, amount, snf::test_address() - ) - ); - - token_bridge.withdraw(usdc_address, 100, contract_address_const::<0>()); -} - #[test] #[should_panic(expected: ('INVALID_MESSAGE_TO_CONSUME',))] fn withdraw_incorrect_recipient() { @@ -173,23 +99,7 @@ fn withdraw_incorrect_recipient() { usdc.transfer(snf::test_address(), 100); snf::stop_cheat_caller_address(usdc_address); - assert(token_bridge.get_status(usdc_address) == TokenStatus::Unknown, 'Should be Unknown'); - - token_bridge.enroll_token(usdc_address); - assert(token_bridge.get_status(usdc_address) == TokenStatus::Pending, 'Should be Pending'); - - // Settles the message sent to appchain - messaging_mock - .process_last_message_to_appchain( - L3_BRIDGE_ADDRESS(), - constants::HANDLE_TOKEN_DEPLOYMENT_SELECTOR, - message_payloads::deployment_message_payload(usdc_address) - ); - - token_bridge.check_deployment_status(usdc_address); - - let final_status = token_bridge.get_status(usdc_address); - assert(final_status == TokenStatus::Active, 'Should be Active'); + enroll_token_and_settle(token_bridge, messaging_mock, usdc_address); let amount = 100; usdc.approve(token_bridge.contract_address, amount); @@ -236,23 +146,7 @@ fn withdraw_limit_reached() { usdc.transfer(snf::test_address(), 100); snf::stop_cheat_caller_address(usdc_address); - assert(token_bridge.get_status(usdc_address) == TokenStatus::Unknown, 'Should be Unknown'); - - token_bridge.enroll_token(usdc_address); - assert(token_bridge.get_status(usdc_address) == TokenStatus::Pending, 'Should be Pending'); - - // Settles the message sent to appchain - messaging_mock - .process_last_message_to_appchain( - L3_BRIDGE_ADDRESS(), - constants::HANDLE_TOKEN_DEPLOYMENT_SELECTOR, - message_payloads::deployment_message_payload(usdc_address) - ); - - token_bridge.check_deployment_status(usdc_address); - - let final_status = token_bridge.get_status(usdc_address); - assert(final_status == TokenStatus::Active, 'Should be Active'); + enroll_token_and_settle(token_bridge, messaging_mock, usdc_address); let amount = 100; usdc.approve(token_bridge.contract_address, amount); From 8f7d0aaf2d6ec87da75b9d651745bbb96c928b13 Mon Sep 17 00:00:00 2001 From: byteZorvin Date: Fri, 9 Aug 2024 10:25:59 +0530 Subject: [PATCH 39/62] fix consume message --- src/bridge/tests/token_actions_test.cairo | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/bridge/tests/token_actions_test.cairo b/src/bridge/tests/token_actions_test.cairo index 0f0ded4..c56aa14 100644 --- a/src/bridge/tests/token_actions_test.cairo +++ b/src/bridge/tests/token_actions_test.cairo @@ -1,10 +1,12 @@ +use starknet_bridge::bridge::token_bridge::TokenBridge::__member_module_appchain_bridge::InternalContractMemberStateTrait; use starknet_bridge::bridge::token_bridge::TokenBridge::TokenBridgeInternal; -use starknet_bridge::bridge::token_bridge::TokenBridge::__member_module_token_settings::InternalContractMemberStateTrait; +use starknet_bridge::bridge::token_bridge::TokenBridge::__member_module_token_settings::InternalContractMemberStateTrait as tokenSettingsStateTrait; use snforge_std as snf; use starknet::{ContractAddress, storage::StorageMemberAccessTrait}; use starknet_bridge::mocks::{ messaging::{IMockMessagingDispatcherTrait, IMockMessagingDispatcher}, erc20::ERC20 }; +use piltover::messaging::interface::IMessagingDispatcher; use starknet_bridge::bridge::{ ITokenBridge, ITokenBridgeAdmin, ITokenBridgeDispatcher, ITokenBridgeDispatcherTrait, ITokenBridgeAdminDispatcher, ITokenBridgeAdminDispatcherTrait, IWithdrawalLimitStatusDispatcher, @@ -210,5 +212,6 @@ fn consume_message_zero_recipient() { let mut mock = mock_state_testing(); let usdc_address = USDC_MOCK_ADDRESS(); + mock.appchain_bridge.write(L3_BRIDGE_ADDRESS()); mock.consume_message(usdc_address, 100, contract_address_const::<0>()); } From 7f78c0bf65cdc87504339d35e4b8c8ff299370bb Mon Sep 17 00:00:00 2001 From: byteZorvin Date: Fri, 9 Aug 2024 11:12:40 +0530 Subject: [PATCH 40/62] reclaim testcases --- src/bridge/tests/token_actions_test.cairo | 18 +- tests/deposit_reclaim_test.cairo | 278 ++++++++++++++++++++++ tests/deposit_test.cairo | 51 +++- tests/lib.cairo | 1 + 4 files changed, 330 insertions(+), 18 deletions(-) create mode 100644 tests/deposit_reclaim_test.cairo diff --git a/src/bridge/tests/token_actions_test.cairo b/src/bridge/tests/token_actions_test.cairo index c56aa14..f54bbe1 100644 --- a/src/bridge/tests/token_actions_test.cairo +++ b/src/bridge/tests/token_actions_test.cairo @@ -205,13 +205,13 @@ fn enroll_token_blocked() { snf::start_cheat_caller_address_global(OWNER()); mock.enroll_token(usdc_address); } +// #[test] +// #[should_panic(expected: ('Invalid recipient',))] +// fn consume_message_zero_recipient() { +// let mut mock = mock_state_testing(); +// let usdc_address = USDC_MOCK_ADDRESS(); +// +// mock.appchain_bridge.write(L3_BRIDGE_ADDRESS()); +// mock.consume_message(usdc_address, 100, contract_address_const::<0>()); +// } -#[test] -#[should_panic(expected: ('Invalid recipient',))] -fn consume_message_zero_recipient() { - let mut mock = mock_state_testing(); - let usdc_address = USDC_MOCK_ADDRESS(); - - mock.appchain_bridge.write(L3_BRIDGE_ADDRESS()); - mock.consume_message(usdc_address, 100, contract_address_const::<0>()); -} diff --git a/tests/deposit_reclaim_test.cairo b/tests/deposit_reclaim_test.cairo new file mode 100644 index 0000000..83958b8 --- /dev/null +++ b/tests/deposit_reclaim_test.cairo @@ -0,0 +1,278 @@ +use core::num::traits::zero::Zero; +use starknet_bridge::bridge::token_bridge::TokenBridge::__member_module_token_settings::InternalContractMemberStateTrait; +use core::array::ArrayTrait; +use core::serde::Serde; +use core::result::ResultTrait; +use core::option::OptionTrait; +use core::traits::TryInto; +use snforge_std as snf; +use snforge_std::{ + ContractClassTrait, EventSpy, EventSpyTrait, EventsFilterTrait, EventSpyAssertionsTrait +}; +use starknet::{ContractAddress, storage::StorageMemberAccessTrait}; +use starknet_bridge::mocks::{ + messaging::{IMockMessagingDispatcherTrait, IMockMessagingDispatcher}, erc20::ERC20 +}; +use piltover::messaging::{IMessaging, IMessagingDispatcher, IMessagingDispatcherTrait}; +use starknet_bridge::bridge::{ + ITokenBridge, ITokenBridgeAdmin, ITokenBridgeDispatcher, ITokenBridgeDispatcherTrait, + ITokenBridgeAdminDispatcher, ITokenBridgeAdminDispatcherTrait, IWithdrawalLimitStatusDispatcher, + IWithdrawalLimitStatusDispatcherTrait, TokenBridge, TokenBridge::Event, + types::{TokenStatus, TokenSettings} +}; +use openzeppelin::access::ownable::{ + OwnableComponent, OwnableComponent::Event as OwnableEvent, + interface::{IOwnableTwoStepDispatcher, IOwnableTwoStepDispatcherTrait} +}; + +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::{ + deploy_erc20, deploy_token_bridge_with_messaging, deploy_token_bridge, enroll_token_and_settle +}; + +#[test] +fn deposit_reclaim_ok() { + let (token_bridge, mut spy, messaging_mock) = deploy_token_bridge_with_messaging(); + let usdc_address = deploy_erc20("usdc", "usdc"); + let usdc = IERC20Dispatcher { contract_address: usdc_address }; + + enroll_token_and_settle(token_bridge, messaging_mock, usdc_address); + + usdc.approve(token_bridge.contract_address, 100); + token_bridge.deposit(usdc_address, 100, snf::test_address()); + + snf::start_cheat_block_timestamp_global(5); + token_bridge.deposit_cancel_request(usdc_address, 100, snf::test_address(), 2); + + snf::start_cheat_block_timestamp_global( + starknet::get_block_timestamp() + DELAY_TIME.try_into().unwrap() + 10 + ); + + token_bridge.deposit_reclaim(usdc_address, 100, snf::test_address(), 2); + + let expected_deposit_cancel = TokenBridge::DepositCancelRequest { + sender: snf::test_address(), + token: usdc_address, + amount: 100, + appchain_recipient: snf::test_address(), + nonce: 2 + }; + + let expected_deposit_reclaim = TokenBridge::DepositReclaimed { + sender: snf::test_address(), + token: usdc_address, + amount: 100, + appchain_recipient: snf::test_address(), + nonce: 2 + }; + + spy + .assert_emitted( + @array![ + ( + token_bridge.contract_address, + Event::DepostiCancelRequest(expected_deposit_cancel) + ), + (token_bridge.contract_address, Event::DepositReclaimed(expected_deposit_reclaim)) + ] + ); +} + +#[test] +#[should_panic(expected: ('CANCELLATION_NOT_ALLOWED_YET',))] +fn deposit_reclaim_delay_not_reached() { + let (token_bridge, _, messaging_mock) = deploy_token_bridge_with_messaging(); + let usdc_address = deploy_erc20("usdc", "usdc"); + let usdc = IERC20Dispatcher { contract_address: usdc_address }; + + enroll_token_and_settle(token_bridge, messaging_mock, usdc_address); + + usdc.approve(token_bridge.contract_address, 100); + token_bridge.deposit(usdc_address, 100, snf::test_address()); + + snf::start_cheat_block_timestamp_global(5); + token_bridge.deposit_cancel_request(usdc_address, 100, snf::test_address(), 2); + + token_bridge.deposit_reclaim(usdc_address, 100, snf::test_address(), 2); +} + + +#[test] +#[should_panic(expected: ('CANCELLATION_NOT_REQUESTED',))] +fn deposit_reclaim_not_cancelled() { + let (token_bridge, _, messaging_mock) = deploy_token_bridge_with_messaging(); + let usdc_address = deploy_erc20("usdc", "usdc"); + let usdc = IERC20Dispatcher { contract_address: usdc_address }; + + enroll_token_and_settle(token_bridge, messaging_mock, usdc_address); + + usdc.approve(token_bridge.contract_address, 100); + token_bridge.deposit(usdc_address, 100, snf::test_address()); + + snf::start_cheat_block_timestamp_global( + starknet::get_block_timestamp() + DELAY_TIME.try_into().unwrap() + 10 + ); + + token_bridge.deposit_reclaim(usdc_address, 100, snf::test_address(), 2); +} + +#[test] +#[should_panic(expected: ('NO_MESSAGE_TO_CANCEL',))] +fn deposit_reclaim_different_user() { + let (token_bridge, _, messaging_mock) = deploy_token_bridge_with_messaging(); + let usdc_address = deploy_erc20("usdc", "usdc"); + let usdc = IERC20Dispatcher { contract_address: usdc_address }; + + enroll_token_and_settle(token_bridge, messaging_mock, usdc_address); + + usdc.approve(token_bridge.contract_address, 100); + token_bridge.deposit(usdc_address, 100, snf::test_address()); + + snf::start_cheat_block_timestamp_global(5); + token_bridge.deposit_cancel_request(usdc_address, 100, snf::test_address(), 2); + + snf::start_cheat_block_timestamp_global( + starknet::get_block_timestamp() + DELAY_TIME.try_into().unwrap() + 10 + ); + + snf::start_cheat_caller_address_global(contract_address_const::<'user2'>()); + token_bridge.deposit_reclaim(usdc_address, 100, snf::test_address(), 2); +} + + +#[test] +fn deposit_with_message_reclaim_ok() { + let (token_bridge, mut spy, messaging_mock) = deploy_token_bridge_with_messaging(); + let usdc_address = deploy_erc20("usdc", "usdc"); + let usdc = IERC20Dispatcher { contract_address: usdc_address }; + + enroll_token_and_settle(token_bridge, messaging_mock, usdc_address); + + let mut calldata = ArrayTrait::new(); + 'param1'.serialize(ref calldata); + 'param2'.serialize(ref calldata); + + usdc.approve(token_bridge.contract_address, 100); + token_bridge.deposit_with_message(usdc_address, 100, snf::test_address(), calldata.span()); + + snf::start_cheat_block_timestamp_global(5); + token_bridge + .deposit_with_message_cancel_request( + usdc_address, 100, snf::test_address(), calldata.span(), 2 + ); + + snf::start_cheat_block_timestamp_global( + starknet::get_block_timestamp() + DELAY_TIME.try_into().unwrap() + 10 + ); + + token_bridge + .deposit_with_message_reclaim(usdc_address, 100, snf::test_address(), calldata.span(), 2); + + let expected_deposit_cancel = TokenBridge::DepositWithMessageCancelRequest { + sender: snf::test_address(), + token: usdc_address, + amount: 100, + appchain_recipient: snf::test_address(), + message: calldata.span(), + nonce: 2 + }; + + let expected_deposit_reclaim = TokenBridge::DepositWithMessageReclaimed { + sender: snf::test_address(), + token: usdc_address, + amount: 100, + appchain_recipient: snf::test_address(), + message: calldata.span(), + nonce: 2 + }; + + spy + .assert_emitted( + @array![ + ( + token_bridge.contract_address, + Event::DepositWithMessageCancelRequest(expected_deposit_cancel) + ), + ( + token_bridge.contract_address, + Event::DepositWithMessageReclaimed(expected_deposit_reclaim) + ) + ] + ); +} + +#[test] +#[should_panic(expected: ('CANCELLATION_NOT_ALLOWED_YET',))] +fn deposit_with_message_reclaim_delay_not_reached() { + let (token_bridge, _, messaging_mock) = deploy_token_bridge_with_messaging(); + let usdc_address = deploy_erc20("usdc", "usdc"); + let usdc = IERC20Dispatcher { contract_address: usdc_address }; + + enroll_token_and_settle(token_bridge, messaging_mock, usdc_address); + + usdc.approve(token_bridge.contract_address, 100); + token_bridge.deposit(usdc_address, 100, snf::test_address()); + + snf::start_cheat_block_timestamp_global(5); + token_bridge.deposit_cancel_request(usdc_address, 100, snf::test_address(), 2); + + token_bridge.deposit_reclaim(usdc_address, 100, snf::test_address(), 2); +} + + +#[test] +#[should_panic(expected: ('CANCELLATION_NOT_REQUESTED',))] +fn deposit_wtih_message_reclaim_not_cancelled() { + let (token_bridge, _, messaging_mock) = deploy_token_bridge_with_messaging(); + let usdc_address = deploy_erc20("usdc", "usdc"); + let usdc = IERC20Dispatcher { contract_address: usdc_address }; + + enroll_token_and_settle(token_bridge, messaging_mock, usdc_address); + + let mut calldata = ArrayTrait::new(); + 'param1'.serialize(ref calldata); + 'param2'.serialize(ref calldata); + + usdc.approve(token_bridge.contract_address, 100); + token_bridge.deposit_with_message(usdc_address, 100, snf::test_address(), calldata.span()); + + snf::start_cheat_block_timestamp_global( + starknet::get_block_timestamp() + DELAY_TIME.try_into().unwrap() + 10 + ); + + token_bridge + .deposit_with_message_reclaim(usdc_address, 100, snf::test_address(), calldata.span(), 2); +} + +#[test] +#[should_panic(expected: ('NO_MESSAGE_TO_CANCEL',))] +fn deposit_reclaim_with_message_different_user() { + let (token_bridge, _, messaging_mock) = deploy_token_bridge_with_messaging(); + let usdc_address = deploy_erc20("usdc", "usdc"); + let usdc = IERC20Dispatcher { contract_address: usdc_address }; + + enroll_token_and_settle(token_bridge, messaging_mock, usdc_address); + + let mut calldata = ArrayTrait::new(); + 'param1'.serialize(ref calldata); + 'param2'.serialize(ref calldata); + + usdc.approve(token_bridge.contract_address, 100); + token_bridge.deposit_with_message(usdc_address, 100, snf::test_address(), calldata.span()); + + snf::start_cheat_block_timestamp_global(5); + token_bridge + .deposit_with_message_cancel_request( + usdc_address, 100, snf::test_address(), calldata.span(), 2 + ); + + snf::start_cheat_block_timestamp_global( + starknet::get_block_timestamp() + DELAY_TIME.try_into().unwrap() + 10 + ); + + snf::start_cheat_caller_address_global(contract_address_const::<'user2'>()); + token_bridge + .deposit_with_message_reclaim(usdc_address, 100, snf::test_address(), calldata.span(), 2); +} diff --git a/tests/deposit_test.cairo b/tests/deposit_test.cairo index c8ab199..2d87230 100644 --- a/tests/deposit_test.cairo +++ b/tests/deposit_test.cairo @@ -86,6 +86,26 @@ fn deposit_insufficient_allowance() { token_bridge.deposit(usdc_address, 100, snf::test_address()); } + +#[test] +#[should_panic(expected: ('Only servicing tokens',))] +fn deposit_deactivated() { + let (token_bridge, _, messaging_mock) = deploy_token_bridge_with_messaging(); + let usdc_address = deploy_erc20("usdc", "usdc"); + let token_bridge_admin = ITokenBridgeAdminDispatcher { + contract_address: token_bridge.contract_address + }; + + enroll_token_and_settle(token_bridge, messaging_mock, usdc_address); + + snf::start_cheat_caller_address(token_bridge.contract_address, OWNER()); + token_bridge_admin.deactivate_token(usdc_address); + snf::stop_cheat_caller_address(OWNER()); + + token_bridge.deposit(usdc_address, 100, snf::test_address()); +} + + #[test] fn deposit_with_message_ok() { let (token_bridge, mut spy, messaging_mock) = deploy_token_bridge_with_messaging(); @@ -169,21 +189,34 @@ fn deposit_with_message_empty_message_ok() { } #[test] -#[should_panic(expected: ('Only servicing tokens',))] -fn deposit_deactivated() { +#[should_panic(expected: ('ERC20: insufficient balance',))] +fn deposit_with_message_insufficient_balance() { let (token_bridge, _, messaging_mock) = deploy_token_bridge_with_messaging(); let usdc_address = deploy_erc20("usdc", "usdc"); - let token_bridge_admin = ITokenBridgeAdminDispatcher { - contract_address: token_bridge.contract_address - }; + let usdc = IERC20Dispatcher { contract_address: usdc_address }; enroll_token_and_settle(token_bridge, messaging_mock, usdc_address); - snf::start_cheat_caller_address(token_bridge.contract_address, OWNER()); - token_bridge_admin.deactivate_token(usdc_address); - snf::stop_cheat_caller_address(OWNER()); + usdc.approve(token_bridge.contract_address, 200); - token_bridge.deposit(usdc_address, 100, snf::test_address()); + let mut calldata = ArrayTrait::new(); + 'param1'.serialize(ref calldata); + 'param2'.serialize(ref calldata); + token_bridge.deposit_with_message(usdc_address, 200, snf::test_address(), calldata.span()); +} + +#[test] +#[should_panic(expected: ('ERC20: insufficient allowance',))] +fn deposit_with_message_insufficient_allowance() { + let (token_bridge, _, messaging_mock) = deploy_token_bridge_with_messaging(); + let usdc_address = deploy_erc20("usdc", "usdc"); + + enroll_token_and_settle(token_bridge, messaging_mock, usdc_address); + + let mut calldata = ArrayTrait::new(); + 'param1'.serialize(ref calldata); + 'param2'.serialize(ref calldata); + token_bridge.deposit_with_message(usdc_address, 100, snf::test_address(), calldata.span()); } #[test] diff --git a/tests/lib.cairo b/tests/lib.cairo index a79f2bd..3f753a6 100644 --- a/tests/lib.cairo +++ b/tests/lib.cairo @@ -5,4 +5,5 @@ mod token_actions_test; mod enroll_token_test; mod deposit_test; mod withdraw_test; +mod deposit_reclaim_test; From 790f2c88ece6e3375a15df47b8017799fb5701b8 Mon Sep 17 00:00:00 2001 From: byteZorvin Date: Fri, 9 Aug 2024 11:15:33 +0530 Subject: [PATCH 41/62] fix consume message check --- src/bridge/token_bridge.cairo | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/bridge/token_bridge.cairo b/src/bridge/token_bridge.cairo index 76160eb..26833b5 100644 --- a/src/bridge/token_bridge.cairo +++ b/src/bridge/token_bridge.cairo @@ -330,6 +330,8 @@ pub mod TokenBridge { fn consume_message( self: @ContractState, token: ContractAddress, amount: u256, recipient: ContractAddress ) { + assert(recipient.is_non_zero(), Errors::INVALID_RECIPIENT); + let appchain_bridge = self.appchain_bridge(); assert(appchain_bridge.is_non_zero(), Errors::APPCHAIN_BRIDGE_NOT_SET); let mut payload = ArrayTrait::new(); @@ -615,10 +617,10 @@ pub mod TokenBridge { recipient: ContractAddress ) { self.reentrancy_guard.start(); - assert(recipient.is_non_zero(), Errors::INVALID_RECIPIENT); self.consume_message(token, amount, recipient); + assert(recipient.is_non_zero(), Errors::INVALID_RECIPIENT); self.withdrawal.consume_withdrawal_quota(token, amount); let tokenDispatcher = IERC20Dispatcher { contract_address: token }; From 7de6fec774350975c1b335dd7b74482fe6f2b1f2 Mon Sep 17 00:00:00 2001 From: byteZorvin Date: Fri, 9 Aug 2024 11:18:39 +0530 Subject: [PATCH 42/62] consume message --- src/bridge/tests/token_actions_test.cairo | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/bridge/tests/token_actions_test.cairo b/src/bridge/tests/token_actions_test.cairo index f54bbe1..f20fe0d 100644 --- a/src/bridge/tests/token_actions_test.cairo +++ b/src/bridge/tests/token_actions_test.cairo @@ -205,13 +205,15 @@ fn enroll_token_blocked() { snf::start_cheat_caller_address_global(OWNER()); mock.enroll_token(usdc_address); } -// #[test] -// #[should_panic(expected: ('Invalid recipient',))] -// fn consume_message_zero_recipient() { -// let mut mock = mock_state_testing(); -// let usdc_address = USDC_MOCK_ADDRESS(); -// -// mock.appchain_bridge.write(L3_BRIDGE_ADDRESS()); -// mock.consume_message(usdc_address, 100, contract_address_const::<0>()); -// } + + +#[test] +#[should_panic(expected: ('Invalid recipient',))] +fn consume_message_zero_recipient() { + let mut mock = mock_state_testing(); + let usdc_address = USDC_MOCK_ADDRESS(); + + mock.appchain_bridge.write(L3_BRIDGE_ADDRESS()); + mock.consume_message(usdc_address, 100, contract_address_const::<0>()); +} From ace08500920d2ecba6622e5f55ed80de1d29d18a Mon Sep 17 00:00:00 2001 From: byteZorvin Date: Fri, 9 Aug 2024 12:11:45 +0530 Subject: [PATCH 43/62] add balance check --- tests/deposit_reclaim_test.cairo | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tests/deposit_reclaim_test.cairo b/tests/deposit_reclaim_test.cairo index 83958b8..f6c2e90 100644 --- a/tests/deposit_reclaim_test.cairo +++ b/tests/deposit_reclaim_test.cairo @@ -49,8 +49,11 @@ fn deposit_reclaim_ok() { snf::start_cheat_block_timestamp_global( starknet::get_block_timestamp() + DELAY_TIME.try_into().unwrap() + 10 ); - + let initial_user_balance = usdc.balance_of(snf::test_address()); token_bridge.deposit_reclaim(usdc_address, 100, snf::test_address(), 2); + assert( + usdc.balance_of(snf::test_address()) == initial_user_balance + 100, 'deposit not recieved' + ); let expected_deposit_cancel = TokenBridge::DepositCancelRequest { sender: snf::test_address(), @@ -167,8 +170,12 @@ fn deposit_with_message_reclaim_ok() { starknet::get_block_timestamp() + DELAY_TIME.try_into().unwrap() + 10 ); + let initial_user_balance = usdc.balance_of(snf::test_address()); token_bridge .deposit_with_message_reclaim(usdc_address, 100, snf::test_address(), calldata.span(), 2); + assert( + usdc.balance_of(snf::test_address()) == initial_user_balance + 100, 'deposit not recieved' + ); let expected_deposit_cancel = TokenBridge::DepositWithMessageCancelRequest { sender: snf::test_address(), From 5d1218cb9b4ce6da5d6532c33eef64f6c61866be Mon Sep 17 00:00:00 2001 From: byteZorvin Date: Fri, 9 Aug 2024 13:29:59 +0530 Subject: [PATCH 44/62] add events in actions --- src/bridge/tests/test_bridge.cairo | 143 ----------------------------- src/lib.cairo | 1 - tests/token_actions_test.cairo | 45 +++++++-- 3 files changed, 35 insertions(+), 154 deletions(-) delete mode 100644 src/bridge/tests/test_bridge.cairo diff --git a/src/bridge/tests/test_bridge.cairo b/src/bridge/tests/test_bridge.cairo deleted file mode 100644 index f4eed8f..0000000 --- a/src/bridge/tests/test_bridge.cairo +++ /dev/null @@ -1,143 +0,0 @@ -use starknet_bridge::bridge::token_bridge::TokenBridge::__member_module_token_settings::InternalContractMemberStateTrait; -use snforge_std as snf; -use starknet::{ContractAddress, storage::StorageMemberAccessTrait}; -use starknet_bridge::mocks::{ - messaging::{IMockMessagingDispatcherTrait, IMockMessagingDispatcher}, erc20::ERC20 -}; -use starknet_bridge::bridge::{ - ITokenBridge, ITokenBridgeAdmin, ITokenBridgeDispatcher, ITokenBridgeDispatcherTrait, - ITokenBridgeAdminDispatcher, ITokenBridgeAdminDispatcherTrait, IWithdrawalLimitStatusDispatcher, - IWithdrawalLimitStatusDispatcherTrait, TokenBridge, TokenBridge::Event, - types::{TokenStatus, TokenSettings} -}; -use openzeppelin::access::ownable::{ - OwnableComponent, OwnableComponent::Event as OwnableEvent, - interface::{IOwnableTwoStepDispatcher, IOwnableTwoStepDispatcherTrait} -}; -use starknet::contract_address::{contract_address_const}; - -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() -} - -#[test] -fn unblock_token_ok() { - let mut mock = mock_state_testing(); - let usdc_address = USDC_MOCK_ADDRESS(); - - // Setting the token active - let old_settings = mock.token_settings.read(usdc_address); - mock - .token_settings - .write(usdc_address, TokenSettings { token_status: TokenStatus::Blocked, ..old_settings }); - - mock.ownable.Ownable_owner.write(OWNER()); - snf::start_cheat_caller_address_global(OWNER()); - - mock.unblock_token(usdc_address); - assert(mock.get_status(usdc_address) == TokenStatus::Unknown, 'Not unblocked'); -} - -#[test] -#[should_panic(expected: ('Caller is not the owner',))] -fn unblock_token_not_owner() { - let mut mock = mock_state_testing(); - let usdc_address = USDC_MOCK_ADDRESS(); - - // Setting the token active - let old_settings = mock.token_settings.read(usdc_address); - mock - .token_settings - .write(usdc_address, TokenSettings { token_status: TokenStatus::Blocked, ..old_settings }); - - mock.ownable.Ownable_owner.write(OWNER()); - snf::start_cheat_caller_address_global(snf::test_address()); - - mock.unblock_token(usdc_address); -} - - -#[test] -#[should_panic(expected: ('Token not blocked',))] -fn unblock_token_not_blocked() { - let mut mock = mock_state_testing(); - let usdc_address = USDC_MOCK_ADDRESS(); - - // Setting the token active - let old_settings = mock.token_settings.read(usdc_address); - mock - .token_settings - .write(usdc_address, TokenSettings { token_status: TokenStatus::Active, ..old_settings }); - - mock.ownable.Ownable_owner.write(OWNER()); - snf::start_cheat_caller_address_global(OWNER()); - - mock.unblock_token(usdc_address); -} - -#[test] -fn reactivate_token_ok() { - let mut mock = mock_state_testing(); - let usdc_address = USDC_MOCK_ADDRESS(); - - // Setting the token active - let old_settings = mock.token_settings.read(usdc_address); - mock - .token_settings - .write( - usdc_address, TokenSettings { token_status: TokenStatus::Deactivated, ..old_settings } - ); - - mock.ownable.Ownable_owner.write(OWNER()); - - snf::start_cheat_caller_address_global(OWNER()); - - mock.reactivate_token(usdc_address); - assert(mock.get_status(usdc_address) == TokenStatus::Active, 'Did not reactivate'); -} - -#[test] -#[should_panic(expected: ('Caller is not the owner',))] -fn reactivate_token_not_owner() { - let mut mock = mock_state_testing(); - let usdc_address = USDC_MOCK_ADDRESS(); - - // Setting the token active - let old_settings = mock.token_settings.read(usdc_address); - mock - .token_settings - .write( - usdc_address, TokenSettings { token_status: TokenStatus::Deactivated, ..old_settings } - ); - - snf::start_cheat_caller_address_global(snf::test_address()); - - mock.reactivate_token(usdc_address); -} - -#[test] -#[should_panic(expected: ('Token not deactivated',))] -fn reactivate_token_not_deactivated() { - let mut mock = mock_state_testing(); - let usdc_address = USDC_MOCK_ADDRESS(); - - // Setting the token active - let old_settings = mock.token_settings.read(usdc_address); - mock - .token_settings - .write(usdc_address, TokenSettings { token_status: TokenStatus::Blocked, ..old_settings }); - - mock.ownable.Ownable_owner.write(OWNER()); - snf::start_cheat_caller_address_global(OWNER()); - - mock.reactivate_token(usdc_address); -} - diff --git a/src/lib.cairo b/src/lib.cairo index a85ec28..e646582 100644 --- a/src/lib.cairo +++ b/src/lib.cairo @@ -6,7 +6,6 @@ pub mod bridge { #[cfg(test)] pub mod tests { pub mod constants; - mod test_bridge; mod token_actions_test; pub mod utils { pub mod message_payloads; diff --git a/tests/token_actions_test.cairo b/tests/token_actions_test.cairo index 3507495..f7535c3 100644 --- a/tests/token_actions_test.cairo +++ b/tests/token_actions_test.cairo @@ -33,13 +33,13 @@ fn enable_withdrawal_limit_not_owner() { contract_address: token_bridge.contract_address }; - let usdc_address = deploy_erc20("USDC", "USDC"); + let usdc_address = USDC_MOCK_ADDRESS(); token_bridge_admin.enable_withdrawal_limit(usdc_address); } #[test] fn enable_withdrawal_limit_ok() { - let (token_bridge, _) = deploy_token_bridge(); + let (token_bridge, mut spy) = deploy_token_bridge(); let token_bridge_admin = ITokenBridgeAdminDispatcher { contract_address: token_bridge.contract_address }; @@ -47,20 +47,32 @@ fn enable_withdrawal_limit_ok() { contract_address: token_bridge.contract_address }; - let owner = OWNER(); - snf::start_cheat_caller_address(token_bridge.contract_address, owner); + snf::start_cheat_caller_address(token_bridge.contract_address, OWNER()); - let usdc_address = deploy_erc20("USDC", "USDC"); + let usdc_address = USDC_MOCK_ADDRESS(); token_bridge_admin.enable_withdrawal_limit(usdc_address); snf::stop_cheat_caller_address(token_bridge.contract_address); assert(withdrawal_limit.is_withdrawal_limit_applied(usdc_address), 'Limit not applied'); + + let exepected_limit_enabled = TokenBridge::WithdrawalLimitEnabled { + sender: OWNER(), token: usdc_address + }; + spy + .assert_emitted( + @array![ + ( + token_bridge_admin.contract_address, + Event::WithdrawalLimitEnabled(exepected_limit_enabled) + ) + ] + ); } #[test] fn disable_withdrwal_limit_ok() { - let (token_bridge, _) = deploy_token_bridge(); + let (token_bridge, mut spy) = deploy_token_bridge(); let token_bridge_admin = ITokenBridgeAdminDispatcher { contract_address: token_bridge.contract_address }; @@ -71,7 +83,7 @@ fn disable_withdrwal_limit_ok() { let owner = OWNER(); snf::start_cheat_caller_address(token_bridge.contract_address, owner); - let usdc_address = deploy_erc20("USDC", "USDC"); + let usdc_address = USDC_MOCK_ADDRESS(); token_bridge_admin.enable_withdrawal_limit(usdc_address); // Withdrawal limit is now applied @@ -82,12 +94,25 @@ fn disable_withdrwal_limit_ok() { assert( withdrawal_limit.is_withdrawal_limit_applied(usdc_address) == false, 'Limit not applied' ); - snf::stop_cheat_caller_address(token_bridge.contract_address); + + let expected_limit_disabled = TokenBridge::WithdrawalLimitDisabled { + sender: OWNER(), token: usdc_address + }; + + spy + .assert_emitted( + @array![ + ( + token_bridge_admin.contract_address, + Event::WithdrawalLimitDisabled(expected_limit_disabled) + ) + ] + ); } #[test] #[should_panic(expected: ('Caller is not the owner',))] -fn disable_withdrwal_not_owner() { +fn disable_withdrawal_limit_not_owner() { let (token_bridge, _) = deploy_token_bridge(); let token_bridge_admin = ITokenBridgeAdminDispatcher { contract_address: token_bridge.contract_address @@ -100,7 +125,7 @@ fn disable_withdrwal_not_owner() { let owner = OWNER(); snf::start_cheat_caller_address(token_bridge.contract_address, owner); - let usdc_address = deploy_erc20("USDC", "USDC"); + let usdc_address = USDC_MOCK_ADDRESS(); token_bridge_admin.enable_withdrawal_limit(usdc_address); // Withdrawal limit is now applied From 39b9e9f6023b8312e39d1588f255c7c464a66cbd Mon Sep 17 00:00:00 2001 From: byteZorvin Date: Fri, 9 Aug 2024 14:09:37 +0530 Subject: [PATCH 45/62] deactivate tc --- src/bridge/tests/token_actions_test.cairo | 45 +++++++++++++++++++++++ tests/token_bridge_test.cairo | 7 +--- 2 files changed, 47 insertions(+), 5 deletions(-) diff --git a/src/bridge/tests/token_actions_test.cairo b/src/bridge/tests/token_actions_test.cairo index f20fe0d..4cd388f 100644 --- a/src/bridge/tests/token_actions_test.cairo +++ b/src/bridge/tests/token_actions_test.cairo @@ -31,6 +31,51 @@ pub fn mock_state_testing() -> TokenBridge::ContractState { TokenBridge::contract_state_for_testing() } +#[test] +fn deactivate_token_ok() { + let mut mock = mock_state_testing(); + let usdc_address = USDC_MOCK_ADDRESS(); + + mock.ownable.Ownable_owner.write(OWNER()); + snf::start_cheat_caller_address_global(OWNER()); + + // Setting the token active + let old_settings = mock.token_settings.read(usdc_address); + mock + .token_settings + .write(usdc_address, TokenSettings { token_status: TokenStatus::Active, ..old_settings }); + + mock.deactivate_token(usdc_address); + assert(mock.get_status(usdc_address) == TokenStatus::Deactivated, 'Token not deactivated'); +} + +#[test] +#[should_panic(expected: ('Token not active',))] +fn deactivate_token_not_active() { + let mut mock = mock_state_testing(); + let usdc_address = USDC_MOCK_ADDRESS(); + + mock.ownable.Ownable_owner.write(OWNER()); + snf::start_cheat_caller_address_global(OWNER()); + + mock.deactivate_token(usdc_address); + assert(mock.get_status(usdc_address) == TokenStatus::Deactivated, 'Token not deactivated'); +} + + +#[test] +#[should_panic(expected: ('Caller is not the owner',))] +fn deactivate_token_not_owner() { + let mut mock = mock_state_testing(); + let usdc_address = USDC_MOCK_ADDRESS(); + + mock.ownable.Ownable_owner.write(OWNER()); + snf::start_cheat_caller_address_global(snf::test_address()); + + mock.deactivate_token(usdc_address); + assert(mock.get_status(usdc_address) == TokenStatus::Deactivated, 'Token not deactivated'); +} + #[test] fn block_token_ok() { let mut mock = mock_state_testing(); diff --git a/tests/token_bridge_test.cairo b/tests/token_bridge_test.cairo index 5e95eab..545c960 100644 --- a/tests/token_bridge_test.cairo +++ b/tests/token_bridge_test.cairo @@ -83,9 +83,6 @@ fn set_appchain_bridge_not_owner() { // Set and check new bridge let new_appchain_bridge_address = contract_address_const::<'l3_bridge_address_new'>(); token_bridge_admin.set_appchain_token_bridge(new_appchain_bridge_address); - assert( - token_bridge.appchain_bridge() == new_appchain_bridge_address, 'Appchain bridge not set' - ); } @@ -97,7 +94,7 @@ fn set_max_total_balance_not_owner() { contract_address: token_bridge.contract_address }; - let usdc_address = deploy_erc20("USDC", "USDC"); + let usdc_address = USDC_MOCK_ADDRESS(); let decimals = 1000_000; token_bridge_admin.set_max_total_balance(usdc_address, 50 * decimals); } @@ -110,7 +107,7 @@ fn set_max_total_balance_ok() { contract_address: token_bridge.contract_address }; - let usdc_address = deploy_erc20("usdc", "usdc"); + let usdc_address = USDC_MOCK_ADDRESS(); let owner = OWNER(); // Cheat for the owner From eba79795aa58161bf0a4a6fd4399c9be2148755e Mon Sep 17 00:00:00 2001 From: byteZorvin Date: Fri, 9 Aug 2024 17:11:43 +0530 Subject: [PATCH 46/62] send messages tc --- src/bridge/tests/token_actions_test.cairo | 181 ++++++++++++++++++++++ src/bridge/token_bridge.cairo | 2 +- tests/token_actions_test.cairo | 18 +++ 3 files changed, 200 insertions(+), 1 deletion(-) diff --git a/src/bridge/tests/token_actions_test.cairo b/src/bridge/tests/token_actions_test.cairo index 4cd388f..d1dc618 100644 --- a/src/bridge/tests/token_actions_test.cairo +++ b/src/bridge/tests/token_actions_test.cairo @@ -2,6 +2,7 @@ use starknet_bridge::bridge::token_bridge::TokenBridge::__member_module_appchain use starknet_bridge::bridge::token_bridge::TokenBridge::TokenBridgeInternal; use starknet_bridge::bridge::token_bridge::TokenBridge::__member_module_token_settings::InternalContractMemberStateTrait as tokenSettingsStateTrait; use snforge_std as snf; +use snforge_std::ContractClassTrait; use starknet::{ContractAddress, storage::StorageMemberAccessTrait}; use starknet_bridge::mocks::{ messaging::{IMockMessagingDispatcherTrait, IMockMessagingDispatcher}, erc20::ERC20 @@ -17,7 +18,9 @@ use openzeppelin::access::ownable::{ OwnableComponent, OwnableComponent::Event as OwnableEvent, interface::{IOwnableTwoStepDispatcher, IOwnableTwoStepDispatcherTrait} }; +use starknet_bridge::bridge::tests::utils::message_payloads; use starknet::contract_address::{contract_address_const}; +use starknet_bridge::constants; use starknet_bridge::bridge::tests::constants::{ OWNER, L3_BRIDGE_ADDRESS, USDC_MOCK_ADDRESS, DELAY_TIME @@ -31,6 +34,19 @@ 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(); @@ -252,6 +268,61 @@ fn enroll_token_blocked() { } +#[test] +fn consume_message_ok() { + let mut mock = mock_state_testing(); + let usdc_address = USDC_MOCK_ADDRESS(); + + // Deploy messaging mock with 5 days cancellation delay + let messaging_mock_class_hash = snf::declare("messaging_mock").unwrap(); + // Deploying with 5 days as the delay time (5 * 86400 = 432000) + let (messaging_contract_address, _) = messaging_mock_class_hash + .deploy(@array![DELAY_TIME]) + .unwrap(); + + TokenBridge::constructor(ref mock, L3_BRIDGE_ADDRESS(), messaging_contract_address, OWNER()); + + let messaging_mock = IMockMessagingDispatcher { contract_address: messaging_contract_address }; + // Register a withdraw message from appchain to piltover + messaging_mock + .process_message_to_starknet( + L3_BRIDGE_ADDRESS(), + snf::test_address(), + message_payloads::withdraw_message_payload_from_appchain( + usdc_address, 100, snf::test_address() + ) + ); + + mock.consume_message(usdc_address, 100, snf::test_address()); +} + +#[test] +#[should_panic(expected: ('INVALID_MESSAGE_TO_CONSUME',))] +fn consume_message_no_message_ok() { + let mut mock = mock_state_testing(); + let usdc_address = USDC_MOCK_ADDRESS(); + + // Deploy messaging mock with 5 days cancellation delay + let messaging_mock_class_hash = snf::declare("messaging_mock").unwrap(); + // Deploying with 5 days as the delay time (5 * 86400 = 432000) + let (messaging_contract_address, _) = messaging_mock_class_hash + .deploy(@array![DELAY_TIME]) + .unwrap(); + + TokenBridge::constructor(ref mock, L3_BRIDGE_ADDRESS(), messaging_contract_address, OWNER()); + + mock.consume_message(usdc_address, 100, snf::test_address()); +} + +#[test] +#[should_panic(expected: ('L3 bridge not set',))] +fn consume_message_bridge_unset() { + let mut mock = mock_state_testing(); + let usdc_address = USDC_MOCK_ADDRESS(); + + mock.consume_message(usdc_address, 100, snf::test_address()); +} + #[test] #[should_panic(expected: ('Invalid recipient',))] fn consume_message_zero_recipient() { @@ -262,3 +333,113 @@ fn consume_message_zero_recipient() { mock.consume_message(usdc_address, 100, contract_address_const::<0>()); } + +#[test] +fn send_deploy_message_ok() { + let mut mock = mock_state_testing(); + let usdc_address = deploy_erc20("USDC", "USDC"); + + // Deploy messaging mock with 5 days cancellation delay + let messaging_mock_class_hash = snf::declare("messaging_mock").unwrap(); + // Deploying with 5 days as the delay time (5 * 86400 = 432000) + let (messaging_contract_address, _) = messaging_mock_class_hash + .deploy(@array![DELAY_TIME]) + .unwrap(); + + snf::start_cheat_caller_address_global(snf::test_address()); + TokenBridge::constructor(ref mock, L3_BRIDGE_ADDRESS(), messaging_contract_address, OWNER()); + + mock.send_deploy_message(usdc_address); +} + +#[test] +#[should_panic(expected: ('L3 bridge not set',))] +fn send_deploy_message_bridge_unset() { + let mut mock = mock_state_testing(); + let usdc_address = USDC_MOCK_ADDRESS(); + + mock.send_deploy_message(usdc_address); +} + +#[test] +fn send_deposit_message_ok() { + let mut mock = mock_state_testing(); + let usdc_address = USDC_MOCK_ADDRESS(); + + // Deploy messaging mock with 5 days cancellation delay + let messaging_mock_class_hash = snf::declare("messaging_mock").unwrap(); + // Deploying with 5 days as the delay time (5 * 86400 = 432000) + let (messaging_contract_address, _) = messaging_mock_class_hash + .deploy(@array![DELAY_TIME]) + .unwrap(); + + TokenBridge::constructor(ref mock, L3_BRIDGE_ADDRESS(), messaging_contract_address, OWNER()); + + let no_message: Span = array![].span(); + mock + .send_deposit_message( + usdc_address, + 100, + snf::test_address(), + no_message, + constants::HANDLE_TOKEN_DEPOSIT_SELECTOR + ); +} + +#[test] +#[should_panic(expected: ('L3 bridge not set',))] +fn send_deposit_message_bridge_unset() { + let mut mock = mock_state_testing(); + let usdc_address = USDC_MOCK_ADDRESS(); + + let no_message: Span = array![].span(); + mock + .send_deposit_message( + usdc_address, + 100, + snf::test_address(), + no_message, + constants::HANDLE_TOKEN_DEPOSIT_SELECTOR + ); +} + + +#[test] +fn get_status_ok() { + let mut mock = mock_state_testing(); + let usdc_address = USDC_MOCK_ADDRESS(); + + assert(mock.get_status(usdc_address) == TokenStatus::Unknown, 'Incorrect status'); + + // Setting the token active + let old_settings = mock.token_settings.read(usdc_address); + mock + .token_settings + .write(usdc_address, TokenSettings { token_status: TokenStatus::Active, ..old_settings }); + + assert(mock.get_status(usdc_address) == TokenStatus::Active, 'Incorrect status'); + + // Setting the token + let old_settings = mock.token_settings.read(usdc_address); + mock + .token_settings + .write(usdc_address, TokenSettings { token_status: TokenStatus::Blocked, ..old_settings }); + + assert(mock.get_status(usdc_address) == TokenStatus::Blocked, 'Incorrect status'); +} + + +#[test] +fn is_servicing_token_ok() { + let mut mock = mock_state_testing(); + let usdc_address = USDC_MOCK_ADDRESS(); + + // Setting the token active + let old_settings = mock.token_settings.read(usdc_address); + mock + .token_settings + .write(usdc_address, TokenSettings { token_status: TokenStatus::Active, ..old_settings }); + + assert(mock.is_servicing_token(usdc_address) == true, 'Should be servicing'); +} + diff --git a/src/bridge/token_bridge.cairo b/src/bridge/token_bridge.cairo index 26833b5..3ebaadd 100644 --- a/src/bridge/token_bridge.cairo +++ b/src/bridge/token_bridge.cairo @@ -272,7 +272,7 @@ pub mod TokenBridge { #[constructor] - fn constructor( + pub fn constructor( ref self: ContractState, appchain_bridge: ContractAddress, messaging_contract: ContractAddress, diff --git a/tests/token_actions_test.cairo b/tests/token_actions_test.cairo index f7535c3..2a1bb5c 100644 --- a/tests/token_actions_test.cairo +++ b/tests/token_actions_test.cairo @@ -139,3 +139,21 @@ fn disable_withdrawal_limit_not_owner() { withdrawal_limit.is_withdrawal_limit_applied(usdc_address) == false, 'Limit not applied' ); } + +#[test] +fn is_withdrawal_limit_applied_ok() { + let (token_bridge, _) = deploy_token_bridge(); + let token_bridge_admin = ITokenBridgeAdminDispatcher { + contract_address: token_bridge.contract_address + }; + let withdrawal_limit = IWithdrawalLimitStatusDispatcher { + contract_address: token_bridge.contract_address + }; + + snf::start_cheat_caller_address(token_bridge.contract_address, OWNER()); + let usdc_address = USDC_MOCK_ADDRESS(); + token_bridge_admin.enable_withdrawal_limit(usdc_address); + snf::stop_cheat_caller_address(token_bridge.contract_address); + + assert(withdrawal_limit.is_withdrawal_limit_applied(usdc_address), 'Limit not applied'); +} From 31b429b6ba75a9fe307c5983b888ee91a6d94e8e Mon Sep 17 00:00:00 2001 From: byteZorvin Date: Fri, 9 Aug 2024 19:09:47 +0530 Subject: [PATCH 47/62] change name --- src/bridge/tests/token_actions_test.cairo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bridge/tests/token_actions_test.cairo b/src/bridge/tests/token_actions_test.cairo index d1dc618..15362ca 100644 --- a/src/bridge/tests/token_actions_test.cairo +++ b/src/bridge/tests/token_actions_test.cairo @@ -298,7 +298,7 @@ fn consume_message_ok() { #[test] #[should_panic(expected: ('INVALID_MESSAGE_TO_CONSUME',))] -fn consume_message_no_message_ok() { +fn consume_message_no_message() { let mut mock = mock_state_testing(); let usdc_address = USDC_MOCK_ADDRESS(); From 0eb7ebf51e4598fcba4d358996c75759d7c582ec Mon Sep 17 00:00:00 2001 From: byteZorvin Date: Fri, 9 Aug 2024 19:10:18 +0530 Subject: [PATCH 48/62] withdrawal limit tests initialised --- src/lib.cairo | 6 ++ src/withdrawal_limit/mock.cairo | 60 +++++++++++++++++++ .../tests/withdrawal_limit_test.cairo | 36 +++++++++++ 3 files changed, 102 insertions(+) create mode 100644 src/withdrawal_limit/mock.cairo create mode 100644 src/withdrawal_limit/tests/withdrawal_limit_test.cairo diff --git a/src/lib.cairo b/src/lib.cairo index e646582..3e42fcb 100644 --- a/src/lib.cairo +++ b/src/lib.cairo @@ -24,6 +24,12 @@ pub mod bridge { pub mod withdrawal_limit { pub mod component; pub mod interface; + pub mod mock; + + #[cfg(test)] + mod tests { + mod withdrawal_limit_test; + } } pub mod constants; diff --git a/src/withdrawal_limit/mock.cairo b/src/withdrawal_limit/mock.cairo new file mode 100644 index 0000000..092d72a --- /dev/null +++ b/src/withdrawal_limit/mock.cairo @@ -0,0 +1,60 @@ +use starknet::ContractAddress; + +#[starknet::interface] +pub trait IMockWithdrawalLimit { + fn change_withdrawal_limit_token(ref self: TState, token: ContractAddress, is_applied: bool); +} + +#[starknet::contract] +mod withdrawal_limit_mock { + 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)] + enum Event { + #[flat] + WithdrawalEvent: WithdrawalLimitComponent::Event, + } + + #[constructor] + fn constructor(ref self: ContractState) {} + + + #[abi(embed_v0)] + impl MockWithdrawalLimitImpl of super::IMockWithdrawalLimit { + fn change_withdrawal_limit_token( + ref self: ContractState, token: ContractAddress, is_applied: bool + ) { + self.limits.write(token, is_applied); + } + } + + #[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/tests/withdrawal_limit_test.cairo b/src/withdrawal_limit/tests/withdrawal_limit_test.cairo new file mode 100644 index 0000000..5bcb1ba --- /dev/null +++ b/src/withdrawal_limit/tests/withdrawal_limit_test.cairo @@ -0,0 +1,36 @@ +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::withdrawal_limit::{ + mock::{IMockWithdrawalLimitDispatcher, IMockWithdrawalLimitDispatcherTrait}, + interface::{IWithdrawalLimit, IWithdrawalLimitDispatcher, IWithdrawalLimitDispatcherTrait,} +}; + +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 = USDC_MOCK_ADDRESS(); + let withdrawal_limit_mock = IMockWithdrawalLimitDispatcher { + contract_address: withdrawal_limit.contract_address + }; + + withdrawal_limit_mock.change_withdrawal_limit_token(usdc_address, true); +} From 84a1640f2d1e91ec60b3fe383ccb858913a08dce Mon Sep 17 00:00:00 2001 From: byteZorvin Date: Tue, 13 Aug 2024 15:25:44 +0530 Subject: [PATCH 49/62] fix build failure --- tests/lib.cairo | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/lib.cairo b/tests/lib.cairo index b2e9b8d..6c2b38c 100644 --- a/tests/lib.cairo +++ b/tests/lib.cairo @@ -2,7 +2,6 @@ mod token_bridge_test; use starknet_bridge::bridge::tests::constants; mod setup; mod withdrawal_limit_bridge_test; -mod token_actions_test; mod enroll_token_test; mod deposit_test; mod withdraw_test; From f2e0765e56f08952a0cca4ac0489b3bee7ec6bec Mon Sep 17 00:00:00 2001 From: byteZorvin Date: Tue, 13 Aug 2024 23:00:23 +0530 Subject: [PATCH 50/62] remaining quota --- src/bridge/token_bridge.cairo | 1 + src/withdrawal_limit/component.cairo | 7 ++ src/withdrawal_limit/mock.cairo | 12 ++- .../tests/withdrawal_limit_test.cairo | 79 ++++++++++++++++++- 4 files changed, 94 insertions(+), 5 deletions(-) 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/withdrawal_limit/component.cairo b/src/withdrawal_limit/component.cairo index e2f600b..e66bd18 100644 --- a/src/withdrawal_limit/component.cairo +++ b/src/withdrawal_limit/component.cairo @@ -45,6 +45,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 +58,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 diff --git a/src/withdrawal_limit/mock.cairo b/src/withdrawal_limit/mock.cairo index 092d72a..4c84c70 100644 --- a/src/withdrawal_limit/mock.cairo +++ b/src/withdrawal_limit/mock.cairo @@ -3,10 +3,12 @@ use starknet::ContractAddress; #[starknet::interface] pub trait IMockWithdrawalLimit { fn change_withdrawal_limit_token(ref self: TState, token: ContractAddress, is_applied: bool); + fn consume_quota(ref self: TState, token: ContractAddress, amount: u256); } #[starknet::contract] -mod withdrawal_limit_mock { +pub mod withdrawal_limit_mock { + use starknet_bridge::withdrawal_limit::component::WithdrawalLimitComponent::InternalTrait; use starknet_bridge::withdrawal_limit::{ component::WithdrawalLimitComponent, interface::{IWithdrawalLimitDispatcher, IWithdrawalLimitDispatcherTrait, IWithdrawalLimit} @@ -39,7 +41,9 @@ mod withdrawal_limit_mock { } #[constructor] - fn constructor(ref self: ContractState) {} + pub fn constructor(ref self: ContractState) { + self.withdrawal.initialize(5); + } #[abi(embed_v0)] @@ -49,6 +53,10 @@ mod withdrawal_limit_mock { ) { self.limits.write(token, is_applied); } + + fn consume_quota(ref self: ContractState, token: ContractAddress, amount: u256) { + self.withdrawal.consume_withdrawal_quota(token, amount); + } } #[abi(embed_v0)] diff --git a/src/withdrawal_limit/tests/withdrawal_limit_test.cairo b/src/withdrawal_limit/tests/withdrawal_limit_test.cairo index 5bcb1ba..29c05dc 100644 --- a/src/withdrawal_limit/tests/withdrawal_limit_test.cairo +++ b/src/withdrawal_limit/tests/withdrawal_limit_test.cairo @@ -1,15 +1,19 @@ +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::withdrawal_limit::{ - mock::{IMockWithdrawalLimitDispatcher, IMockWithdrawalLimitDispatcherTrait}, + mock::{ + withdrawal_limit_mock, IMockWithdrawalLimitDispatcher, IMockWithdrawalLimitDispatcherTrait + }, interface::{IWithdrawalLimit, IWithdrawalLimitDispatcher, IWithdrawalLimitDispatcherTrait,} }; +use openzeppelin::token::erc20::interface::{IERC20, IERC20Dispatcher, IERC20DispatcherTrait}; fn deploy_withdrawal_limit() -> (IWithdrawalLimitDispatcher, EventSpy) { let withdrawal_limit_mock_class_hash = snf::declare("withdrawal_limit_mock").unwrap(); @@ -24,13 +28,82 @@ fn deploy_withdrawal_limit() -> (IWithdrawalLimitDispatcher, EventSpy) { (withdrawal_limit_mock, spy) } + +pub 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(); + + let usdc_token = IERC20Dispatcher { contract_address: usdc }; + + // Transfering usdc to test address for testing + snf::start_cheat_caller_address(usdc, OWNER()); + usdc_token.transfer(snf::test_address(), 1000_000_000); + snf::stop_cheat_caller_address(usdc); + + return usdc; +} + +fn mock_component_state() -> withdrawal_limit_mock::ContractState { + let mut mock = withdrawal_limit_mock::contract_state_for_testing(); + + withdrawal_limit_mock::constructor(ref mock); + return mock; +} + #[test] fn get_remaining_withdrawal_quota_ok() { let (withdrawal_limit, _) = deploy_withdrawal_limit(); - let usdc_address = USDC_MOCK_ADDRESS(); + + let usdc_address = deploy_erc20("USDC", "USDC"); + let usdc = IERC20Dispatcher { contract_address: usdc_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 }; + assert( + withdrawal_limit.get_remaining_withdrawal_quota(usdc_address) == BoundedInt::max(), + 'Quota should be 0' + ); withdrawal_limit_mock.change_withdrawal_limit_token(usdc_address, true); + + assert( + withdrawal_limit.get_remaining_withdrawal_quota(usdc_address) == 5000_0, + 'Quota should not be 0' + ); } + +#[test] +fn consume_withdrawal_quota_ok() { + let (withdrawal_limit, _) = deploy_withdrawal_limit(); + + let usdc_address = deploy_erc20("USDC", "USDC"); + let usdc = IERC20Dispatcher { contract_address: usdc_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 + }; + + assert( + withdrawal_limit.get_remaining_withdrawal_quota(usdc_address) == BoundedInt::max(), + 'Quota should be 0' + ); + withdrawal_limit_mock.change_withdrawal_limit_token(usdc_address, true); + + assert( + withdrawal_limit.get_remaining_withdrawal_quota(usdc_address) == 5000_0, + 'Quota should not be 0' + ); +} + From 4e9e30f30fd5fb3ec5eeef72c4111f680587bebf Mon Sep 17 00:00:00 2001 From: byteZorvin Date: Wed, 14 Aug 2024 15:48:34 +0530 Subject: [PATCH 51/62] withdrawal tests --- src/withdrawal_limit/component.cairo | 18 ++- src/withdrawal_limit/mock.cairo | 12 +- .../tests/withdrawal_limit_test.cairo | 135 ++++++++++++++++-- 3 files changed, 151 insertions(+), 14 deletions(-) diff --git a/src/withdrawal_limit/component.cairo b/src/withdrawal_limit/component.cairo index e66bd18..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< @@ -72,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. @@ -125,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/mock.cairo b/src/withdrawal_limit/mock.cairo index 4c84c70..4bfe0fe 100644 --- a/src/withdrawal_limit/mock.cairo +++ b/src/withdrawal_limit/mock.cairo @@ -4,6 +4,8 @@ use starknet::ContractAddress; pub trait IMockWithdrawalLimit { fn change_withdrawal_limit_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] @@ -35,7 +37,7 @@ pub mod withdrawal_limit_mock { #[event] #[derive(Drop, starknet::Event)] - enum Event { + pub enum Event { #[flat] WithdrawalEvent: WithdrawalLimitComponent::Event, } @@ -57,6 +59,14 @@ pub mod withdrawal_limit_mock { 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)] diff --git a/src/withdrawal_limit/tests/withdrawal_limit_test.cairo b/src/withdrawal_limit/tests/withdrawal_limit_test.cairo index 29c05dc..6d7c1c7 100644 --- a/src/withdrawal_limit/tests/withdrawal_limit_test.cairo +++ b/src/withdrawal_limit/tests/withdrawal_limit_test.cairo @@ -9,9 +9,14 @@ use starknet_bridge::bridge::tests::constants::{ }; use starknet_bridge::withdrawal_limit::{ mock::{ - withdrawal_limit_mock, IMockWithdrawalLimitDispatcher, IMockWithdrawalLimitDispatcherTrait + withdrawal_limit_mock, withdrawal_limit_mock::Event::WithdrawalEvent, + IMockWithdrawalLimitDispatcher, IMockWithdrawalLimitDispatcherTrait }, - interface::{IWithdrawalLimit, IWithdrawalLimitDispatcher, IWithdrawalLimitDispatcherTrait,} + interface::{IWithdrawalLimit, IWithdrawalLimitDispatcher, IWithdrawalLimitDispatcherTrait} +}; +use starknet_bridge::withdrawal_limit::component::{ + WithdrawalLimitComponent, + WithdrawalLimitComponent::{RemainingQuotaUpdated, DailyWithdrawalPercentageUpdated} }; use openzeppelin::token::erc20::interface::{IERC20, IERC20Dispatcher, IERC20DispatcherTrait}; @@ -50,13 +55,6 @@ pub fn deploy_erc20(name: ByteArray, symbol: ByteArray) -> ContractAddress { return usdc; } -fn mock_component_state() -> withdrawal_limit_mock::ContractState { - let mut mock = withdrawal_limit_mock::contract_state_for_testing(); - - withdrawal_limit_mock::constructor(ref mock); - return mock; -} - #[test] fn get_remaining_withdrawal_quota_ok() { let (withdrawal_limit, _) = deploy_withdrawal_limit(); @@ -70,12 +68,14 @@ fn get_remaining_withdrawal_quota_ok() { contract_address: withdrawal_limit.contract_address }; + // Should return 0 when withdrawal limit not applied assert( withdrawal_limit.get_remaining_withdrawal_quota(usdc_address) == BoundedInt::max(), 'Quota should be 0' ); withdrawal_limit_mock.change_withdrawal_limit_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) == 5000_0, 'Quota should not be 0' @@ -84,6 +84,46 @@ fn get_remaining_withdrawal_quota_ok() { #[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 }; + // 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.change_withdrawal_limit_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 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"); @@ -95,15 +135,88 @@ fn consume_withdrawal_quota_ok() { contract_address: withdrawal_limit.contract_address }; + withdrawal_limit_mock.change_withdrawal_limit_token(usdc_address, true); + assert( - withdrawal_limit.get_remaining_withdrawal_quota(usdc_address) == BoundedInt::max(), - 'Quota should be 0' + 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 }; + // 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.change_withdrawal_limit_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); } From 86dfa691f7dc0216d99ea350b53abddf17508441 Mon Sep 17 00:00:00 2001 From: Mehul Chauhan Date: Thu, 15 Aug 2024 17:25:28 +0530 Subject: [PATCH 52/62] Update src/withdrawal_limit/mock.cairo Co-authored-by: Apoorv Sadana <95699312+apoorvsadana@users.noreply.github.com> --- src/withdrawal_limit/mock.cairo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/withdrawal_limit/mock.cairo b/src/withdrawal_limit/mock.cairo index 4bfe0fe..e345df4 100644 --- a/src/withdrawal_limit/mock.cairo +++ b/src/withdrawal_limit/mock.cairo @@ -50,7 +50,7 @@ pub mod withdrawal_limit_mock { #[abi(embed_v0)] impl MockWithdrawalLimitImpl of super::IMockWithdrawalLimit { - fn change_withdrawal_limit_token( + fn toggle_withdrawal_limit_for_token( ref self: ContractState, token: ContractAddress, is_applied: bool ) { self.limits.write(token, is_applied); From 912bc4a3c69e89d37e34a516b922e2154fd2a690 Mon Sep 17 00:00:00 2001 From: Mehul Chauhan Date: Thu, 15 Aug 2024 17:25:50 +0530 Subject: [PATCH 53/62] Update src/withdrawal_limit/tests/withdrawal_limit_test.cairo Co-authored-by: Apoorv Sadana <95699312+apoorvsadana@users.noreply.github.com> --- src/withdrawal_limit/tests/withdrawal_limit_test.cairo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/withdrawal_limit/tests/withdrawal_limit_test.cairo b/src/withdrawal_limit/tests/withdrawal_limit_test.cairo index 6d7c1c7..19682e9 100644 --- a/src/withdrawal_limit/tests/withdrawal_limit_test.cairo +++ b/src/withdrawal_limit/tests/withdrawal_limit_test.cairo @@ -62,7 +62,7 @@ fn get_remaining_withdrawal_quota_ok() { let usdc_address = deploy_erc20("USDC", "USDC"); let usdc = IERC20Dispatcher { contract_address: usdc_address }; // Mocking deposits with the contract - usdc.transfer(withdrawal_limit.contract_address, 1000_000); + usdc.transfer(withdrawal_limit.contract_address, 1_000_000); let withdrawal_limit_mock = IMockWithdrawalLimitDispatcher { contract_address: withdrawal_limit.contract_address From 52c154bf0e0d15351a3b66facf85abacdf388fd0 Mon Sep 17 00:00:00 2001 From: Mehul Chauhan Date: Thu, 15 Aug 2024 17:26:03 +0530 Subject: [PATCH 54/62] Update src/withdrawal_limit/tests/withdrawal_limit_test.cairo Co-authored-by: Apoorv Sadana <95699312+apoorvsadana@users.noreply.github.com> --- src/withdrawal_limit/tests/withdrawal_limit_test.cairo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/withdrawal_limit/tests/withdrawal_limit_test.cairo b/src/withdrawal_limit/tests/withdrawal_limit_test.cairo index 19682e9..ea60b1c 100644 --- a/src/withdrawal_limit/tests/withdrawal_limit_test.cairo +++ b/src/withdrawal_limit/tests/withdrawal_limit_test.cairo @@ -68,7 +68,7 @@ fn get_remaining_withdrawal_quota_ok() { contract_address: withdrawal_limit.contract_address }; - // Should return 0 when withdrawal limit not applied + // Should return BoundedInt::max() when withdrawal limit not applied assert( withdrawal_limit.get_remaining_withdrawal_quota(usdc_address) == BoundedInt::max(), 'Quota should be 0' From 930aaa94963a56c3ca66844617f1bbe598dc1e5d Mon Sep 17 00:00:00 2001 From: Mehul Chauhan Date: Thu, 15 Aug 2024 17:26:09 +0530 Subject: [PATCH 55/62] Update src/withdrawal_limit/tests/withdrawal_limit_test.cairo Co-authored-by: Apoorv Sadana <95699312+apoorvsadana@users.noreply.github.com> --- src/withdrawal_limit/tests/withdrawal_limit_test.cairo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/withdrawal_limit/tests/withdrawal_limit_test.cairo b/src/withdrawal_limit/tests/withdrawal_limit_test.cairo index ea60b1c..e7a01ef 100644 --- a/src/withdrawal_limit/tests/withdrawal_limit_test.cairo +++ b/src/withdrawal_limit/tests/withdrawal_limit_test.cairo @@ -71,7 +71,7 @@ fn get_remaining_withdrawal_quota_ok() { // Should return BoundedInt::max() when withdrawal limit not applied assert( withdrawal_limit.get_remaining_withdrawal_quota(usdc_address) == BoundedInt::max(), - 'Quota should be 0' + 'Quota should be BoundedInt::max()' ); withdrawal_limit_mock.change_withdrawal_limit_token(usdc_address, true); From 079ba0ca7885d86281d5badc7fcfb8dce4d81b27 Mon Sep 17 00:00:00 2001 From: Mehul Chauhan Date: Fri, 16 Aug 2024 12:49:41 +0530 Subject: [PATCH 56/62] should fail if message not registered (#12) --- src/lib.cairo | 1 + src/mocks/messaging_malicious.cairo | 56 +++++++++++++++++++++++++++++ tests/enroll_token_test.cairo | 31 ++++++++++++++++ 3 files changed, 88 insertions(+) create mode 100644 src/mocks/messaging_malicious.cairo diff --git a/src/lib.cairo b/src/lib.cairo index 26bc487..4e94b2d 100644 --- a/src/lib.cairo +++ b/src/lib.cairo @@ -38,6 +38,7 @@ pub mod constants; pub mod mocks { pub mod erc20; pub mod messaging; + pub mod messaging_malicious; 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/tests/enroll_token_test.cairo b/tests/enroll_token_test.cairo index 90b7a06..9e13cea 100644 --- a/tests/enroll_token_test.cairo +++ b/tests/enroll_token_test.cairo @@ -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); +} + From c9a13ccdee6611754b356b0719c19b5bef3abe8d Mon Sep 17 00:00:00 2001 From: byteZorvin Date: Fri, 16 Aug 2024 12:58:27 +0530 Subject: [PATCH 57/62] resolve commits --- src/withdrawal_limit/mock.cairo | 4 +++- src/withdrawal_limit/tests/withdrawal_limit_test.cairo | 10 +++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/withdrawal_limit/mock.cairo b/src/withdrawal_limit/mock.cairo index e345df4..ea1f31d 100644 --- a/src/withdrawal_limit/mock.cairo +++ b/src/withdrawal_limit/mock.cairo @@ -2,7 +2,9 @@ use starknet::ContractAddress; #[starknet::interface] pub trait IMockWithdrawalLimit { - fn change_withdrawal_limit_token(ref self: TState, token: ContractAddress, is_applied: bool); + 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; diff --git a/src/withdrawal_limit/tests/withdrawal_limit_test.cairo b/src/withdrawal_limit/tests/withdrawal_limit_test.cairo index e7a01ef..b42c543 100644 --- a/src/withdrawal_limit/tests/withdrawal_limit_test.cairo +++ b/src/withdrawal_limit/tests/withdrawal_limit_test.cairo @@ -71,9 +71,9 @@ fn get_remaining_withdrawal_quota_ok() { // Should return BoundedInt::max() when withdrawal limit not applied assert( withdrawal_limit.get_remaining_withdrawal_quota(usdc_address) == BoundedInt::max(), - 'Quota should be BoundedInt::max()' + 'Quota is not BoundedInt::max()' ); - withdrawal_limit_mock.change_withdrawal_limit_token(usdc_address, true); + 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( @@ -95,7 +95,7 @@ fn consume_withdrawal_quota_ok() { contract_address: withdrawal_limit.contract_address }; - withdrawal_limit_mock.change_withdrawal_limit_token(usdc_address, true); + withdrawal_limit_mock.toggle_withdrawal_limit_for_token(usdc_address, true); assert( withdrawal_limit.get_remaining_withdrawal_quota(usdc_address) == 5000_0, @@ -135,7 +135,7 @@ fn consume_withdrawal_quota_limit_exceeded() { contract_address: withdrawal_limit.contract_address }; - withdrawal_limit_mock.change_withdrawal_limit_token(usdc_address, true); + withdrawal_limit_mock.toggle_withdrawal_limit_for_token(usdc_address, true); assert( withdrawal_limit.get_remaining_withdrawal_quota(usdc_address) == 5000_0, @@ -157,7 +157,7 @@ fn get_remaining_withdrawal_quota_should_reset_after_1_day_ok() { contract_address: withdrawal_limit.contract_address }; - withdrawal_limit_mock.change_withdrawal_limit_token(usdc_address, true); + withdrawal_limit_mock.toggle_withdrawal_limit_for_token(usdc_address, true); assert( withdrawal_limit.get_remaining_withdrawal_quota(usdc_address) == 5000_0, From adf45753412c288cb754671ba9cb20a29248f112 Mon Sep 17 00:00:00 2001 From: Mehul Chauhan Date: Fri, 16 Aug 2024 12:58:53 +0530 Subject: [PATCH 58/62] Update src/withdrawal_limit/tests/withdrawal_limit_test.cairo Co-authored-by: Apoorv Sadana <95699312+apoorvsadana@users.noreply.github.com> --- src/withdrawal_limit/tests/withdrawal_limit_test.cairo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/withdrawal_limit/tests/withdrawal_limit_test.cairo b/src/withdrawal_limit/tests/withdrawal_limit_test.cairo index b42c543..8b4520f 100644 --- a/src/withdrawal_limit/tests/withdrawal_limit_test.cairo +++ b/src/withdrawal_limit/tests/withdrawal_limit_test.cairo @@ -77,7 +77,7 @@ fn get_remaining_withdrawal_quota_ok() { // Should return the default 5% of the balance of contract when limit applied assert( - withdrawal_limit.get_remaining_withdrawal_quota(usdc_address) == 5000_0, + withdrawal_limit.get_remaining_withdrawal_quota(usdc_address) == 50_000, 'Quota should not be 0' ); } From 16cac78165833ed28b850c7d4ef17bd51f8ac644 Mon Sep 17 00:00:00 2001 From: Mehul Chauhan Date: Fri, 16 Aug 2024 12:58:59 +0530 Subject: [PATCH 59/62] Update src/withdrawal_limit/tests/withdrawal_limit_test.cairo Co-authored-by: Apoorv Sadana <95699312+apoorvsadana@users.noreply.github.com> --- src/withdrawal_limit/tests/withdrawal_limit_test.cairo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/withdrawal_limit/tests/withdrawal_limit_test.cairo b/src/withdrawal_limit/tests/withdrawal_limit_test.cairo index 8b4520f..56ed7f4 100644 --- a/src/withdrawal_limit/tests/withdrawal_limit_test.cairo +++ b/src/withdrawal_limit/tests/withdrawal_limit_test.cairo @@ -101,7 +101,7 @@ fn consume_withdrawal_quota_ok() { withdrawal_limit.get_remaining_withdrawal_quota(usdc_address) == 5000_0, 'Quota should not be 0' ); - withdrawal_limit_mock.consume_quota(usdc_address, 10000); + withdrawal_limit_mock.consume_quota(usdc_address, 10_000); // The daily quota should reduce by the exact amount after consumption assert( From cac5ff0c7c41fcc098743e50be73ad8a5feb88ce Mon Sep 17 00:00:00 2001 From: byteZorvin Date: Mon, 19 Aug 2024 10:04:21 +0530 Subject: [PATCH 60/62] move file to mocks --- src/lib.cairo | 2 +- .../withdrawal_limit_mock.cairo} | 0 .../tests/withdrawal_limit_test.cairo | 14 ++++++++------ 3 files changed, 9 insertions(+), 7 deletions(-) rename src/{withdrawal_limit/mock.cairo => mocks/withdrawal_limit_mock.cairo} (100%) diff --git a/src/lib.cairo b/src/lib.cairo index 4e94b2d..0a9f4ef 100644 --- a/src/lib.cairo +++ b/src/lib.cairo @@ -25,7 +25,6 @@ pub mod bridge { pub mod withdrawal_limit { pub mod component; pub mod interface; - pub mod mock; #[cfg(test)] mod tests { @@ -39,6 +38,7 @@ 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/withdrawal_limit/mock.cairo b/src/mocks/withdrawal_limit_mock.cairo similarity index 100% rename from src/withdrawal_limit/mock.cairo rename to src/mocks/withdrawal_limit_mock.cairo diff --git a/src/withdrawal_limit/tests/withdrawal_limit_test.cairo b/src/withdrawal_limit/tests/withdrawal_limit_test.cairo index 56ed7f4..86e5105 100644 --- a/src/withdrawal_limit/tests/withdrawal_limit_test.cairo +++ b/src/withdrawal_limit/tests/withdrawal_limit_test.cairo @@ -7,12 +7,14 @@ use snforge_std::{ use starknet_bridge::bridge::tests::constants::{ OWNER, L3_BRIDGE_ADDRESS, USDC_MOCK_ADDRESS, DELAY_TIME }; -use starknet_bridge::withdrawal_limit::{ - mock::{ - withdrawal_limit_mock, withdrawal_limit_mock::Event::WithdrawalEvent, - IMockWithdrawalLimitDispatcher, IMockWithdrawalLimitDispatcherTrait - }, - interface::{IWithdrawalLimit, IWithdrawalLimitDispatcher, IWithdrawalLimitDispatcherTrait} +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, From 584607cc2ef2a4beadb5bdcb2586d044cb20eab6 Mon Sep 17 00:00:00 2001 From: byteZorvin Date: Tue, 20 Aug 2024 09:52:04 +0530 Subject: [PATCH 61/62] code repetition reduced --- src/bridge/tests/messaging_test.cairo | 22 +----------------- src/bridge/tests/token_actions_test.cairo | 22 +----------------- {tests => src/bridge/tests/utils}/setup.cairo | 12 +++++++++- src/lib.cairo | 1 + .../tests/withdrawal_limit_test.cairo | 23 ++----------------- tests/deposit_reclaim_test.cairo | 2 +- tests/deposit_test.cairo | 2 +- tests/enroll_token_test.cairo | 2 +- tests/lib.cairo | 1 - tests/token_bridge_test.cairo | 2 +- tests/withdraw_test.cairo | 2 +- tests/withdrawal_limit_bridge_test.cairo | 2 +- 12 files changed, 22 insertions(+), 71 deletions(-) rename {tests => src/bridge/tests/utils}/setup.cairo (91%) 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 91% rename from tests/setup.cairo rename to src/bridge/tests/utils/setup.cairo index 8ccaede..9a8cc3b 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; @@ -44,6 +46,14 @@ pub fn deploy_erc20(name: ByteArray, symbol: ByteArray) -> ContractAddress { return usdc; } +/// 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() +} + + pub fn deploy_token_bridge_with_messaging() -> ( ITokenBridgeDispatcher, EventSpy, IMockMessagingDispatcher ) { diff --git a/src/lib.cairo b/src/lib.cairo index 0a9f4ef..e24179b 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; } } diff --git a/src/withdrawal_limit/tests/withdrawal_limit_test.cairo b/src/withdrawal_limit/tests/withdrawal_limit_test.cairo index 86e5105..efbe5cb 100644 --- a/src/withdrawal_limit/tests/withdrawal_limit_test.cairo +++ b/src/withdrawal_limit/tests/withdrawal_limit_test.cairo @@ -21,6 +21,8 @@ use starknet_bridge::withdrawal_limit::component::{ 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(); @@ -36,27 +38,6 @@ fn deploy_withdrawal_limit() -> (IWithdrawalLimitDispatcher, EventSpy) { } -pub 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(); - - let usdc_token = IERC20Dispatcher { contract_address: usdc }; - - // Transfering usdc to test address for testing - snf::start_cheat_caller_address(usdc, OWNER()); - usdc_token.transfer(snf::test_address(), 1000_000_000); - snf::stop_cheat_caller_address(usdc); - - return usdc; -} - #[test] fn get_remaining_withdrawal_quota_ok() { let (withdrawal_limit, _) = deploy_withdrawal_limit(); 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 9e13cea..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; 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] From 1e519064edb43b76491aa623a2cff707ac3d98d9 Mon Sep 17 00:00:00 2001 From: byteZorvin Date: Tue, 20 Aug 2024 10:10:53 +0530 Subject: [PATCH 62/62] failing tests fixed --- src/bridge/tests/utils/setup.cairo | 8 ------- src/lib.cairo | 2 +- .../tests/withdrawal_limit_test.cairo | 24 ++++++++++++++++++- 3 files changed, 24 insertions(+), 10 deletions(-) diff --git a/src/bridge/tests/utils/setup.cairo b/src/bridge/tests/utils/setup.cairo index 9a8cc3b..5017086 100644 --- a/src/bridge/tests/utils/setup.cairo +++ b/src/bridge/tests/utils/setup.cairo @@ -46,14 +46,6 @@ pub fn deploy_erc20(name: ByteArray, symbol: ByteArray) -> ContractAddress { return usdc; } -/// 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() -} - - pub fn deploy_token_bridge_with_messaging() -> ( ITokenBridgeDispatcher, EventSpy, IMockMessagingDispatcher ) { diff --git a/src/lib.cairo b/src/lib.cairo index e24179b..07f663d 100644 --- a/src/lib.cairo +++ b/src/lib.cairo @@ -10,7 +10,7 @@ pub mod bridge { mod messaging_test; pub mod utils { pub mod message_payloads; - pub mod setup; + pub mod setup; } } diff --git a/src/withdrawal_limit/tests/withdrawal_limit_test.cairo b/src/withdrawal_limit/tests/withdrawal_limit_test.cairo index efbe5cb..2f8ac3d 100644 --- a/src/withdrawal_limit/tests/withdrawal_limit_test.cairo +++ b/src/withdrawal_limit/tests/withdrawal_limit_test.cairo @@ -44,6 +44,12 @@ fn get_remaining_withdrawal_quota_ok() { 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); @@ -71,6 +77,12 @@ fn consume_withdrawal_quota_ok() { 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); @@ -111,6 +123,11 @@ fn consume_withdrawal_quota_limit_exceeded() { 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); @@ -133,9 +150,14 @@ fn get_remaining_withdrawal_quota_should_reset_after_1_day_ok() { 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 };