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
120 changes: 120 additions & 0 deletions contracts/account/Scarb.lock
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,129 @@ version = 1
name = "account"
version = "0.1.0"
dependencies = [
"openzeppelin",
"snforge_std",
]

[[package]]
name = "openzeppelin"
version = "1.0.0"
source = "registry+https://scarbs.xyz/"
checksum = "sha256:320185f3e17cf9fafda88b1ce490f5eaed0bfcc273036b56cd22ce4fb8de628f"
dependencies = [
"openzeppelin_access",
"openzeppelin_account",
"openzeppelin_finance",
"openzeppelin_governance",
"openzeppelin_introspection",
"openzeppelin_merkle_tree",
"openzeppelin_presets",
"openzeppelin_security",
"openzeppelin_token",
"openzeppelin_upgrades",
"openzeppelin_utils",
]

[[package]]
name = "openzeppelin_access"
version = "1.0.0"
source = "registry+https://scarbs.xyz/"
checksum = "sha256:a39a4ea1582916c637bf7e3aee0832c3fe1ea3a3e39191955e8dc39d08327f9b"
dependencies = [
"openzeppelin_introspection",
"openzeppelin_utils",
]

[[package]]
name = "openzeppelin_account"
version = "1.0.0"
source = "registry+https://scarbs.xyz/"
checksum = "sha256:7e943a2de32ddca4d48e467e52790e380ab1f49c4daddbbbc4634dd930d0243f"
dependencies = [
"openzeppelin_introspection",
"openzeppelin_utils",
]

[[package]]
name = "openzeppelin_finance"
version = "1.0.0"
source = "registry+https://scarbs.xyz/"
checksum = "sha256:9fa9e91d39b6ccdfa31eef32fdc087cd06c0269cc9c6b86e32d57f5a6997d98b"
dependencies = [
"openzeppelin_access",
"openzeppelin_token",
]

[[package]]
name = "openzeppelin_governance"
version = "1.0.0"
source = "registry+https://scarbs.xyz/"
checksum = "sha256:c05add2974b3193c3a5c022b9586a84cf98c5970cdb884dcf201c77dbe359f55"
dependencies = [
"openzeppelin_access",
"openzeppelin_account",
"openzeppelin_introspection",
"openzeppelin_token",
"openzeppelin_utils",
]

[[package]]
name = "openzeppelin_introspection"
version = "1.0.0"
source = "registry+https://scarbs.xyz/"
checksum = "sha256:34e088ecf19e0b3012481a29f1fbb20e600540cb9a5db1c3002a97ebb7f5a32a"

[[package]]
name = "openzeppelin_merkle_tree"
version = "1.0.0"
source = "registry+https://scarbs.xyz/"
checksum = "sha256:a5341705514a3d9beeeb39cf11464111f7355be621639740d2c5006786aa63dc"

[[package]]
name = "openzeppelin_presets"
version = "1.0.0"
source = "registry+https://scarbs.xyz/"
checksum = "sha256:4eb098e2ee3ac0e67b6828115a7de62f781418beab767d4e80b54e176808369d"
dependencies = [
"openzeppelin_access",
"openzeppelin_account",
"openzeppelin_finance",
"openzeppelin_introspection",
"openzeppelin_token",
"openzeppelin_upgrades",
"openzeppelin_utils",
]

[[package]]
name = "openzeppelin_security"
version = "1.0.0"
source = "registry+https://scarbs.xyz/"
checksum = "sha256:1deb811a239c4f9cc28fc302039e2ffcb19911698a8c612487207448d70d2e6e"

[[package]]
name = "openzeppelin_token"
version = "1.0.0"
source = "registry+https://scarbs.xyz/"
checksum = "sha256:33fcb84a1a76d2d3fff9302094ff564f78d45b743548fd7568c130b272473f66"
dependencies = [
"openzeppelin_access",
"openzeppelin_account",
"openzeppelin_introspection",
"openzeppelin_utils",
]

[[package]]
name = "openzeppelin_upgrades"
version = "1.0.0"
source = "registry+https://scarbs.xyz/"
checksum = "sha256:36f7a03e7e7111577916aacf31f88ad0053de20f33ee10b0ab3804849c3aa373"

[[package]]
name = "openzeppelin_utils"
version = "1.0.0"
source = "registry+https://scarbs.xyz/"
checksum = "sha256:fd348b31c4a4407add33adc3c2b8f26dca71dbd7431faaf726168f37a91db0c1"

[[package]]
name = "snforge_scarb_plugin"
version = "0.43.1"
Expand Down
1 change: 1 addition & 0 deletions contracts/account/Scarb.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ edition = "2024_07"

[dependencies]
starknet = "2.11.4"
openzeppelin = "1.0.0"

[dev-dependencies]
snforge_std = "0.43.0"
Expand Down
107 changes: 107 additions & 0 deletions contracts/account/src/contract/account.cairo
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please add this to storage:
// Custom storage for SyncPayment functionality
fiat_balance: Map<(ContractAddress, felt252), u128>, // (user, currency) => balance
token_address: Map<felt252, ContractAddress>, // symbol => token_address
default_fiat_currency: felt252,
liquidity_bridge: ContractAddress,
initialized: bool,

Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
// SPDX-License-Identifier: MIT
// Compatible with OpenZeppelin Contracts for Cairo 2.0.0-alpha.1

#[starknet::contract(account)]
mod Account {
use account::interfaces::Iaccount::Iaccount;
use openzeppelin::account::AccountComponent;
use openzeppelin::account::extensions::SRC9Component;
use openzeppelin::introspection::src5::SRC5Component;
use openzeppelin::upgrades::UpgradeableComponent;
use openzeppelin::upgrades::interface::IUpgradeable;
use starknet::storage::{
Map, StorageMapReadAccess, StorageMapWriteAccess, StoragePointerReadAccess,
StoragePointerWriteAccess,
};
use starknet::{ClassHash, ContractAddress, get_caller_address};


component!(path: AccountComponent, storage: account, event: AccountEvent);
component!(path: SRC5Component, storage: src5, event: SRC5Event);
component!(path: SRC9Component, storage: src9, event: SRC9Event);
component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);

// External
#[abi(embed_v0)]
impl AccountMixinImpl = AccountComponent::AccountMixinImpl<ContractState>;
#[abi(embed_v0)]
impl OutsideExecutionV2Impl =
SRC9Component::OutsideExecutionV2Impl<ContractState>;

// Internal
impl AccountInternalImpl = AccountComponent::InternalImpl<ContractState>;
impl OutsideExecutionInternalImpl = SRC9Component::InternalImpl<ContractState>;
impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl<ContractState>;

#[storage]
struct Storage {
#[substorage(v0)]
account: AccountComponent::Storage,
#[substorage(v0)]
src5: SRC5Component::Storage,
#[substorage(v0)]
src9: SRC9Component::Storage,
#[substorage(v0)]
upgradeable: UpgradeableComponent::Storage,
// Custom storage for SyncPayment functionality
fiat_balance: Map<(ContractAddress, felt252), u128>, // (user, currency) => balance
token_address: Map<felt252, ContractAddress>, // symbol => token_address
default_fiat_currency: felt252,
liquidity_bridge: ContractAddress,
initialized: bool,
}

#[event]
#[derive(Drop, starknet::Event)]
enum Event {
#[flat]
AccountEvent: AccountComponent::Event,
#[flat]
SRC5Event: SRC5Component::Event,
#[flat]
SRC9Event: SRC9Component::Event,
#[flat]
UpgradeableEvent: UpgradeableComponent::Event,
}

#[constructor]
fn constructor(ref self: ContractState, public_key: felt252) {
self.account.initializer(public_key);
self.src9.initializer();
}

//
// Upgradeable
//

#[abi(embed_v0)]
impl UpgradeableImpl of IUpgradeable<ContractState> {
fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {
self.account.assert_only_self();
self.upgradeable.upgrade(new_class_hash);
}
}


// contract impl
#[abi(embed_v0)]
impl AccountImpl of Iaccount<ContractState> {
fn increase_balance(ref self: ContractState, amount: felt252) {
assert(amount != 0, 'Amount cannot be 0');
let caller = get_caller_address();
let currency = self.default_fiat_currency.read();
let current_balance = self.fiat_balance.read((caller, currency));

self
.fiat_balance
.write((caller, currency), current_balance + amount.try_into().unwrap());
}

fn get_balance(self: @ContractState) -> felt252 {
let caller = get_caller_address();
let currency = self.default_fiat_currency.read();
self.fiat_balance.read((caller, currency)).into()
}
}
}

5 changes: 5 additions & 0 deletions contracts/account/src/interfaces/Iaccount.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#[starknet::interface]
pub trait Iaccount<TContractState> {
fn increase_balance(ref self: TContractState, amount: felt252);
fn get_balance(self: @TContractState) -> felt252;
}
33 changes: 4 additions & 29 deletions contracts/account/src/lib.cairo
Original file line number Diff line number Diff line change
@@ -1,32 +1,7 @@
/// Interface representing `HelloContract`.
/// This interface allows modification and retrieval of the contract balance.
#[starknet::interface]
pub trait IHelloStarknet<TContractState> {
/// Increase contract balance.
fn increase_balance(ref self: TContractState, amount: felt252);
/// Retrieve contract balance.
fn get_balance(self: @TContractState) -> felt252;
pub mod contract {
pub mod account;
}

/// Simple contract for managing balance.
#[starknet::contract]
mod HelloStarknet {
use starknet::storage::{StoragePointerReadAccess, StoragePointerWriteAccess};

#[storage]
struct Storage {
balance: felt252,
}

#[abi(embed_v0)]
impl HelloStarknetImpl of super::IHelloStarknet<ContractState> {
fn increase_balance(ref self: ContractState, amount: felt252) {
assert(amount != 0, 'Amount cannot be 0');
self.balance.write(self.balance.read() + amount);
}

fn get_balance(self: @ContractState) -> felt252 {
self.balance.read()
}
}
pub mod interfaces {
pub mod Iaccount;
}
1 change: 1 addition & 0 deletions contracts/account/tests/lib.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod test_contract;
53 changes: 40 additions & 13 deletions contracts/account/tests/test_contract.cairo
Original file line number Diff line number Diff line change
@@ -1,37 +1,64 @@
use account::{
IHelloStarknetDispatcher, IHelloStarknetDispatcherTrait, IHelloStarknetSafeDispatcher,
IHelloStarknetSafeDispatcherTrait,
use account::interfaces::Iaccount::{
IaccountDispatcher, IaccountDispatcherTrait, IaccountSafeDispatcher,
IaccountSafeDispatcherTrait,
};
use snforge_std::{ContractClassTrait, DeclareResultTrait, declare};
use starknet::ContractAddress;
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 decleration 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');

fn deploy_contract(name: ByteArray) -> ContractAddress {
let contract = declare(name).unwrap().contract_class();
let (contract_address, _) = contract.deploy(@ArrayTrait::new()).unwrap();
contract_address
let (contract_address, _) = deploy_result.unwrap();

(contract_address, admin_address)
}


#[test]
fn test_increase_balance() {
let contract_address = deploy_contract("HelloStarknet");
let (contract_address, admin_address_) = setup();
let owner = contract_address_const::<'1'>();

let dispatcher = IaccountDispatcher { contract_address };

let dispatcher = IHelloStarknetDispatcher { contract_address };
start_cheat_caller_address(dispatcher.contract_address, owner);

let balance_before = dispatcher.get_balance();
assert(balance_before == 0, 'Invalid balance');

dispatcher.increase_balance(42);

stop_cheat_caller_address(owner);

let balance_after = dispatcher.get_balance();
assert(balance_after == 42, 'Invalid balance');
}

#[test]
#[feature("safe_dispatcher")]
fn test_cannot_increase_balance_with_zero_value() {
let contract_address = deploy_contract("HelloStarknet");
let (contract_address, admin_address_) = setup();
let owner = contract_address_const::<'1'>();

let dispatcher = IaccountDispatcher { contract_address };

start_cheat_caller_address(dispatcher.contract_address, owner);

let safe_dispatcher = IHelloStarknetSafeDispatcher { contract_address };
let safe_dispatcher = IaccountSafeDispatcher { contract_address };

let balance_before = safe_dispatcher.get_balance().unwrap();
assert(balance_before == 0, 'Invalid balance');
Expand Down
Loading