Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion contracts/account/src/base/errors.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ pub mod AccountErrors {
pub const CANNOT_BE_ADDR_ZERO: felt252 = 'Address cannot be Zero';
pub const AMOUNT_CANNOT_BE_ZERO: felt252 = 'Amount cannot be Zero';
pub const CURRENCY_IS_REQUIRED: felt252 = 'Currency cannot be Zero';
}
}
90 changes: 79 additions & 11 deletions contracts/account/src/contract/account.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,23 @@

#[starknet::contract(account)]
mod Account {
use core::num::traits::Zero;
use account::interfaces::Iaccount::Iaccount;
use account::interfaces::ILiquidityBridge::{ILiquidityBridge, ILiquidityBridgeDispatcher, ILiquidityBridgeDispatcherTrait};
use account::base::errors::AccountErrors;
use account::interfaces::ILiquidityBridge::{
ILiquidityBridge, ILiquidityBridgeDispatcher, ILiquidityBridgeDispatcherTrait,
};
use account::interfaces::Iaccount::Iaccount;
use core::num::traits::Zero;
use openzeppelin::account::AccountComponent;
use openzeppelin::account::extensions::SRC9Component;
use openzeppelin::introspection::src5::SRC5Component;
use openzeppelin::token::erc20::interface::{IERC20Dispatcher, IERC20DispatcherTrait};
use openzeppelin::upgrades::UpgradeableComponent;
use openzeppelin::upgrades::interface::IUpgradeable;
use starknet::storage::{
Map, StorageMapReadAccess, StorageMapWriteAccess, StoragePointerReadAccess,
StoragePointerWriteAccess,
};
use starknet::{ClassHash, ContractAddress, get_caller_address, get_contract_address};
use openzeppelin::token::erc20::interface::{IERC20Dispatcher, IERC20DispatcherTrait};


component!(path: AccountComponent, storage: account, event: AccountEvent);
Expand Down Expand Up @@ -54,7 +56,7 @@ mod Account {
liquidity_bridge: ContractAddress,
initialized: bool,
public_key: felt252,
approved_tokens: Map<felt252, ContractAddress>, // symbol => token_address
approved_tokens: Map<felt252, ContractAddress> // symbol => token_address
}

#[event]
Expand All @@ -69,7 +71,9 @@ mod Account {
#[flat]
UpgradeableEvent: UpgradeableComponent::Event,
TokenApproved: TokenApproved,
PaymentMade: PaymentMade
PaymentMade: PaymentMade,
FiatDeposit: FiatDeposit,
FiatWithdrawal: FiatWithdrawal,
}

#[derive(Drop, starknet::Event)]
Expand All @@ -89,6 +93,22 @@ mod Account {
pub used_bridge: bool,
}


#[derive(Drop, starknet::Event)]
pub struct FiatDeposit {
pub user: ContractAddress,
pub currency: felt252,
pub amount: u128,
}

#[derive(Drop, starknet::Event)]
pub struct FiatWithdrawal {
pub account_address: ContractAddress,
pub currency: felt252,
pub amount: u128,
pub recipient: ContractAddress,
}

#[constructor]
fn constructor(ref self: ContractState, public_key: felt252) {
self.account.initializer(public_key);
Expand Down Expand Up @@ -210,7 +230,7 @@ mod Account {
}

fn initialize(
ref self: ContractState, public_key: felt252, liquidity_bridge: ContractAddress
ref self: ContractState, public_key: felt252, liquidity_bridge: ContractAddress,
) {
assert(!self.initialized.read(), 'Already initialized');
self.public_key.write(public_key);
Expand All @@ -222,7 +242,8 @@ mod Account {
self.account.assert_only_self();
assert(self.initialized.read(), 'Not initialized');
assert(
self.approved_tokens.read(symbol) == 0.try_into().unwrap(), 'Token already approved'
self.approved_tokens.read(symbol) == 0.try_into().unwrap(),
'Token already approved',
);
assert(token_address != 0.try_into().unwrap(), 'Token address cannot be 0');

Expand All @@ -241,7 +262,7 @@ mod Account {
symbol,
token_address,
amount: 10000000000000000000,
}
},
);
}

Expand All @@ -261,8 +282,55 @@ mod Account {
self.initialized.read()
}

fn get_fiat_balance(self: @ContractState, user: ContractAddress, currency: felt252) -> u128 {
123456789
// fn get_fiat_balance(self: @ContractState, user: ContractAddress, currency: felt252) ->
// u128 {
// 123456789
// }

fn get_fiat_balance(
self: @ContractState, user: ContractAddress, currency: felt252,
) -> u128 {
self.fiat_balance.read((user, currency))
}


fn deposit_fiat(ref self: ContractState, currency: felt252, amount: u128) {
self.account.assert_only_self();
assert(!amount.is_zero(), AccountErrors::AMOUNT_CANNOT_BE_ZERO);
assert(!currency.is_zero(), AccountErrors::CURRENCY_IS_REQUIRED);
let account_address = get_contract_address();
let current_balance = self.fiat_balance.read((account_address, currency));
self.fiat_balance.write((account_address, currency), current_balance + amount);
self
.emit(
FiatDeposit {
user: account_address, currency, amount: current_balance + amount,
},
);
}

fn withdraw_fiat(
ref self: ContractState, currency: felt252, amount: u128, recipient: ContractAddress,
) {
self.account.assert_only_self();
assert(!amount.is_zero(), AccountErrors::AMOUNT_CANNOT_BE_ZERO);
assert(!currency.is_zero(), AccountErrors::CURRENCY_IS_REQUIRED);
assert(!recipient.is_zero(), AccountErrors::CANNOT_BE_ADDR_ZERO);

let account_address = get_contract_address();
let current_balance = self.fiat_balance.read((account_address, currency));
assert(current_balance >= amount, 'Insufficient balance');

self.fiat_balance.write((account_address, currency), current_balance - amount);
self
.emit(
FiatWithdrawal {
account_address,
currency,
amount: current_balance - amount,
recipient: recipient,
},
);
}
}
}
Expand Down
4 changes: 4 additions & 0 deletions contracts/account/src/interfaces/Iaccount.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,8 @@ pub trait Iaccount<TContractState> {
use_liquidity_bridge: bool,
) -> bool;
fn get_fiat_balance(self: @TContractState, user: ContractAddress, currency: felt252) -> u128;
fn deposit_fiat(ref self: TContractState, currency: felt252, amount: u128);
fn withdraw_fiat(
ref self: TContractState, currency: felt252, amount: u128, recipient: ContractAddress,
);
}
2 changes: 1 addition & 1 deletion contracts/account/src/lib.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ pub mod contract {
}

pub mod interfaces {
pub mod Iaccount;
pub mod ILiquidityBridge;
pub mod Iaccount;
}


Expand Down
2 changes: 1 addition & 1 deletion contracts/account/tests/lib.cairo
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
pub mod test_contract;
pub mod test_account;
pub mod test_contract;
95 changes: 94 additions & 1 deletion contracts/account/tests/test_account.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ fn test_approve_token() {
let dispatcher = IaccountDispatcher { contract_address };

let token_address: ContractAddress = contract_address_const::<
0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d
0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d,
>();

start_cheat_caller_address(contract_address, contract_address);
Expand All @@ -62,3 +62,96 @@ fn test_approve_token() {
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 };
let currency = 'USD';
let amount: u128 = 1000;

start_cheat_caller_address(contract_address, contract_address);
dispatcher.initialize(1, 2.try_into().unwrap());

dispatcher.deposit_fiat(currency, amount);

let balance = dispatcher.get_fiat_balance(contract_address, currency);
assert(balance == amount.into(), 'Bal equal to deposited amount');

stop_cheat_caller_address(contract_address);
}


#[test]
#[should_panic(expected: ('Insufficient balance',))]
fn test_withdraw_fiat_insufficient_balance() {
let (contract_address, _) = setup();
let dispatcher = IaccountDispatcher { contract_address };
let currency = 'USD';
let recipient: ContractAddress = contract_address_const::<'2'>();

start_cheat_caller_address(contract_address, contract_address);
dispatcher.initialize(1, 2.try_into().unwrap());

dispatcher.withdraw_fiat(currency, 1000, recipient);

stop_cheat_caller_address(contract_address);
}


#[test]
fn test_multiple_deposits() {
let (contract_address, _) = setup();
let dispatcher = IaccountDispatcher { contract_address };
let currency = 'USD';
let amount1: u128 = 1000;
let amount2: u128 = 500;

start_cheat_caller_address(contract_address, contract_address);
dispatcher.initialize(1, 2.try_into().unwrap());

dispatcher.deposit_fiat(currency, amount1);
// Second deposit
dispatcher.deposit_fiat(currency, amount2);

let balance = dispatcher.get_fiat_balance(contract_address, currency);
assert(balance == (amount1 + amount2).into(), 'Bal equ sum of both deposits');

stop_cheat_caller_address(contract_address);
}

#[test]
fn test_different_currencies() {
let (contract_address, _) = setup();
let dispatcher = IaccountDispatcher { contract_address };
let usd_amount: u128 = 1000;
let eur_amount: u128 = 500;

start_cheat_caller_address(contract_address, contract_address);
dispatcher.initialize(1, 2.try_into().unwrap());

dispatcher.deposit_fiat('USD', usd_amount);
dispatcher.deposit_fiat('EUR', eur_amount);

let usd_balance = dispatcher.get_fiat_balance(contract_address, 'USD');
let eur_balance = dispatcher.get_fiat_balance(contract_address, 'EUR');

assert(usd_balance == usd_amount.into(), 'USD balance incorrect');
assert(eur_balance == eur_amount.into(), 'EUR balance incorrect');

stop_cheat_caller_address(contract_address);
}

#[test]
#[should_panic(expected: ('Amount cannot be Zero',))]
fn test_deposit_zero_amount() {
let (contract_address, _) = setup();
let dispatcher = IaccountDispatcher { contract_address };

start_cheat_caller_address(contract_address, contract_address);
dispatcher.initialize(1, 2.try_into().unwrap());

dispatcher.deposit_fiat('USD', 0);
}

Loading