extern crate std;
use soroban_sdk::{
contract, contracttype,
testutils::{Address as _, Ledger},
Address, Env,
};
use crate::role_transfer::{
accept_transfer, has_active_pending_transfer, transfer_role, PendingTransfer,
};
#[contract]
struct MockContract;
#[contracttype]
pub enum MockRole {
Admin,
PendingAdmin,
}
#[test]
fn role_transfer_works() {
let e = Env::default();
e.mock_all_auths();
let address = e.register(MockContract, ());
let admin = Address::generate(&e);
let new_admin = Address::generate(&e);
let active_key = MockRole::Admin;
let pending_key = MockRole::PendingAdmin;
e.as_contract(&address, || {
e.storage().instance().set(&active_key, &admin);
transfer_role(&e, &new_admin, &pending_key, 1000);
accept_transfer(&e, &active_key, &pending_key);
assert_eq!(e.storage().instance().get::<_, Address>(&MockRole::Admin), Some(new_admin));
});
}
#[test]
fn role_transfer_cancel_works() {
let e = Env::default();
e.mock_all_auths();
let address = e.register(MockContract, ());
let admin = Address::generate(&e);
let new_admin = Address::generate(&e);
let pending_key = MockRole::PendingAdmin;
e.as_contract(&address, || {
e.storage().instance().set(&MockRole::Admin, &admin);
transfer_role(&e, &new_admin, &pending_key, 1000);
});
e.as_contract(&address, || {
transfer_role(&e, &new_admin, &pending_key, 0);
assert!(e.storage().temporary().get::<_, PendingTransfer>(&pending_key).is_none());
assert_eq!(e.storage().instance().get::<_, Address>(&MockRole::Admin), Some(admin));
});
}
#[test]
#[should_panic(expected = "Error(Contract, #2203)")]
fn accept_transfer_after_expiry_panics() {
let e = Env::default();
e.mock_all_auths();
let address = e.register(MockContract, ());
let admin = Address::generate(&e);
let new_admin = Address::generate(&e);
let active_key = MockRole::Admin;
let pending_key = MockRole::PendingAdmin;
e.ledger().set_sequence_number(2000);
e.as_contract(&address, || {
e.storage().instance().set(&active_key, &admin);
let expired = PendingTransfer { address: new_admin.clone(), live_until_ledger: 1999 };
e.storage().temporary().set(&pending_key, &expired);
accept_transfer(&e, &active_key, &pending_key);
});
}
#[test]
#[should_panic(expected = "Error(Contract, #2203)")]
fn accept_transfer_one_ledger_past_deadline_panics() {
let e = Env::default();
e.mock_all_auths();
let address = e.register(MockContract, ());
let admin = Address::generate(&e);
let new_admin = Address::generate(&e);
let active_key = MockRole::Admin;
let pending_key = MockRole::PendingAdmin;
e.ledger().set_sequence_number(500);
e.as_contract(&address, || {
e.storage().instance().set(&active_key, &admin);
transfer_role(&e, &new_admin, &pending_key, 1000);
});
e.ledger().set_sequence_number(1001);
e.as_contract(&address, || {
let expired = PendingTransfer { address: new_admin.clone(), live_until_ledger: 1000 };
e.storage().temporary().set(&pending_key, &expired);
accept_transfer(&e, &active_key, &pending_key);
});
}
#[test]
#[should_panic(expected = "Error(Contract, #2200)")]
fn accept_transfer_with_no_pending_transfer_panics() {
let e = Env::default();
e.mock_all_auths();
let address = e.register(MockContract, ());
let admin = Address::generate(&e);
let active_key = MockRole::Admin;
let pending_key = MockRole::PendingAdmin;
e.as_contract(&address, || {
e.storage().instance().set(&MockRole::Admin, &admin);
accept_transfer(&e, &active_key, &pending_key);
});
}
#[test]
#[should_panic(expected = "Error(Contract, #2202)")]
fn cannot_cancel_with_invalid_pending_address() {
let e = Env::default();
e.mock_all_auths();
let address = e.register(MockContract, ());
let admin = Address::generate(&e);
let new_admin = Address::generate(&e);
let wrong_new_admin = Address::generate(&e);
let pending_key = MockRole::PendingAdmin;
e.as_contract(&address, || {
e.storage().instance().set(&MockRole::Admin, &admin);
transfer_role(&e, &new_admin, &pending_key, 1000);
});
e.as_contract(&address, || {
transfer_role(&e, &wrong_new_admin, &pending_key, 0);
});
}
#[test]
#[should_panic(expected = "Error(Contract, #2201)")]
fn transfer_with_invalid_live_until_ledger_panics() {
let e = Env::default();
e.mock_all_auths();
let address = e.register(MockContract, ());
let admin = Address::generate(&e);
let new_admin = Address::generate(&e);
let pending_key = MockRole::PendingAdmin;
e.ledger().set_sequence_number(1000);
e.as_contract(&address, || {
e.storage().instance().set(&MockRole::Admin, &admin);
transfer_role(&e, &new_admin, &pending_key, 3);
});
}
#[test]
fn has_active_pending_transfer_cleans_up_expired_entry() {
let e = Env::default();
e.mock_all_auths();
let address = e.register(MockContract, ());
let new_admin = Address::generate(&e);
let pending_key = MockRole::PendingAdmin;
e.ledger().set_sequence_number(200);
e.as_contract(&address, || {
let expired = PendingTransfer { address: new_admin.clone(), live_until_ledger: 100 };
e.storage().temporary().set(&pending_key, &expired);
e.storage().temporary().extend_ttl(&pending_key, 1000, 1000);
assert!(e.storage().temporary().get::<_, PendingTransfer>(&pending_key).is_some());
assert!(!has_active_pending_transfer(&e, &pending_key));
assert!(e.storage().temporary().get::<_, PendingTransfer>(&pending_key).is_none());
});
}
#[test]
fn has_active_pending_transfer_returns_true_for_active_entry() {
let e = Env::default();
e.mock_all_auths();
let address = e.register(MockContract, ());
let new_admin = Address::generate(&e);
let pending_key = MockRole::PendingAdmin;
e.ledger().set_sequence_number(50);
e.as_contract(&address, || {
let active = PendingTransfer { address: new_admin.clone(), live_until_ledger: 100 };
e.storage().temporary().set(&pending_key, &active);
e.storage().temporary().extend_ttl(&pending_key, 1000, 1000);
assert!(has_active_pending_transfer(&e, &pending_key));
assert!(e.storage().temporary().get::<_, PendingTransfer>(&pending_key).is_some());
});
}
#[test]
#[should_panic(expected = "Error(Contract, #2200)")]
fn cancel_transfer_when_there_is_no_pending_transfer_panics() {
let e = Env::default();
e.mock_all_auths();
let address = e.register(MockContract, ());
let admin = Address::generate(&e);
let new_admin = Address::generate(&e);
let pending_key = MockRole::PendingAdmin;
e.as_contract(&address, || {
e.storage().instance().set(&MockRole::Admin, &admin);
transfer_role(&e, &new_admin, &pending_key, 0);
});
}