From 4d53b30e0a03d09c4703db565cd345fd60ef58f5 Mon Sep 17 00:00:00 2001 From: NehharShah Date: Fri, 31 Jan 2025 17:16:44 -0500 Subject: [PATCH 1/5] test cases for inter transfer --- src/interface.cairo | 6 +++ src/tokenized_bond.cairo | 58 ++++++++++----------- tests/lib.cairo | 110 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 145 insertions(+), 29 deletions(-) diff --git a/src/interface.cairo b/src/interface.cairo index c1a2be7..a90a323 100644 --- a/src/interface.cairo +++ b/src/interface.cairo @@ -30,4 +30,10 @@ pub trait ITokenizedBond { fn minter_is_operator(self: @TState, token_id: u256, minter: ContractAddress) -> bool; fn check_owner_and_operator(self: @TState, transfers: Array) -> bool; fn upgrade(ref self: TState, new_class_hash: ClassHash); + fn inter_transfer_allowed( + self: @TState, token_id: u256, sender: ContractAddress, receiver: ContractAddress, + ) -> bool; + fn is_inter_transfer_after_expiry( + self: @TState, token_id: u256, receiver: ContractAddress, + ) -> bool; } diff --git a/src/tokenized_bond.cairo b/src/tokenized_bond.cairo index 3c38934..3a17b68 100644 --- a/src/tokenized_bond.cairo +++ b/src/tokenized_bond.cairo @@ -176,6 +176,35 @@ pub mod TokenizedBond { self.pausable.unpause(); } + fn inter_transfer_allowed( + self: @ContractState, + token_id: u256, + sender: ContractAddress, + receiver: ContractAddress, + ) -> bool { + if !self.tokens.entry(token_id).read().token_itr_paused { + return true; + } + if (self.tokens.entry(token_id).read().minter == sender + || self.tokens.entry(token_id).read().minter == receiver) { + return true; + } + return false; + } + + fn is_inter_transfer_after_expiry( + self: @ContractState, token_id: u256, receiver: ContractAddress, + ) -> bool { + if !self.tokens.entry(token_id).read().token_itr_expiry_paused { + return true; + } + if self.tokens.entry(token_id).read().expiration_date > get_block_timestamp() + || self.tokens.entry(token_id).read().minter == receiver { + return true; + } + return false; + } + fn resume_inter_transfer(ref self: ContractState, token_id: u256) { self.ownable.assert_only_owner(); assert(self.tokens.entry(token_id).read().token_itr_paused, Errors::TOKEN_IS_PAUSED); @@ -478,34 +507,5 @@ pub mod TokenizedBond { Errors::TOKEN_DOES_NOT_EXIST, ); } - - fn inter_transfer_allowed( - self: @ContractState, - token_id: u256, - sender: ContractAddress, - receiver: ContractAddress, - ) -> bool { - if !self.tokens.entry(token_id).read().token_itr_paused { - return true; - } - if (self.tokens.entry(token_id).read().minter == sender - || self.tokens.entry(token_id).read().minter == receiver) { - return true; - } - return false; - } - - fn is_inter_transfer_after_expiry( - self: @ContractState, token_id: u256, receiever: ContractAddress, - ) -> bool { - if !self.tokens.entry(token_id).read().token_itr_expiry_paused { - return true; - } - if self.tokens.entry(token_id).read().expiration_date > get_block_timestamp() - || self.tokens.entry(token_id).read().minter == receiever { - return true; - } - return false; - } } } diff --git a/tests/lib.cairo b/tests/lib.cairo index f8d9182..5591e09 100644 --- a/tests/lib.cairo +++ b/tests/lib.cairo @@ -503,6 +503,7 @@ fn test_pause_itr_after_expiry() { spy.assert_emitted(@array![(tokenized_bond.contract_address, expected_tokenized_bond_event)]); } +#[test] fn test_freeze_token_success() { let mut tokenized_bond = ITokenizedBondDispatcher { contract_address: setup() }; let minter = setup_receiver(); @@ -956,3 +957,112 @@ fn test_upgrade_not_owner() { let (tokenized_bond, _minter) = setup_contract_with_minter(); tokenized_bond.upgrade(class_hash_const::<'UPGRADE'>()); } + +#[test] +fn test_inter_transfer_allowed_when_not_paused() { + let (tokenized_bond, _minter) = setup_contract_with_minter(); + let receiver = setup_receiver(); + assert( + tokenized_bond.inter_transfer_allowed(TOKEN_ID(), NOT_MINTER(), receiver), + 'Should allow when not paused', + ); +} + +#[test] +fn test_inter_transfer_allowed_when_paused_but_minter_is_sender() { + let (tokenized_bond, minter) = setup_contract_with_minter(); + let receiver = setup_receiver(); + + start_cheat_caller_address(tokenized_bond.contract_address, OWNER()); + tokenized_bond.pause_inter_transfer(TOKEN_ID()); + + assert( + tokenized_bond.inter_transfer_allowed(TOKEN_ID(), minter, receiver), + 'Allow when minter is sender', + ); +} + +#[test] +fn test_inter_transfer_allowed_when_paused_but_minter_is_receiver() { + let (tokenized_bond, minter) = setup_contract_with_minter(); + let sender = setup_receiver(); + + start_cheat_caller_address(tokenized_bond.contract_address, OWNER()); + tokenized_bond.pause_inter_transfer(TOKEN_ID()); + + assert( + tokenized_bond.inter_transfer_allowed(TOKEN_ID(), sender, minter), + 'Allow when minter is receiver', + ); +} + +#[test] +fn test_inter_transfer_allowed_when_paused_and_no_minter_involved() { + let (tokenized_bond, _minter) = setup_contract_with_minter(); + let sender = setup_receiver(); + let receiver = setup_receiver(); + + start_cheat_caller_address(tokenized_bond.contract_address, OWNER()); + tokenized_bond.pause_inter_transfer(TOKEN_ID()); + + assert( + !tokenized_bond.inter_transfer_allowed(TOKEN_ID(), sender, receiver), + 'Fail when paused without minter', + ); +} + +#[test] +fn test_is_inter_transfer_after_expiry_when_not_paused() { + let (tokenized_bond, _minter) = setup_contract_with_minter(); + let receiver = setup_receiver(); + + assert( + tokenized_bond.is_inter_transfer_after_expiry(TOKEN_ID(), receiver), + 'Should allow when not paused', + ); +} + +#[test] +fn test_is_inter_transfer_after_expiry_when_paused_but_not_expired() { + let (tokenized_bond, _minter) = setup_contract_with_minter(); + let receiver = setup_receiver(); + + start_cheat_caller_address(tokenized_bond.contract_address, OWNER()); + tokenized_bond.pause_itr_after_expiry(TOKEN_ID()); + + assert( + tokenized_bond.is_inter_transfer_after_expiry(TOKEN_ID(), receiver), + 'Should allow when not expired', + ); +} + +#[test] +fn test_is_inter_transfer_after_expiry_when_paused_expired_but_receiver_is_minter() { + let (tokenized_bond, minter) = setup_contract_with_minter(); + + start_cheat_caller_address(tokenized_bond.contract_address, OWNER()); + tokenized_bond.pause_itr_after_expiry(TOKEN_ID()); + + start_cheat_block_timestamp_global(TIME_IN_THE_FUTURE() + 1); + + assert( + tokenized_bond.is_inter_transfer_after_expiry(TOKEN_ID(), minter), + 'Allow when receiver is minter', + ); +} + +#[test] +fn test_is_inter_transfer_after_expiry_when_paused_expired_and_not_minter() { + let (tokenized_bond, _minter) = setup_contract_with_minter(); + let receiver = setup_receiver(); + + start_cheat_caller_address(tokenized_bond.contract_address, OWNER()); + tokenized_bond.pause_itr_after_expiry(TOKEN_ID()); + + start_cheat_block_timestamp_global(TIME_IN_THE_FUTURE() + 1); + + assert( + !tokenized_bond.is_inter_transfer_after_expiry(TOKEN_ID(), receiver), + 'Fail expired without minter', + ); +} \ No newline at end of file From ef8525fd64329f982e8a4bd7b0da441771082bab Mon Sep 17 00:00:00 2001 From: NehharShah Date: Fri, 31 Jan 2025 17:22:16 -0500 Subject: [PATCH 2/5] fmt --- tests/lib.cairo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/lib.cairo b/tests/lib.cairo index 5591e09..c7703a4 100644 --- a/tests/lib.cairo +++ b/tests/lib.cairo @@ -1065,4 +1065,4 @@ fn test_is_inter_transfer_after_expiry_when_paused_expired_and_not_minter() { !tokenized_bond.is_inter_transfer_after_expiry(TOKEN_ID(), receiver), 'Fail expired without minter', ); -} \ No newline at end of file +} From 09483261a3164f32052da42c43e6e7ef8a5a2f44 Mon Sep 17 00:00:00 2001 From: NehharShah Date: Mon, 3 Feb 2025 12:29:53 -0500 Subject: [PATCH 3/5] changes as per review for private fn --- src/interface.cairo | 6 --- src/tokenized_bond.cairo | 58 +++++++++++------------ tests/lib.cairo | 100 +++++++++++++++++---------------------- 3 files changed, 72 insertions(+), 92 deletions(-) diff --git a/src/interface.cairo b/src/interface.cairo index a90a323..c1a2be7 100644 --- a/src/interface.cairo +++ b/src/interface.cairo @@ -30,10 +30,4 @@ pub trait ITokenizedBond { fn minter_is_operator(self: @TState, token_id: u256, minter: ContractAddress) -> bool; fn check_owner_and_operator(self: @TState, transfers: Array) -> bool; fn upgrade(ref self: TState, new_class_hash: ClassHash); - fn inter_transfer_allowed( - self: @TState, token_id: u256, sender: ContractAddress, receiver: ContractAddress, - ) -> bool; - fn is_inter_transfer_after_expiry( - self: @TState, token_id: u256, receiver: ContractAddress, - ) -> bool; } diff --git a/src/tokenized_bond.cairo b/src/tokenized_bond.cairo index 3a17b68..0d0934f 100644 --- a/src/tokenized_bond.cairo +++ b/src/tokenized_bond.cairo @@ -176,35 +176,6 @@ pub mod TokenizedBond { self.pausable.unpause(); } - fn inter_transfer_allowed( - self: @ContractState, - token_id: u256, - sender: ContractAddress, - receiver: ContractAddress, - ) -> bool { - if !self.tokens.entry(token_id).read().token_itr_paused { - return true; - } - if (self.tokens.entry(token_id).read().minter == sender - || self.tokens.entry(token_id).read().minter == receiver) { - return true; - } - return false; - } - - fn is_inter_transfer_after_expiry( - self: @ContractState, token_id: u256, receiver: ContractAddress, - ) -> bool { - if !self.tokens.entry(token_id).read().token_itr_expiry_paused { - return true; - } - if self.tokens.entry(token_id).read().expiration_date > get_block_timestamp() - || self.tokens.entry(token_id).read().minter == receiver { - return true; - } - return false; - } - fn resume_inter_transfer(ref self: ContractState, token_id: u256) { self.ownable.assert_only_owner(); assert(self.tokens.entry(token_id).read().token_itr_paused, Errors::TOKEN_IS_PAUSED); @@ -507,5 +478,34 @@ pub mod TokenizedBond { Errors::TOKEN_DOES_NOT_EXIST, ); } + + fn inter_transfer_allowed( + self: @ContractState, + token_id: u256, + sender: ContractAddress, + receiver: ContractAddress, + ) -> bool { + if !self.tokens.entry(token_id).read().token_itr_paused { + return true; + } + if (self.tokens.entry(token_id).read().minter == sender + || self.tokens.entry(token_id).read().minter == receiver) { + return true; + } + return false; + } + + fn is_inter_transfer_after_expiry( + self: @ContractState, token_id: u256, receiver: ContractAddress, + ) -> bool { + if !self.tokens.entry(token_id).read().token_itr_expiry_paused { + return true; + } + if self.tokens.entry(token_id).read().expiration_date > get_block_timestamp() + || self.tokens.entry(token_id).read().minter == receiver { + return true; + } + return false; + } } } diff --git a/tests/lib.cairo b/tests/lib.cairo index c7703a4..940670e 100644 --- a/tests/lib.cairo +++ b/tests/lib.cairo @@ -959,110 +959,96 @@ fn test_upgrade_not_owner() { } #[test] -fn test_inter_transfer_allowed_when_not_paused() { - let (tokenized_bond, _minter) = setup_contract_with_minter(); +fn test_make_transfer_with_inter_transfer_not_paused() { + let (tokenized_bond, minter) = setup_contract_with_minter(); let receiver = setup_receiver(); - assert( - tokenized_bond.inter_transfer_allowed(TOKEN_ID(), NOT_MINTER(), receiver), - 'Should allow when not paused', - ); + let transfer = setup_transfer(from: minter, to: receiver, amount: AMOUNT_TRANSFERRED()); + + start_cheat_caller_address(tokenized_bond.contract_address, minter); + tokenized_bond.make_transfer(transfer); } + #[test] -fn test_inter_transfer_allowed_when_paused_but_minter_is_sender() { +#[should_panic(expected: 'Token ITR is paused')] +fn test_make_transfer_when_paused_neither_minter() { let (tokenized_bond, minter) = setup_contract_with_minter(); - let receiver = setup_receiver(); + let from = address_with_tokens(tokenized_bond, minter); + let to = setup_receiver(); + let transfer = setup_transfer(from, to, AMOUNT_TRANSFERRED()); start_cheat_caller_address(tokenized_bond.contract_address, OWNER()); tokenized_bond.pause_inter_transfer(TOKEN_ID()); - assert( - tokenized_bond.inter_transfer_allowed(TOKEN_ID(), minter, receiver), - 'Allow when minter is sender', - ); + start_cheat_caller_address(tokenized_bond.contract_address, from); + tokenized_bond.make_transfer(transfer); } #[test] -fn test_inter_transfer_allowed_when_paused_but_minter_is_receiver() { +fn test_make_transfer_when_paused_sender_is_minter() { let (tokenized_bond, minter) = setup_contract_with_minter(); - let sender = setup_receiver(); + let receiver = setup_receiver(); + let transfer = setup_transfer(from: minter, to: receiver, amount: AMOUNT_TRANSFERRED()); start_cheat_caller_address(tokenized_bond.contract_address, OWNER()); tokenized_bond.pause_inter_transfer(TOKEN_ID()); - assert( - tokenized_bond.inter_transfer_allowed(TOKEN_ID(), sender, minter), - 'Allow when minter is receiver', - ); + start_cheat_caller_address(tokenized_bond.contract_address, minter); + tokenized_bond.make_transfer(transfer); } #[test] -fn test_inter_transfer_allowed_when_paused_and_no_minter_involved() { - let (tokenized_bond, _minter) = setup_contract_with_minter(); - let sender = setup_receiver(); - let receiver = setup_receiver(); +fn test_make_transfer_when_paused_receiver_is_minter() { + let (tokenized_bond, minter) = setup_contract_with_minter(); + let from = address_with_tokens(tokenized_bond, minter); + let transfer = setup_transfer(from: from, to: minter, amount: AMOUNT_TRANSFERRED()); start_cheat_caller_address(tokenized_bond.contract_address, OWNER()); tokenized_bond.pause_inter_transfer(TOKEN_ID()); - assert( - !tokenized_bond.inter_transfer_allowed(TOKEN_ID(), sender, receiver), - 'Fail when paused without minter', - ); -} - -#[test] -fn test_is_inter_transfer_after_expiry_when_not_paused() { - let (tokenized_bond, _minter) = setup_contract_with_minter(); - let receiver = setup_receiver(); - - assert( - tokenized_bond.is_inter_transfer_after_expiry(TOKEN_ID(), receiver), - 'Should allow when not paused', - ); + start_cheat_caller_address(tokenized_bond.contract_address, from); + tokenized_bond.make_transfer(transfer); } #[test] -fn test_is_inter_transfer_after_expiry_when_paused_but_not_expired() { - let (tokenized_bond, _minter) = setup_contract_with_minter(); +fn test_make_transfer_before_expiry_when_expiry_paused() { + let (tokenized_bond, minter) = setup_contract_with_minter(); let receiver = setup_receiver(); + let transfer = setup_transfer(from: minter, to: receiver, amount: AMOUNT_TRANSFERRED()); start_cheat_caller_address(tokenized_bond.contract_address, OWNER()); tokenized_bond.pause_itr_after_expiry(TOKEN_ID()); - assert( - tokenized_bond.is_inter_transfer_after_expiry(TOKEN_ID(), receiver), - 'Should allow when not expired', - ); + start_cheat_caller_address(tokenized_bond.contract_address, minter); + tokenized_bond.make_transfer(transfer); } #[test] -fn test_is_inter_transfer_after_expiry_when_paused_expired_but_receiver_is_minter() { +#[should_panic(expected: 'Inter after expiry is paused')] +fn test_make_transfer_after_expiry_when_paused_not_to_minter() { let (tokenized_bond, minter) = setup_contract_with_minter(); + let from = address_with_tokens(tokenized_bond, minter); + let receiver = setup_receiver(); + let transfer = setup_transfer(from: from, to: receiver, amount: AMOUNT_TRANSFERRED()); start_cheat_caller_address(tokenized_bond.contract_address, OWNER()); tokenized_bond.pause_itr_after_expiry(TOKEN_ID()); start_cheat_block_timestamp_global(TIME_IN_THE_FUTURE() + 1); - - assert( - tokenized_bond.is_inter_transfer_after_expiry(TOKEN_ID(), minter), - 'Allow when receiver is minter', - ); + start_cheat_caller_address(tokenized_bond.contract_address, from); + tokenized_bond.make_transfer(transfer); } #[test] -fn test_is_inter_transfer_after_expiry_when_paused_expired_and_not_minter() { - let (tokenized_bond, _minter) = setup_contract_with_minter(); - let receiver = setup_receiver(); +fn test_make_transfer_after_expiry_when_paused_to_minter() { + let (tokenized_bond, minter) = setup_contract_with_minter(); + let from = address_with_tokens(tokenized_bond, minter); + let transfer = setup_transfer(from: from, to: minter, amount: AMOUNT_TRANSFERRED()); start_cheat_caller_address(tokenized_bond.contract_address, OWNER()); tokenized_bond.pause_itr_after_expiry(TOKEN_ID()); start_cheat_block_timestamp_global(TIME_IN_THE_FUTURE() + 1); - - assert( - !tokenized_bond.is_inter_transfer_after_expiry(TOKEN_ID(), receiver), - 'Fail expired without minter', - ); + start_cheat_caller_address(tokenized_bond.contract_address, from); + tokenized_bond.make_transfer(transfer); } From 3027eefda9a02e7872fc3ea9f1aec65994d4c1c1 Mon Sep 17 00:00:00 2001 From: NehharShah Date: Mon, 3 Feb 2025 14:58:04 -0500 Subject: [PATCH 4/5] removing duplicate test --- tests/lib.cairo | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/tests/lib.cairo b/tests/lib.cairo index 940670e..48b8750 100644 --- a/tests/lib.cairo +++ b/tests/lib.cairo @@ -968,22 +968,6 @@ fn test_make_transfer_with_inter_transfer_not_paused() { tokenized_bond.make_transfer(transfer); } - -#[test] -#[should_panic(expected: 'Token ITR is paused')] -fn test_make_transfer_when_paused_neither_minter() { - let (tokenized_bond, minter) = setup_contract_with_minter(); - let from = address_with_tokens(tokenized_bond, minter); - let to = setup_receiver(); - let transfer = setup_transfer(from, to, AMOUNT_TRANSFERRED()); - - start_cheat_caller_address(tokenized_bond.contract_address, OWNER()); - tokenized_bond.pause_inter_transfer(TOKEN_ID()); - - start_cheat_caller_address(tokenized_bond.contract_address, from); - tokenized_bond.make_transfer(transfer); -} - #[test] fn test_make_transfer_when_paused_sender_is_minter() { let (tokenized_bond, minter) = setup_contract_with_minter(); From b49c9c021fb8c56bcfe514585c585b6fa7728308 Mon Sep 17 00:00:00 2001 From: NehharShah Date: Mon, 3 Feb 2025 15:23:12 -0500 Subject: [PATCH 5/5] removing one more duplicate test fn --- tests/lib.cairo | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/tests/lib.cairo b/tests/lib.cairo index 48b8750..28d096f 100644 --- a/tests/lib.cairo +++ b/tests/lib.cairo @@ -1007,22 +1007,6 @@ fn test_make_transfer_before_expiry_when_expiry_paused() { tokenized_bond.make_transfer(transfer); } -#[test] -#[should_panic(expected: 'Inter after expiry is paused')] -fn test_make_transfer_after_expiry_when_paused_not_to_minter() { - let (tokenized_bond, minter) = setup_contract_with_minter(); - let from = address_with_tokens(tokenized_bond, minter); - let receiver = setup_receiver(); - let transfer = setup_transfer(from: from, to: receiver, amount: AMOUNT_TRANSFERRED()); - - start_cheat_caller_address(tokenized_bond.contract_address, OWNER()); - tokenized_bond.pause_itr_after_expiry(TOKEN_ID()); - - start_cheat_block_timestamp_global(TIME_IN_THE_FUTURE() + 1); - start_cheat_caller_address(tokenized_bond.contract_address, from); - tokenized_bond.make_transfer(transfer); -} - #[test] fn test_make_transfer_after_expiry_when_paused_to_minter() { let (tokenized_bond, minter) = setup_contract_with_minter();