diff --git a/contracts/account/src/contract/account.cairo b/contracts/account/src/contract/account.cairo index 7202083..5744895 100644 --- a/contracts/account/src/contract/account.cairo +++ b/contracts/account/src/contract/account.cairo @@ -19,7 +19,6 @@ mod Account { use starknet::{ClassHash, ContractAddress, get_caller_address, get_contract_address}; use openzeppelin::token::erc20::interface::{IERC20Dispatcher, IERC20DispatcherTrait}; - component!(path: AccountComponent, storage: account, event: AccountEvent); component!(path: SRC5Component, storage: src5, event: SRC5Event); component!(path: SRC9Component, storage: src9, event: SRC9Event); @@ -69,9 +68,7 @@ mod Account { #[flat] UpgradeableEvent: UpgradeableComponent::Event, TokenApproved: TokenApproved, - PaymentMade: PaymentMade - } - + } #[derive(Drop, starknet::Event)] pub struct TokenApproved { pub user: ContractAddress, @@ -81,14 +78,6 @@ mod Account { } #[derive(Drop, starknet::Event)] - pub struct PaymentMade { - pub from: ContractAddress, - pub to: ContractAddress, - pub currency: felt252, - pub amount: u128, - pub used_bridge: bool, - } - #[constructor] fn constructor(ref self: ContractState, public_key: felt252) { self.account.initializer(public_key); @@ -107,7 +96,6 @@ mod Account { } } - // contract impl #[abi(embed_v0)] impl AccountImpl of Iaccount { @@ -260,6 +248,24 @@ mod Account { fn get_initialized_status(self: @ContractState) -> bool { self.initialized.read() } + + // -- New functions added here -- + + fn deposit_fiat(ref self: ContractState, currency: felt252, amount: u128) { + assert(amount > 0, 'Amount must be > 0'); + let caller = get_caller_address(); + let current_balance = self.fiat_balance.read((caller, currency)); + self.fiat_balance.write((caller, currency), current_balance + amount); + self.emit(FiatDeposit { user: caller, currency, amount }); + } + + fn withdraw_fiat(ref self: ContractState, currency: felt252, amount: u128, recipient: ContractAddress) { + assert(amount > 0, 'Amount must be > 0'); + let caller = get_caller_address(); + let balance = self.fiat_balance.read((caller, currency)); + assert(balance >= amount, 'Insufficient balance'); + self.fiat_balance.write((caller, currency), balance - amount); + self.emit(FiatWithdrawal { account_address: caller, currency, amount, recipient }); + } } } - diff --git a/contracts/account/tests/test_account.cairo b/contracts/account/tests/test_account.cairo index 4bb11d2..ddd4213 100644 --- a/contracts/account/tests/test_account.cairo +++ b/contracts/account/tests/test_account.cairo @@ -10,13 +10,13 @@ fn setup() -> (ContractAddress, ContractAddress) { let public_key: felt252 = 'TEST_PUBLIC_KEY'; let declare_result = declare("Account"); - assert(declare_result.is_ok(), 'contract decleration failed'); + assert(declare_result.is_ok(), "contract declaration failed"); let contract_class = declare_result.unwrap().contract_class(); let mut calldata = array![public_key]; let deploy_result = contract_class.deploy(@calldata); - assert(deploy_result.is_ok(), 'contract deployment failed'); + assert(deploy_result.is_ok(), "contract deployment failed"); let (contract_address, _) = deploy_result.unwrap(); @@ -32,13 +32,13 @@ fn test_initialize() { dispatcher.initialize(1, 2.try_into().unwrap()); let liquidity_bridge = dispatcher.get_liquidity_bridge(); - assert(liquidity_bridge == 2.try_into().unwrap(), 'Invalid liquidity bridge'); + assert(liquidity_bridge == 2.try_into().unwrap(), "Invalid liquidity bridge"); let public_key = dispatcher.get_key_public(); - assert(public_key == 1, 'Invalid public key'); + assert(public_key == 1, "Invalid public key"); let initialized = dispatcher.get_initialized_status(); - assert(initialized, 'Invalid initialized'); + assert(initialized, "Invalid initialized"); } #[test] @@ -60,5 +60,54 @@ fn test_approve_token() { stop_cheat_caller_address(contract_address); let approved_token = dispatcher.get_approved_token('STRK'); - assert(approved_token == token_address, 'Invalid approved token'); + assert(approved_token == token_address, "Invalid approved token"); +} + +#[test] +fn test_deposit_fiat() { + let (contract_address, _) = setup(); + let dispatcher = IaccountDispatcher { contract_address }; + + dispatcher.initialize(1, 2.try_into().unwrap()); + + // Deposit 1000 units of currency '1' + dispatcher.deposit_fiat(1, 1000); + + let balance = dispatcher.get_balance(); + assert(balance == 1000.try_into().unwrap(), "Balance should be 1000 after deposit"); + + // Deposit zero should fail + let deposit_zero_result = std::panic::catch_unwind(|| { + dispatcher.deposit_fiat(1, 0); + }); + assert(deposit_zero_result.is_err(), "Deposit of 0 should fail"); +} + +#[test] +fn test_withdraw_fiat() { + let (contract_address, _) = setup(); + let dispatcher = IaccountDispatcher { contract_address }; + + dispatcher.initialize(1, 2.try_into().unwrap()); + + // Deposit 1000 so withdrawal can succeed + dispatcher.deposit_fiat(1, 1000); + + // Withdraw 500 + dispatcher.withdraw_fiat(1, 500, contract_address); + + let balance = dispatcher.get_balance(); + assert(balance == 500.try_into().unwrap(), "Balance should be 500 after withdrawal"); + + // Withdraw zero should fail + let withdraw_zero_result = std::panic::catch_unwind(|| { + dispatcher.withdraw_fiat(1, 0, contract_address); + }); + assert(withdraw_zero_result.is_err(), "Withdraw of 0 should fail"); + + // Withdraw more than balance should fail + let withdraw_too_much_result = std::panic::catch_unwind(|| { + dispatcher.withdraw_fiat(1, 1000, contract_address); + }); + assert(withdraw_too_much_result.is_err(), "Withdraw more than balance should fail"); } diff --git a/tests/test_account.cairo b/tests/test_account.cairo new file mode 100644 index 0000000..98a049a --- /dev/null +++ b/tests/test_account.cairo @@ -0,0 +1,113 @@ +use account::interfaces::Iaccount::{ + IaccountDispatcher, IaccountDispatcherTrait +}; +use snforge_std::{ + ContractClassTrait, DeclareResultTrait, declare, start_cheat_caller_address, + stop_cheat_caller_address, +}; +use starknet::{ContractAddress, contract_address_const}; + +fn setup() -> (ContractAddress, ContractAddress) { + let admin_address: ContractAddress = contract_address_const::<'1'>(); + let public_key: felt252 = 'TEST_PUBLIC_KEY'; + + let declare_result = declare("Account"); + assert(declare_result.is_ok(), "contract declaration failed"); + + let contract_class = declare_result.unwrap().contract_class(); + let mut calldata = array![public_key]; + + let deploy_result = contract_class.deploy(@calldata); + assert(deploy_result.is_ok(), "contract deployment failed"); + + let (contract_address, _) = deploy_result.unwrap(); + + (contract_address, admin_address) +} + +#[test] +fn test_initialize() { + let (contract_address, _) = setup(); + + let dispatcher = IaccountDispatcher { contract_address }; + + dispatcher.initialize(1, 2.try_into().unwrap()); + + let liquidity_bridge = dispatcher.get_liquidity_bridge(); + assert(liquidity_bridge == 2.try_into().unwrap(), "Invalid liquidity bridge"); + + let public_key = dispatcher.get_key_public(); + assert(public_key == 1, "Invalid public key"); + + let initialized = dispatcher.get_initialized_status(); + assert(initialized, "Invalid initialized"); +} + +#[test] +fn test_approve_token() { + let (contract_address, _) = setup(); + + let dispatcher = IaccountDispatcher { contract_address }; + + let token_address: ContractAddress = contract_address_const::<0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d>(); + + start_cheat_caller_address(contract_address, contract_address); + + dispatcher.initialize(1, 2.try_into().unwrap()); + + dispatcher.approve_token('STRK', token_address); + + stop_cheat_caller_address(contract_address); + + let approved_token = dispatcher.get_approved_token('STRK'); + assert(approved_token == token_address, "Invalid approved token"); +} + +#[test] +fn test_deposit_fiat() { + let (contract_address, _) = setup(); + let dispatcher = IaccountDispatcher { contract_address }; + + dispatcher.initialize(1, 2.try_into().unwrap()); + + // Deposit 1000 units of currency '1' + dispatcher.deposit_fiat(1, 1000); + + let balance = dispatcher.get_balance(); + assert(balance == 1000.try_into().unwrap(), "Balance should be 1000 after deposit"); + + // Deposit zero should fail + let deposit_zero_result = std::panic::catch_unwind(|| { + dispatcher.deposit_fiat(1, 0); + }); + assert(deposit_zero_result.is_err(), "Deposit of 0 should fail"); +} + +#[test] +fn test_withdraw_fiat() { + let (contract_address, _) = setup(); + let dispatcher = IaccountDispatcher { contract_address }; + + dispatcher.initialize(1, 2.try_into().unwrap()); + + // Deposit 1000 so withdrawal can succeed + dispatcher.deposit_fiat(1, 1000); + + // Withdraw 500 + dispatcher.withdraw_fiat(1, 500, contract_address); + + let balance = dispatcher.get_balance(); + assert(balance == 500.try_into().unwrap(), "Balance should be 500 after withdrawal"); + + // Withdraw zero should fail + let withdraw_zero_result = std::panic::catch_unwind(|| { + dispatcher.withdraw_fiat(1, 0, contract_address); + }); + assert(withdraw_zero_result.is_err(), "Withdraw of 0 should fail"); + + // Withdraw more than balance should fail + let withdraw_too_much_result = std::panic::catch_unwind(|| { + dispatcher.withdraw_fiat(1, 1000, contract_address); + }); + assert(withdraw_too_much_result.is_err(), "Withdraw more than balance should fail"); +}