#[cfg(test)]
mod allowance_tests {
use core::ops::Add;
use odra::casper_types::U256;
use odra::host::{Deployer, HostRef, NoArgs};
use odra::prelude::*;
use crate::cep18::cep18_client_contract::Cep18ClientContract;
use crate::cep18::errors::Error::{CannotTargetSelfUser, InsufficientAllowance};
use crate::cep18::events::{DecreaseAllowance, IncreaseAllowance, SetAllowance};
use crate::cep18_token::tests::{
invert_address, setup, ALLOWANCE_AMOUNT_1, ALLOWANCE_AMOUNT_2, TRANSFER_AMOUNT_1
};
use crate::cep18_token::utils::Cep18ExampleHostRef;
fn test_approve_for(
cep18_token: &mut Cep18ExampleHostRef,
sender: Address,
owner: Address,
spender: Address
) {
let amount = TRANSFER_AMOUNT_1.into();
assert_eq!(cep18_token.allowance(&owner, &spender), 0.into());
cep18_token.env().set_caller(sender);
cep18_token.approve(&spender, &amount);
assert_eq!(cep18_token.allowance(&owner, &spender), amount);
assert!(cep18_token.env().emitted_event(
cep18_token,
SetAllowance {
owner,
spender,
allowance: amount
}
));
cep18_token.approve(&spender, &(amount.add(U256::one())));
assert_eq!(
cep18_token.allowance(&owner, &spender),
amount.add(U256::one())
);
let inverted_owner = invert_address(owner);
let inverted_spender = invert_address(spender);
assert_eq!(
cep18_token.allowance(&inverted_owner, &inverted_spender),
U256::zero()
);
}
#[test]
fn should_approve_funds() {
let mut cep18_token = setup();
let owner = cep18_token.env().get_account(0);
let alice = cep18_token.env().get_account(1);
let token_address = cep18_token.address();
let client_contract = Cep18ClientContract::deploy(cep18_token.env(), NoArgs);
let another_client_contract = Cep18ClientContract::deploy(cep18_token.env(), NoArgs);
let client_contract_address = client_contract.address();
let another_client_contract_address = another_client_contract.address();
test_approve_for(&mut cep18_token, owner, owner, alice);
cep18_token.approve(&client_contract_address, &ALLOWANCE_AMOUNT_1.into());
assert_eq!(
cep18_token.allowance(&owner, &client_contract_address),
ALLOWANCE_AMOUNT_1.into()
);
client_contract.transfer_from_as_stored_contract(
token_address,
owner,
client_contract_address,
ALLOWANCE_AMOUNT_1.into()
);
assert_eq!(
cep18_token.balance_of(&client_contract_address),
ALLOWANCE_AMOUNT_1.into()
);
client_contract.approve_as_stored_contract(
token_address,
another_client_contract_address,
ALLOWANCE_AMOUNT_1.into()
);
assert_eq!(
cep18_token.allowance(&client_contract_address, &another_client_contract_address),
ALLOWANCE_AMOUNT_1.into()
);
another_client_contract.transfer_from_as_stored_contract(
token_address,
client_contract_address,
another_client_contract_address,
ALLOWANCE_AMOUNT_1.into()
);
assert_eq!(
cep18_token.balance_of(&another_client_contract_address),
ALLOWANCE_AMOUNT_1.into()
);
}
#[test]
fn should_not_approve_self() {
let mut cep18_token = setup();
let owner = cep18_token.env().get_account(0);
let amount = ALLOWANCE_AMOUNT_1.into();
let result = cep18_token.try_approve(&owner, &amount);
assert_eq!(result.err().unwrap(), CannotTargetSelfUser.into());
assert_eq!(cep18_token.allowance(&owner, &owner), U256::zero());
}
#[test]
fn should_not_transfer_from_without_enough_allowance() {
let mut cep18_token = setup();
let owner = cep18_token.env().get_account(0);
let alice = cep18_token.env().get_account(1);
cep18_token.approve(&alice, &ALLOWANCE_AMOUNT_1.into());
assert_eq!(
cep18_token.allowance(&owner, &alice),
ALLOWANCE_AMOUNT_1.into()
);
cep18_token.env().set_caller(alice);
let result =
cep18_token.try_transfer_from(&owner, &alice, &U256::from(ALLOWANCE_AMOUNT_1 + 1));
assert_eq!(result.err().unwrap(), InsufficientAllowance.into());
cep18_token.transfer_from(&owner, &alice, &U256::from(ALLOWANCE_AMOUNT_1));
}
#[test]
fn test_decrease_allowance() {
let mut cep18_token = setup();
let owner = cep18_token.env().get_account(0);
let alice = cep18_token.env().get_account(1);
cep18_token.approve(&alice, &ALLOWANCE_AMOUNT_1.into());
assert_eq!(
cep18_token.allowance(&owner, &alice),
ALLOWANCE_AMOUNT_1.into()
);
cep18_token.decrease_allowance(&alice, &ALLOWANCE_AMOUNT_2.into());
let allowance_after_decrease: U256 = (ALLOWANCE_AMOUNT_1 - ALLOWANCE_AMOUNT_2).into();
assert_eq!(
cep18_token.allowance(&owner, &alice),
allowance_after_decrease
);
assert!(cep18_token.env().emitted_event(
&cep18_token,
DecreaseAllowance {
owner,
spender: alice,
allowance: ALLOWANCE_AMOUNT_1.into(),
decr_by: ALLOWANCE_AMOUNT_2.into()
}
));
cep18_token.increase_allowance(&alice, &ALLOWANCE_AMOUNT_1.into());
let allowance_after_increase: U256 = ((ALLOWANCE_AMOUNT_1 * 2) - ALLOWANCE_AMOUNT_2).into();
assert_eq!(
cep18_token.allowance(&owner, &alice),
allowance_after_increase
);
assert!(cep18_token.env().emitted_event(
&cep18_token,
IncreaseAllowance {
owner,
spender: alice,
allowance: allowance_after_decrease,
inc_by: ALLOWANCE_AMOUNT_1.into()
}
));
}
#[test]
fn should_saturate_allowance_at_zero_when_decreasing_below_available() {
let mut cep18_token = setup();
let owner = cep18_token.env().get_account(0);
let alice = cep18_token.env().get_account(1);
cep18_token.approve(&alice, &ALLOWANCE_AMOUNT_2.into());
cep18_token.decrease_allowance(&alice, &(ALLOWANCE_AMOUNT_2 + 1).into());
assert_eq!(cep18_token.allowance(&owner, &alice), U256::zero());
}
}