Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Withdrawal tests #11

Merged
merged 71 commits into from
Aug 20, 2024
Merged
Show file tree
Hide file tree
Changes from 60 commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
2e79cf8
feat: initiliased testcases
byteZorvin Jul 22, 2024
3a0db04
admin function tests
byteZorvin Jul 29, 2024
a2e6ada
fix: max total balance check
byteZorvin Jul 29, 2024
ac258c1
feat: block token test
byteZorvin Jul 29, 2024
d64eb7f
disable limit test
byteZorvin Jul 30, 2024
19d7fb0
feat: add failing tc for withdraw limit
byteZorvin Jul 30, 2024
b84a398
fixed testcases after rebase
byteZorvin Jul 30, 2024
c248850
chore: added messaging mock
byteZorvin Jul 31, 2024
7a3b3f8
Update src/bridge/token_bridge.cairo
byteZorvin Jul 31, 2024
4cf51a9
resolve comments
byteZorvin Jul 31, 2024
091f4d4
add reactivate and unblock
byteZorvin Jul 31, 2024
2d9e963
add reactivate and unblock
byteZorvin Jul 31, 2024
6b49de0
Merge branch 're-enroll' of https://github.com/karnotxyz/starknet_bri…
byteZorvin Jul 31, 2024
8523be2
unblock tests
byteZorvin Jul 31, 2024
ab6e5fd
reactivate and unblock tests
byteZorvin Aug 1, 2024
8ad12e7
Merge branch 'main' into re-enroll
byteZorvin Aug 1, 2024
3b1e08f
resolved merge conflicts
byteZorvin Aug 1, 2024
91b4c03
restructure testcases
byteZorvin Aug 1, 2024
6752ad3
fix: visibility modifier
byteZorvin Aug 1, 2024
5708aa1
deposit tests
byteZorvin Aug 1, 2024
0c613d0
make them unit
byteZorvin Aug 1, 2024
0bfb32b
make them unit
byteZorvin Aug 1, 2024
18690bb
deposit flow tests
byteZorvin Aug 3, 2024
fc691b5
change to mock usdc address
byteZorvin Aug 5, 2024
02205bd
improve: not needed to deploy usdc in while mock testing
byteZorvin Aug 5, 2024
be74d26
Merge branch 're-enroll' into test-restructure
byteZorvin Aug 5, 2024
2b285d3
unit testcases
byteZorvin Aug 5, 2024
1809796
resolved merge conflicts
byteZorvin Aug 5, 2024
e36df0f
add token actions restructure
byteZorvin Aug 5, 2024
8b48d99
Merge branch 'test-restructure' into deposit-testcases
byteZorvin Aug 5, 2024
ae2f0e8
migrate to latest foundry
byteZorvin Aug 5, 2024
9600774
resolved merge conflicts
byteZorvin Aug 5, 2024
670f679
restructure
byteZorvin Aug 5, 2024
6d6b87c
deposit failing tc
byteZorvin Aug 6, 2024
1fd11b9
test: happy withdraw test
byteZorvin Aug 7, 2024
f38f877
chore: ran formatter
byteZorvin Aug 7, 2024
6f187f3
fix settlement of message
byteZorvin Aug 7, 2024
b5eedca
change deposit tests to use message_payloads
byteZorvin Aug 7, 2024
f0d0caf
add assert
byteZorvin Aug 7, 2024
ad0c073
failing withdraw tc
byteZorvin Aug 7, 2024
65dc258
cancel request
byteZorvin Aug 7, 2024
bfa4a71
deposit with message cancels
byteZorvin Aug 7, 2024
d130cac
Update tests/deposit_test.cairo
byteZorvin Aug 8, 2024
eb0280f
resolved comments
byteZorvin Aug 9, 2024
1b67140
Merge branch 'deposit-testcases' of https://github.com/karnotxyz/star…
byteZorvin Aug 9, 2024
8f7d0aa
fix consume message
byteZorvin Aug 9, 2024
7f78c0b
reclaim testcases
byteZorvin Aug 9, 2024
790f2c8
fix consume message check
byteZorvin Aug 9, 2024
d54e7dd
Merge branch 'deposit-testcases' into reclaim-tests
byteZorvin Aug 9, 2024
7de6fec
consume message
byteZorvin Aug 9, 2024
ace0850
add balance check
byteZorvin Aug 9, 2024
5d1218c
add events in actions
byteZorvin Aug 9, 2024
39b9e9f
deactivate tc
byteZorvin Aug 9, 2024
eba7979
send messages tc
byteZorvin Aug 9, 2024
31b429b
change name
byteZorvin Aug 9, 2024
0eb7ebf
withdrawal limit tests initialised
byteZorvin Aug 9, 2024
8eb609b
Merge branch 'withdrawal-limit-tests' into withdrawal-tests
byteZorvin Aug 13, 2024
84a1640
fix build failure
byteZorvin Aug 13, 2024
f2e0765
remaining quota
byteZorvin Aug 13, 2024
4e9e30f
withdrawal tests
byteZorvin Aug 14, 2024
86dfa69
Update src/withdrawal_limit/mock.cairo
byteZorvin Aug 15, 2024
912bc4a
Update src/withdrawal_limit/tests/withdrawal_limit_test.cairo
byteZorvin Aug 15, 2024
52c154b
Update src/withdrawal_limit/tests/withdrawal_limit_test.cairo
byteZorvin Aug 15, 2024
930aaa9
Update src/withdrawal_limit/tests/withdrawal_limit_test.cairo
byteZorvin Aug 15, 2024
079ba0c
should fail if message not registered (#12)
byteZorvin Aug 16, 2024
c9a13cc
resolve commits
byteZorvin Aug 16, 2024
adf4575
Update src/withdrawal_limit/tests/withdrawal_limit_test.cairo
byteZorvin Aug 16, 2024
16cac78
Update src/withdrawal_limit/tests/withdrawal_limit_test.cairo
byteZorvin Aug 16, 2024
cac5ff0
move file to mocks
byteZorvin Aug 19, 2024
584607c
code repetition reduced
byteZorvin Aug 20, 2024
1e51906
failing tests fixed
byteZorvin Aug 20, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/bridge/token_bridge.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,7 @@ pub mod TokenBridge {
self
.messaging_contract
.write(IMessagingDispatcher { contract_address: messaging_contract });
self.withdrawal.initialize(5);
self.ownable.initializer(owner);
}

Expand Down
6 changes: 6 additions & 0 deletions src/lib.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,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;
Expand Down
25 changes: 23 additions & 2 deletions src/withdrawal_limit/component.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -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<
Expand All @@ -45,6 +52,8 @@ pub mod WithdrawalLimitComponent {
return BoundedInt::max();
}
let remaining_quota = self.read_withdrawal_quota_slot(:token);

// if remaining_quota is 0 then quota is not initialised
if remaining_quota == 0 {
return self.get_daily_withdrawal_limit(:token);
}
Expand All @@ -56,6 +65,11 @@ pub mod WithdrawalLimitComponent {
pub impl InternalImpl<
TContractState, +HasComponent<TContractState>, +IWithdrawalLimitStatus<TContractState>
> of InternalTrait<TContractState> {
// This initializes the withdrawal_limit component
fn initialize(ref self: ComponentState<TContractState>, 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<TContractState>, token: ContractAddress, amount: u256
Expand All @@ -65,6 +79,8 @@ pub mod WithdrawalLimitComponent {
self
.remaining_intraday_withdraw_quota
.write((token, day), amount + constants::REMAINING_QUOTA_OFFSET);

self.emit(RemainingQuotaUpdated { token: token, day: day, new_quota: amount });
}

// Returns the remaining withdrawal quota for today.
Expand Down Expand Up @@ -118,6 +134,11 @@ pub mod WithdrawalLimitComponent {
) {
assert(daily_withdrawal_limit_pct <= 100, 'LIMIT_PCT_TOO_HIGH');
self.daily_withdrawal_limit_pct.write(daily_withdrawal_limit_pct);

self
.emit(
DailyWithdrawalPercentageUpdated { new_percentage: daily_withdrawal_limit_pct }
);
}
}
}
78 changes: 78 additions & 0 deletions src/withdrawal_limit/mock.cairo
byteZorvin marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
use starknet::ContractAddress;

#[starknet::interface]
pub trait IMockWithdrawalLimit<TState> {
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]
pub mod withdrawal_limit_mock {
use starknet_bridge::withdrawal_limit::component::WithdrawalLimitComponent::InternalTrait;
use starknet_bridge::withdrawal_limit::{
component::WithdrawalLimitComponent,
interface::{IWithdrawalLimitDispatcher, IWithdrawalLimitDispatcherTrait, IWithdrawalLimit}
};
use starknet_bridge::bridge::interface::IWithdrawalLimitStatus;
use starknet::ContractAddress;


component!(path: WithdrawalLimitComponent, storage: withdrawal, event: WithdrawalEvent);

// WithdrawalLimit
#[abi(embed_v0)]
impl WithdrawalLimitImpl =
WithdrawalLimitComponent::WithdrawalLimitImpl<ContractState>;
impl WithdrawalLimitInternal = WithdrawalLimitComponent::InternalImpl<ContractState>;


#[storage]
struct Storage {
limits: LegacyMap<ContractAddress, bool>,
#[substorage(v0)]
withdrawal: WithdrawalLimitComponent::Storage,
}

#[event]
#[derive(Drop, starknet::Event)]
pub enum Event {
#[flat]
WithdrawalEvent: WithdrawalLimitComponent::Event,
}

#[constructor]
pub fn constructor(ref self: ContractState) {
self.withdrawal.initialize(5);
}


#[abi(embed_v0)]
impl MockWithdrawalLimitImpl of super::IMockWithdrawalLimit<ContractState> {
fn change_withdrawal_limit_token(
byteZorvin marked this conversation as resolved.
Show resolved Hide resolved
ref self: ContractState, token: ContractAddress, is_applied: bool
) {
self.limits.write(token, is_applied);
}

fn consume_quota(ref self: ContractState, token: ContractAddress, amount: u256) {
self.withdrawal.consume_withdrawal_quota(token, amount);
}

fn write_daily_withdrawal_limit_pct(ref self: ContractState, limit_percent: u8) {
self.withdrawal.write_daily_withdrawal_limit_pct(limit_percent);
}

fn get_daily_withdrawal_limit_pct(self: @ContractState) -> u8 {
self.withdrawal.daily_withdrawal_limit_pct.read()
}
}

#[abi(embed_v0)]
impl WithdrawalLimitStatusImpl of IWithdrawalLimitStatus<ContractState> {
fn is_withdrawal_limit_applied(self: @ContractState, token: ContractAddress) -> bool {
self.limits.read(token)
}
}
}
222 changes: 222 additions & 0 deletions src/withdrawal_limit/tests/withdrawal_limit_test.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
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::{
withdrawal_limit_mock, withdrawal_limit_mock::Event::WithdrawalEvent,
IMockWithdrawalLimitDispatcher, IMockWithdrawalLimitDispatcherTrait
},
interface::{IWithdrawalLimit, IWithdrawalLimitDispatcher, IWithdrawalLimitDispatcherTrait}
};
use starknet_bridge::withdrawal_limit::component::{
WithdrawalLimitComponent,
WithdrawalLimitComponent::{RemainingQuotaUpdated, DailyWithdrawalPercentageUpdated}
};
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();
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)
}


pub fn deploy_erc20(name: ByteArray, symbol: ByteArray) -> ContractAddress {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we already have this function in other test cases, can we not move to utils and reuse?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did not find a way to import files from the tests/ folder into src/ so had to replicate

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you create an issue for this w/ an enhancement tag and add a todo on code as well

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();

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);
byteZorvin marked this conversation as resolved.
Show resolved Hide resolved

let withdrawal_limit_mock = IMockWithdrawalLimitDispatcher {
contract_address: withdrawal_limit.contract_address
};

// Should return 0 when withdrawal limit not applied
byteZorvin marked this conversation as resolved.
Show resolved Hide resolved
assert(
withdrawal_limit.get_remaining_withdrawal_quota(usdc_address) == BoundedInt::max(),
'Quota should be 0'
byteZorvin marked this conversation as resolved.
Show resolved Hide resolved
);
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,
byteZorvin marked this conversation as resolved.
Show resolved Hide resolved
'Quota should not be 0'
);
}

#[test]
fn consume_withdrawal_quota_ok() {
let (withdrawal_limit, mut spy) = deploy_withdrawal_limit();

let usdc_address = deploy_erc20("USDC", "USDC");
let usdc = IERC20Dispatcher { contract_address: usdc_address };
// 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);
byteZorvin marked this conversation as resolved.
Show resolved Hide resolved

// The daily quota should reduce by the exact amount after consumption
assert(
withdrawal_limit.get_remaining_withdrawal_quota(usdc_address) == 4000_0,
'Daily quota not updated'
);

let expected_event = RemainingQuotaUpdated { token: usdc_address, day: 0, new_quota: 40000 };
spy
.assert_emitted(
@array![
(
withdrawal_limit_mock.contract_address,
WithdrawalLimitComponent::Event::RemainingQuotaUpdated(expected_event)
)
]
);
}

#[test]
#[should_panic(expected: ('LIMIT_EXCEEDED',))]
fn consume_withdrawal_quota_limit_exceeded() {
let (withdrawal_limit, _) = deploy_withdrawal_limit();

let usdc_address = deploy_erc20("USDC", "USDC");
let usdc = IERC20Dispatcher { contract_address: usdc_address };
// 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, 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);
}