Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
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
6 changes: 6 additions & 0 deletions src/interface.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,10 @@ pub trait ITokenizedBond<TState> {
fn minter_is_operator(self: @TState, token_id: u256, minter: ContractAddress) -> bool;
fn check_owner_and_operator(self: @TState, transfers: Array<TransferParam>) -> 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;
}
58 changes: 29 additions & 29 deletions src/tokenized_bond.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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;
}
}
}
110 changes: 110 additions & 0 deletions tests/lib.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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',
);
}
Loading