From f76f4cff0528bfdc3a0b1b228fb90287008bd12a Mon Sep 17 00:00:00 2001 From: Nonnyjoe Date: Wed, 27 Dec 2023 17:15:06 +0100 Subject: [PATCH 1/2] Added piggyBank contract example --- examples/piggy_bank/.gitignore | 4 + examples/piggy_bank/Scarb.lock | 14 + examples/piggy_bank/Scarb.toml | 20 ++ examples/piggy_bank/src/lib.cairo | 3 + .../piggy_bank/src/ownership_component.cairo | 82 +++++ examples/piggy_bank/src/piggy_bank.cairo | 203 +++++++++++++ examples/piggy_bank/src/piggy_factory.cairo | 138 +++++++++ examples/piggy_bank/tests/lib.cairo | 2 + .../piggy_bank/tests/test_piggy_bank.cairo | 279 ++++++++++++++++++ .../piggy_bank/tests/test_piggy_factory.cairo | 109 +++++++ 10 files changed, 854 insertions(+) create mode 100644 examples/piggy_bank/.gitignore create mode 100644 examples/piggy_bank/Scarb.lock create mode 100644 examples/piggy_bank/Scarb.toml create mode 100644 examples/piggy_bank/src/lib.cairo create mode 100644 examples/piggy_bank/src/ownership_component.cairo create mode 100644 examples/piggy_bank/src/piggy_bank.cairo create mode 100644 examples/piggy_bank/src/piggy_factory.cairo create mode 100644 examples/piggy_bank/tests/lib.cairo create mode 100644 examples/piggy_bank/tests/test_piggy_bank.cairo create mode 100644 examples/piggy_bank/tests/test_piggy_factory.cairo diff --git a/examples/piggy_bank/.gitignore b/examples/piggy_bank/.gitignore new file mode 100644 index 000000000..9d78812b7 --- /dev/null +++ b/examples/piggy_bank/.gitignore @@ -0,0 +1,4 @@ +target +.snfoundry_cache +.env +env diff --git a/examples/piggy_bank/Scarb.lock b/examples/piggy_bank/Scarb.lock new file mode 100644 index 000000000..955e0c4a3 --- /dev/null +++ b/examples/piggy_bank/Scarb.lock @@ -0,0 +1,14 @@ +# Code generated by scarb DO NOT EDIT. +version = 1 + +[[package]] +name = "piggy_bank" +version = "0.1.0" +dependencies = [ + "snforge_std", +] + +[[package]] +name = "snforge_std" +version = "0.1.0" +source = "git+https://github.com/foundry-rs/starknet-foundry?tag=v0.10.1#2f1597fb724b7df3050468bd0e6a8a3a0e225001" diff --git a/examples/piggy_bank/Scarb.toml b/examples/piggy_bank/Scarb.toml new file mode 100644 index 000000000..eaa5ce9d8 --- /dev/null +++ b/examples/piggy_bank/Scarb.toml @@ -0,0 +1,20 @@ +[package] +name = "piggy_bank" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest.html + +[dependencies] +snforge_std = { git = "https://github.com/foundry-rs/starknet-foundry", tag = "v0.10.1" } +starknet = "2.3.1" + +[[target.starknet-contract]] +casm = true + +[[tool.snforge.fork]] +name = "GoerliFork" +url = "https://starknet-goerli.infura.io/v3/571aaed99608415397cb4eb46ca740c4" +block_id.tag = "Latest" + +RUST_BACKTRACE=1 + diff --git a/examples/piggy_bank/src/lib.cairo b/examples/piggy_bank/src/lib.cairo new file mode 100644 index 000000000..a654ae566 --- /dev/null +++ b/examples/piggy_bank/src/lib.cairo @@ -0,0 +1,3 @@ +mod piggy_bank; +mod ownership_component; +mod piggy_factory; \ No newline at end of file diff --git a/examples/piggy_bank/src/ownership_component.cairo b/examples/piggy_bank/src/ownership_component.cairo new file mode 100644 index 000000000..e145d320e --- /dev/null +++ b/examples/piggy_bank/src/ownership_component.cairo @@ -0,0 +1,82 @@ +use starknet::ContractAddress; +#[starknet::interface] +trait IOwnable { + fn owner(self: @TContractState) -> ContractAddress; + fn transfer_ownership(ref self: TContractState, new_owner: ContractAddress); + fn renounce_ownership(ref self: TContractState); +} + +#[starknet::component] +mod ownable_component { + use starknet::{get_caller_address, ContractAddress, get_contract_address, Zeroable, get_block_timestamp}; + use super::Errors; + + #[storage] + struct Storage { + owner: ContractAddress + } + + #[event] + #[derive(Drop, starknet::Event)] + enum Event { + OwnershipTransferred: OwnershipTransferred + } + + #[derive(Drop, starknet::Event)] + struct OwnershipTransferred { + previous_owner: ContractAddress, + new_owner: ContractAddress, + } + + #[embeddable_as(Ownable)] + impl OwnableImpl< + TContractState, +HasComponent> of super::IOwnable> { + fn owner(self: @ComponentState) -> ContractAddress { + self.owner.read() + } + + fn transfer_ownership( + ref self: ComponentState, new_owner: ContractAddress + ) { + assert(!new_owner.is_zero(), Errors::ZERO_ADDRESS_OWNER); + self.assert_only_owner(); + self._transfer_ownership(new_owner); + } + + fn renounce_ownership(ref self: ComponentState) { + self.assert_only_owner(); + self._transfer_ownership(Zeroable::zero()); + } + } + + #[generate_trait] + impl InternalImpl> of InternalTrait { + fn initializer(ref self: ComponentState, owner: ContractAddress) { + self._transfer_ownership(owner); + } + + fn assert_only_owner(self: @ComponentState) { + let owner: ContractAddress = self.owner.read(); + let caller: ContractAddress = get_caller_address(); + assert(!caller.is_zero(), Errors::ZERO_ADDRESS_CALLER); + assert(caller == owner, Errors::NOT_OWNER); + } + + fn _transfer_ownership( + ref self: ComponentState, new_owner: ContractAddress + ) { + let previous_owner: ContractAddress = self.owner.read(); + self.owner.write(new_owner); + self + .emit( + OwnershipTransferred { previous_owner: previous_owner, new_owner: new_owner } + ); + } + } +} + +mod Errors { + const NOT_OWNER: felt252 = 'Caller is not the owner'; + const ZERO_ADDRESS_CALLER: felt252 = 'Caller is the zero address'; + const ZERO_ADDRESS_OWNER: felt252 = 'New owner is the zero address'; +} \ No newline at end of file diff --git a/examples/piggy_bank/src/piggy_bank.cairo b/examples/piggy_bank/src/piggy_bank.cairo new file mode 100644 index 000000000..885954dab --- /dev/null +++ b/examples/piggy_bank/src/piggy_bank.cairo @@ -0,0 +1,203 @@ +use starknet::ContractAddress; + +#[derive(Drop, Serde, starknet::Store)] +enum target { + blockTime: u128, + amount: u128, +} + +#[starknet::interface] +trait IERC20 { + fn name(self: @TContractState) -> felt252; + fn symbol(self: @TContractState) -> felt252; + fn decimals(self: @TContractState) -> u8; + fn total_supply(self: @TContractState) -> u256; + fn balanceOf(self: @TContractState, account: ContractAddress) -> u256; + fn allowance(self: @TContractState, owner: ContractAddress, spender: ContractAddress) -> u256; + fn transfer(ref self: TContractState, recipient: ContractAddress, amount: u256) -> bool; + fn transferFrom( + ref self: TContractState, sender: ContractAddress, recipient: ContractAddress, amount: u256 + ) -> bool; + fn approve(ref self: TContractState, spender: ContractAddress, amount: u256) -> bool; +} + +#[starknet::interface] +trait piggyBankTrait { + fn deposit(ref self: TContractState, _amount: u128); + fn withdraw(ref self: TContractState, _amount: u128); + fn get_balance(self: @TContractState) -> u128; + fn get_Target(self: @TContractState) -> (u128 , piggyBank::targetOption) ; + fn get_owner(self: @TContractState) -> ContractAddress; + fn viewTarget(self: @TContractState) -> target; +} + +#[starknet::contract] +mod piggyBank { + use core::option::OptionTrait; + use core::traits::TryInto; + use starknet::{get_caller_address, ContractAddress, get_contract_address, Zeroable, get_block_timestamp}; + use super::{IERC20Dispatcher, IERC20DispatcherTrait, target}; + use core::traits::Into; + use piggy_bank::ownership_component::ownable_component; + component!(path: ownable_component, storage: ownable, event: OwnableEvent); + + + #[abi(embed_v0)] + impl OwnableImpl = ownable_component::Ownable; + impl OwnableInternalImpl = ownable_component::InternalImpl; + + #[storage] + struct Storage { + token: IERC20Dispatcher, + manager: ContractAddress, + balance: u128, + withdrawalCondition: target, + #[substorage(v0)] + ownable: ownable_component::Storage + } + + #[derive(Drop, Serde)] + enum targetOption { + targetTime, + targetAmount, + } + + #[event] + #[derive(Drop, starknet::Event)] + enum Event { + Deposit: Deposit, + Withdraw: Withdraw, + PaidProcessingFee: PaidProcessingFee, + OwnableEvent: ownable_component::Event + } + + #[derive(Drop, starknet::Event)] + struct Deposit { + #[key] + from: ContractAddress, + #[key] + Amount: u128, + } + + #[derive(Drop, starknet::Event)] + struct Withdraw { + #[key] + to: ContractAddress, + #[key] + Amount: u128, + #[key] + ActualAmount: u128, + } + + #[derive(Drop, starknet::Event)] + struct PaidProcessingFee { + #[key] + from: ContractAddress, + #[key] + Amount: u128, + } + + mod Errors { + const Address_Zero_Owner: felt252 = 'Invalid owner'; + const Address_Zero_Token: felt252 = 'Invalid Token'; + const UnAuthorized_Caller: felt252 = 'UnAuthorized caller'; + const Insufficient_Balance: felt252 = 'Insufficient balance'; + } + + #[constructor] + fn constructor(ref self: ContractState, _owner: ContractAddress, _token: ContractAddress, _manager: ContractAddress, target: targetOption, targetDetails: u128) { + assert(!_owner.is_zero(), Errors::Address_Zero_Owner); + assert(!_token.is_zero(), Errors::Address_Zero_Token); + self.ownable.owner.write(_owner); + self.token.write(super::IERC20Dispatcher{contract_address: _token}); + self.manager.write(_manager); + match target { + targetOption::targetTime => self.withdrawalCondition.write(target::blockTime(targetDetails.into())), + targetOption::targetAmount => self.withdrawalCondition.write(target::amount(targetDetails)), + } + } + + #[external(v0)] + impl piggyBankImpl of super::piggyBankTrait { + fn deposit(ref self: ContractState, _amount: u128) { + let (caller, this, currentBalance) = self.getImportantAddresses(); + self.balance.write(currentBalance + _amount); + + self.token.read().transferFrom(caller, this, _amount.into()); + + self.emit(Deposit { from: caller, Amount: _amount}); + } + + fn withdraw(ref self: ContractState, _amount: u128) { + self.ownable.assert_only_owner(); + let (caller, this, currentBalance) = self.getImportantAddresses(); + assert(self.balance.read() >= _amount, Errors::Insufficient_Balance); + + let mut new_amount: u128 = 0; + match self.withdrawalCondition.read() { + target::blockTime(x) => new_amount = self.verifyBlockTime(x, _amount), + target::amount(x) => new_amount = self.verifyTargetAmount(x, _amount), + }; + + self.balance.write(currentBalance - _amount); + self.token.read().transfer(caller, new_amount.into()); + + self.emit(Withdraw { to: caller, Amount: _amount, ActualAmount: new_amount}); + } + + fn get_balance(self: @ContractState) -> u128 { + self.balance.read() + } + + fn get_Target(self: @ContractState) -> (u128 , targetOption) { + let condition = self.withdrawalCondition.read(); + match condition { + target::blockTime(x) => {return (x, targetOption::targetTime);}, + target::amount(x) => {return (x, targetOption::targetAmount);}, + } + } + + fn get_owner(self: @ContractState) -> ContractAddress { + self.ownable.owner() + } + + fn viewTarget(self: @ContractState) -> target { + self.withdrawalCondition.read() + } + + } + + #[generate_trait] + impl Private of PrivateTrait { + fn verifyBlockTime(ref self: ContractState, blockTime: u128, withdrawalAmount: u128) -> u128 { + if (blockTime <= get_block_timestamp().into()) { + return withdrawalAmount; + } else { + return self.processWithdrawalFee(withdrawalAmount); + } + } + + fn verifyTargetAmount(ref self: ContractState, targetAmount: u128, withdrawalAmount: u128) -> u128 { + if (self.balance.read() < targetAmount) { + return self.processWithdrawalFee(withdrawalAmount); + } else { + return withdrawalAmount; + } + } + + fn processWithdrawalFee(ref self: ContractState, withdrawalAmount: u128) -> u128 { + let withdrawalCharge: u128 = ((withdrawalAmount * 10) / 100); + self.balance.write(self.balance.read() - withdrawalCharge); + self.token.read().transfer(self.manager.read(), withdrawalCharge.into()); + self.emit(PaidProcessingFee{from: get_caller_address(), Amount: withdrawalCharge}); + return withdrawalAmount - withdrawalCharge; + } + + fn getImportantAddresses(self: @ContractState) -> (ContractAddress, ContractAddress, u128) { + let caller: ContractAddress = get_caller_address(); + let this: ContractAddress = get_contract_address(); + let currentBalance: u128 = self.balance.read(); + (caller, this, currentBalance) + } + } +} diff --git a/examples/piggy_bank/src/piggy_factory.cairo b/examples/piggy_bank/src/piggy_factory.cairo new file mode 100644 index 000000000..0a72aaf2b --- /dev/null +++ b/examples/piggy_bank/src/piggy_factory.cairo @@ -0,0 +1,138 @@ +use starknet::{ContractAddress, ClassHash}; +use piggy_bank::piggy_bank::piggyBank::targetOption; +use array::ArrayTrait; + +#[starknet::interface] +trait IPiggyBankFactory { + fn createPiggyBank(ref self: TContractState, savingsTarget: targetOption, targetDetails: u128) -> ContractAddress; + fn updatePiggyBankHash(ref self: TContractState, newClasHash: ClassHash); + fn getAllPiggyBank(self: @TContractState) -> Array; + fn getPiggyBanksNumber(self: @TContractState) -> u128; + fn getPiggyBankAddr(self: @TContractState, userAddress: ContractAddress) -> ContractAddress; + fn get_owner(self: @TContractState) -> ContractAddress; + fn get_childClassHash(self: @TContractState) -> ClassHash; +} + +#[starknet::contract] +mod piggyFactory{ + use core::starknet::event::EventEmitter; +use piggy_bank::ownership_component::IOwnable; + use core::serde::Serde; + use starknet::{ContractAddress, ClassHash, get_caller_address, Zeroable}; + use starknet::syscalls::deploy_syscall; + use dict::Felt252DictTrait; + use super::targetOption; + use piggy_bank::ownership_component::ownable_component; + component!(path: ownable_component, storage: ownable, event: OwnableEvent); + + #[abi(embed_v0)] + impl OwnableImpl = ownable_component::Ownable; + impl OwnableInternalImpl = ownable_component::InternalImpl; + + #[storage] + struct Storage { + piggyBankHash: ClassHash, + totalPiggyBanksNo: u128, + AllBanksRecords: LegacyMap, + piggyBankOwner: LegacyMap::, + TokenAddr: ContractAddress, + #[substorage(v0)] + ownable: ownable_component::Storage + } + + #[event] + #[derive(Drop, starknet::Event)] + enum Event { + BankCreated: BankCreated, + HashUpdated: HashUpdated, + OwnableEvent: ownable_component::Event + } + + #[derive(Drop, starknet::Event)] + struct BankCreated { + #[key] + for: ContractAddress, + } + + #[derive(Drop, starknet::Event)] + struct HashUpdated { + #[key] + by: ContractAddress, + #[key] + oldHash: ClassHash, + #[key] + newHash: ClassHash, + } + + mod Errors { + const Address_Zero_Owner: felt252 = 'Invalid owner'; + } + + #[constructor] + fn constructor(ref self: ContractState, piggyBankClassHash: ClassHash, tokenAddr: ContractAddress, _owner: ContractAddress) { + self.piggyBankHash.write(piggyBankClassHash); + self.ownable.owner.write(_owner); + self.TokenAddr.write(tokenAddr); + } + + #[external(v0)] + impl piggyFactoryImpl of super::IPiggyBankFactory { + fn createPiggyBank(ref self: ContractState, savingsTarget: targetOption, targetDetails: u128) -> ContractAddress { + // Contructor arguments + let mut constructor_calldata = ArrayTrait::new(); + get_caller_address().serialize(ref constructor_calldata); + self.TokenAddr.read().serialize(ref constructor_calldata); + self.ownable.owner().serialize(ref constructor_calldata); + savingsTarget.serialize(ref constructor_calldata); + targetDetails.serialize(ref constructor_calldata); + + // Contract deployment + let (deployed_address, _) = deploy_syscall( + self.piggyBankHash.read(), 0, constructor_calldata.span(), false + ) + .expect('failed to deploy counter'); + self.totalPiggyBanksNo.write(self.totalPiggyBanksNo.read() + 1); + self.AllBanksRecords.write(self.totalPiggyBanksNo.read(), deployed_address); + self.piggyBankOwner.write(get_caller_address(), deployed_address); + self.emit(BankCreated{for: get_caller_address()}); + + deployed_address + } + + fn updatePiggyBankHash(ref self: ContractState, newClasHash: ClassHash) { + self.ownable.assert_only_owner(); + self.piggyBankHash.write(newClasHash); + self.emit(HashUpdated{by: self.ownable.owner(), oldHash: self.piggyBankHash.read(), newHash: newClasHash}); + } + + fn getAllPiggyBank(self: @ContractState) -> Array { + let mut piggyBanksAddress = ArrayTrait::new(); + let mut i: u128 = 1; + loop { + if i > self.totalPiggyBanksNo.read() { + break; + } + piggyBanksAddress.append(self.AllBanksRecords.read(i)); + i += 1; + }; + piggyBanksAddress + } + + fn getPiggyBanksNumber(self: @ContractState) -> u128 { + self.totalPiggyBanksNo.read() + } + fn getPiggyBankAddr(self: @ContractState, userAddress: ContractAddress) -> ContractAddress { + assert(!userAddress.is_zero(), Errors::Address_Zero_Owner); + self.piggyBankOwner.read(userAddress) + } + fn get_owner(self: @ContractState) -> ContractAddress { + self.ownable.owner() + } + + fn get_childClassHash(self: @ContractState) -> ClassHash { + self.piggyBankHash.read() + } + + } + +} \ No newline at end of file diff --git a/examples/piggy_bank/tests/lib.cairo b/examples/piggy_bank/tests/lib.cairo new file mode 100644 index 000000000..57cf3ed1e --- /dev/null +++ b/examples/piggy_bank/tests/lib.cairo @@ -0,0 +1,2 @@ +mod test_piggy_bank; +mod test_piggy_factory; \ No newline at end of file diff --git a/examples/piggy_bank/tests/test_piggy_bank.cairo b/examples/piggy_bank/tests/test_piggy_bank.cairo new file mode 100644 index 000000000..5f2702633 --- /dev/null +++ b/examples/piggy_bank/tests/test_piggy_bank.cairo @@ -0,0 +1,279 @@ +use core::{traits::Into, debug::PrintTrait}; +use array::ArrayTrait; +use result::ResultTrait; +use option::OptionTrait; +use traits::TryInto; +use starknet::{ContractAddress, get_contract_address, ClassHash}; +use starknet::Felt252TryIntoContractAddress; +use piggy_bank::piggy_bank::{piggyBankTraitDispatcher, piggyBankTraitDispatcherTrait, IERC20Dispatcher, IERC20DispatcherTrait, }; +use snforge_std::{declare, ContractClassTrait, start_prank, stop_prank, start_warp, stop_warp, env::var, ContractClass, get_class_hash}; + +mod testStorage { + const contract_address: felt252 = 0; +} + + +fn deploy_contract_forked(name: felt252, owner: ContractAddress, token: ContractAddress, manager: ContractAddress, target: u8, targetDetails: u128) -> ContractAddress { + let mut calldata = ArrayTrait::new(); + owner.serialize(ref calldata); + token.serialize(ref calldata); + manager.serialize(ref calldata); + target.serialize(ref calldata); + targetDetails.serialize(ref calldata); + let deployed_contract_address: ContractAddress = 0x042f0284511fb30a93defacad0c7d2a8968bfe0700fb54785337753e3b12720a.try_into().unwrap(); + // Precalculate the address to obtain the contract address before the constructor call (deploy) itself + let contract_address = ContractClass{class_hash: get_class_hash(deployed_contract_address)}.precalculate_address(@calldata); + start_prank(contract_address, owner.try_into().unwrap()); + let deployedContract = ContractClass{class_hash: get_class_hash(deployed_contract_address)}.deploy(@calldata).unwrap(); + stop_prank(contract_address); + + deployedContract +} + + +fn deploy_contract(name: felt252, owner: ContractAddress, token: ContractAddress, manager: ContractAddress, target: u8, targetDetails: u128) -> ContractAddress { + let contract = declare(name); + let mut calldata = ArrayTrait::new(); + owner.serialize(ref calldata); + token.serialize(ref calldata); + manager.serialize(ref calldata); + target.serialize(ref calldata); + targetDetails.serialize(ref calldata); + + // Precalculate the address to obtain the contract address before the constructor call (deploy) itself + let contract_address = contract.precalculate_address(@calldata); + + start_prank(contract_address, owner.try_into().unwrap()); + let deployedContract = contract.deploy(@calldata).unwrap(); + stop_prank(contract_address); + + deployedContract +} + + +fn get_important_addresses() ->(ContractAddress, ContractAddress, ContractAddress,) { + let caller: ContractAddress = 0x048242eca329a05af1909fa79cb1f9a4275ff89b987d405ec7de08f73b85588f.try_into().unwrap(); + let EthToken: ContractAddress = 0x049D36570D4e46f48e99674bd3fcc84644DdD6b96F7C741B1562B82f9e004dC7.try_into().unwrap(); + let this: ContractAddress = get_contract_address(); + return (caller, EthToken, this); +} + + +#[test] +fn test_initial_balance() { + let (caller, EthToken, this) = get_important_addresses(); + let targetSavings = 10_000000000000000000; + let contract_address = deploy_contract('piggyBank', caller, EthToken, this, 1, targetSavings); + let piggy_dispatcher = piggyBankTraitDispatcher { contract_address }; + let initial_balance: u128 = piggy_dispatcher.get_balance(); + + assert(initial_balance == 0, 'Invalid balance'); +} + + +#[test] +fn test_expected_owner() { + let (caller, EthToken, this) = get_important_addresses(); + let targetSavings = 10_000000000000000000; + let contract_address = deploy_contract('piggyBank', caller, EthToken, this, 1, targetSavings); + let piggy_dispatcher = piggyBankTraitDispatcher { contract_address }; + let owner: ContractAddress = piggy_dispatcher.get_owner(); + + assert(owner == caller, 'Unexpected owner'); +} + + +#[test] +#[fork("GoerliFork")] +fn test_deposit_into_Account() { + let (caller, EthToken, this) = get_important_addresses(); + let targetSavings = 10_000000000000000000; + let contract_address = deploy_contract_forked('piggyBank', caller, EthToken, this, 1, targetSavings); + let piggy_dispatcher = piggyBankTraitDispatcher { contract_address }; + let eth_dispatcher = IERC20Dispatcher{ contract_address: EthToken}; + let depositAmount: u128 = 1000000000000000000; + + start_prank(EthToken, caller); + eth_dispatcher.approve(contract_address, depositAmount.into()); + stop_prank(EthToken); + + start_prank(contract_address, caller); + piggy_dispatcher.deposit(depositAmount); + stop_prank(contract_address); + + let newBalance: u128 = eth_dispatcher.balanceOf(contract_address).try_into().unwrap(); + let currentBalance = piggy_dispatcher.get_balance(); + assert(currentBalance == depositAmount, 'WRONG CONTRACT BALANCE'); + assert(newBalance == depositAmount, 'CONTRACT BALANCE SHOULD TALLY'); +} + + +#[test] +#[fork("GoerliFork")] +fn test_withdraw_without_meeting_target_amount() { + let (caller, EthToken, this) = get_important_addresses(); + let targetSavings = 10_000000000000000000; + let contract_address = deploy_contract_forked('piggyBank', caller, EthToken, this, 1, targetSavings); + let piggy_dispatcher = piggyBankTraitDispatcher { contract_address }; + let eth_dispatcher = IERC20Dispatcher{ contract_address: EthToken}; + let depositAmount: u128 = 1000000000000000000; + + start_prank(EthToken, caller); + eth_dispatcher.approve(contract_address, depositAmount.into()); + stop_prank(EthToken); + + start_prank(contract_address, caller); + piggy_dispatcher.deposit(depositAmount); + let managerBlanceBefore = eth_dispatcher.balanceOf(this); + piggy_dispatcher.withdraw(depositAmount); + stop_prank(contract_address); + + let managerBlance = eth_dispatcher.balanceOf(this); + let expectedManagerBlance = (depositAmount * 10) / 100; + let piggyBalanceAfter = piggy_dispatcher.get_balance(); + let expectedPiggyBalanceAfter = 0; + + assert(managerBlance == expectedManagerBlance.into(), 'WRONG MANAGER BALANCE'); + assert(managerBlance != managerBlanceBefore, 'MANAGER BALANCE DOES NOT TALLY'); + assert(piggyBalanceAfter == expectedPiggyBalanceAfter, 'WRONG PIGGY BALANCE CALC'); +} + + +#[test] +#[fork("GoerliFork")] +fn test_withdraw_after_meeting_target_amount() { + let (caller, EthToken, this) = get_important_addresses(); + let targetSavings = 10_000000000000000000; + let contract_address = deploy_contract_forked('piggyBank', caller, EthToken, this, 1, targetSavings); + let piggy_dispatcher = piggyBankTraitDispatcher { contract_address }; + let eth_dispatcher = IERC20Dispatcher{ contract_address: EthToken}; + let depositAmount: u128 = 10000000000000000000; + + start_prank(EthToken, caller); + eth_dispatcher.approve(contract_address, depositAmount.into()); + stop_prank(EthToken); + + start_prank(contract_address, caller); + piggy_dispatcher.deposit(depositAmount); + + let managerBlanceBefore = eth_dispatcher.balanceOf(this); + + piggy_dispatcher.withdraw(depositAmount); + stop_prank(contract_address); + + let managerBlance = eth_dispatcher.balanceOf(this); + let expectedManagerBlance = 0; + let piggyBalanceAfter = piggy_dispatcher.get_balance(); + let expectedPiggyBalanceAfter = 0; + + assert(managerBlance == expectedManagerBlance.into(), 'WRONG MANAGER BALANCE'); + assert(managerBlance == managerBlanceBefore, 'MANAGER BALANCE DOES NOT TALLY'); + assert(piggyBalanceAfter == expectedPiggyBalanceAfter, 'WRONG PIGGY BALANCE CALC'); +} + + +#[test] +#[fork("GoerliFork")] +#[should_panic(expected: ('Caller is not the owner', ))] +fn test_UnAuthorized_user_withdrawal_Attempt() { + let (caller, EthToken, this) = get_important_addresses(); + let targetSavings = 10_000000000000000000; + let contract_address = deploy_contract_forked('piggyBank', caller, EthToken, this, 1, targetSavings); + let piggy_dispatcher = piggyBankTraitDispatcher { contract_address }; + let eth_dispatcher = IERC20Dispatcher{ contract_address: EthToken}; + let depositAmount: u128 = 10000000000000000000; + let unAuthorizedUser: ContractAddress = 123.try_into().unwrap(); + + start_prank(EthToken, caller); + eth_dispatcher.approve(contract_address, depositAmount.into()); + stop_prank(EthToken); + + start_prank(contract_address, caller); + piggy_dispatcher.deposit(depositAmount); + stop_prank(contract_address); + + let managerBlanceBefore = eth_dispatcher.balanceOf(this); + let UUBlanceBefore = eth_dispatcher.balanceOf(unAuthorizedUser); + let piggyBalanceBefore = piggy_dispatcher.get_balance(); + + start_prank(contract_address, unAuthorizedUser); + piggy_dispatcher.withdraw(depositAmount); + stop_prank(contract_address); + + let managerBlance = eth_dispatcher.balanceOf(this); + let UUBlanceAfter = eth_dispatcher.balanceOf(unAuthorizedUser); + let piggyBalanceAfter = piggy_dispatcher.get_balance(); + + assert(UUBlanceBefore == UUBlanceAfter, 'UNAUTHORIZED USER WITHDRAWAL'); + assert(piggyBalanceBefore == piggyBalanceAfter, 'UNAUTHORIZED LOSS OF FUNDS'); +} + + +#[test] +#[fork("GoerliFork")] +fn test_withdraw_after_meeting_target_time() { + let (caller, EthToken, this) = get_important_addresses(); + let targetTime = 1000; + let contract_address = deploy_contract_forked('piggyBank', caller, EthToken, this, 0, targetTime); + let piggy_dispatcher = piggyBankTraitDispatcher { contract_address }; + let eth_dispatcher = IERC20Dispatcher{ contract_address: EthToken}; + let depositAmount: u128 = 10000000000000000000; + let unAuthorizedUser: ContractAddress = 123.try_into().unwrap(); + + start_prank(EthToken, caller); + eth_dispatcher.approve(contract_address, depositAmount.into()); + stop_prank(EthToken); + + start_prank(contract_address, caller); + start_warp(contract_address, 100); + piggy_dispatcher.deposit(depositAmount); + let managerBlanceBefore = eth_dispatcher.balanceOf(this); + + start_warp(contract_address, 2100); + piggy_dispatcher.withdraw(depositAmount); + stop_prank(contract_address); + + let managerBlance = eth_dispatcher.balanceOf(this); + let expectedManagerBlance = 0; + let piggyBalanceAfter = piggy_dispatcher.get_balance(); + let expectedPiggyBalanceAfter = 0; + + assert(managerBlance == expectedManagerBlance.into(), 'WRONG MANAGER BALANCE'); + assert(managerBlance == managerBlanceBefore, 'MANAGER BALANCE DOES NOT TALLY'); + assert(piggyBalanceAfter == expectedPiggyBalanceAfter, 'WRONG PIGGY BALANCE CALC'); +} + +#[test] +#[fork("GoerliFork")] +fn test_withdraw_without_meeting_target_time() { + let (caller, EthToken, this) = get_important_addresses(); + let targetTime = 2000170827; + let contract_address = deploy_contract_forked('piggyBank', caller, EthToken, this, 0, targetTime); + let piggy_dispatcher = piggyBankTraitDispatcher { contract_address }; + let eth_dispatcher = IERC20Dispatcher{ contract_address: EthToken}; + let depositAmount: u128 = 10000000000000000000; + let unAuthorizedUser: ContractAddress = 123.try_into().unwrap(); + + start_prank(EthToken, caller); + eth_dispatcher.approve(contract_address, depositAmount.into()); + stop_prank(EthToken); + + start_prank(contract_address, caller); + piggy_dispatcher.deposit(depositAmount); + let managerBlanceBefore = eth_dispatcher.balanceOf(this); + piggy_dispatcher.withdraw(depositAmount); + stop_prank(contract_address); + + let managerBlance = eth_dispatcher.balanceOf(this); + let expectedManagerBlance = (depositAmount * 10) / 100; + let piggyBalanceAfter = piggy_dispatcher.get_balance(); + let expectedPiggyBalanceAfter = 0; + + assert(managerBlance == expectedManagerBlance.into(), 'WRONG MANAGER BALANCE'); + assert(managerBlance != managerBlanceBefore, 'MANAGER BALANCE DOES NOT TALLY'); + assert(piggyBalanceAfter == expectedPiggyBalanceAfter, 'WRONG PIGGY BALANCE CALC'); +} + + + + diff --git a/examples/piggy_bank/tests/test_piggy_factory.cairo b/examples/piggy_bank/tests/test_piggy_factory.cairo new file mode 100644 index 000000000..042f10f48 --- /dev/null +++ b/examples/piggy_bank/tests/test_piggy_factory.cairo @@ -0,0 +1,109 @@ +use core::option::OptionTrait; +use core::{traits::Into, debug::PrintTrait}; +use array::ArrayTrait; +use serde::Serde; +use traits::TryInto; +use starknet::{ContractAddress, get_contract_address, ClassHash}; +use starknet::Felt252TryIntoContractAddress; +use piggy_bank::piggy_bank::{piggyBankTraitDispatcher, piggyBankTraitDispatcherTrait, IERC20Dispatcher, IERC20DispatcherTrait, }; +use piggy_bank::piggy_bank::piggyBank::targetOption; +use snforge_std::{declare, ContractClassTrait, start_prank, stop_prank, start_warp, stop_warp, env::var}; +use piggy_bank::piggy_factory::{IPiggyBankFactoryDispatcher, IPiggyBankFactoryDispatcherTrait}; +use snforge_std::cheatcodes::contract_class::get_class_hash; + +fn deploy_contract(name: felt252, owner: ContractAddress) -> ContractAddress { + let piggy_bank_class = declare('piggyBank'); + let piggy_class_hash: ClassHash = piggy_bank_class.class_hash; + let EthToken: ContractAddress = 0x049D36570D4e46f48e99674bd3fcc84644DdD6b96F7C741B1562B82f9e004dC7.try_into().unwrap(); + + let contract = declare(name); + let mut calldata = ArrayTrait::new(); + piggy_class_hash.serialize(ref calldata); + EthToken.serialize(ref calldata); + owner.serialize(ref calldata); + + // Precalculate the address to obtain the contract address before the constructor call (deploy) itself + let contract_address = contract.precalculate_address(@calldata); + + // Change the caller address to 123 before the call to contract.deploy + start_prank(contract_address, owner.try_into().unwrap()); + let deployedContract = contract.deploy(@calldata).unwrap(); + stop_prank(contract_address); + + deployedContract +} + +fn get_important_addresses() ->(ContractAddress, ContractAddress, ContractAddress,) { + let caller: ContractAddress = 0x048242eca329a05af1909fa79cb1f9a4275ff89b987d405ec7de08f73b85588f.try_into().unwrap(); + let EthToken: ContractAddress = 0x049D36570D4e46f48e99674bd3fcc84644DdD6b96F7C741B1562B82f9e004dC7.try_into().unwrap(); + let this: ContractAddress = get_contract_address(); + return (caller, EthToken, this); +} + +#[test] +fn test_deploy_contract() { + let (caller, EthToken, this) = get_important_addresses(); + let contract_address = deploy_contract('piggyFactory', this); + let factory_dispatcher = IPiggyBankFactoryDispatcher{contract_address}; + let owner = factory_dispatcher.get_owner(); + assert (owner == this, 'WRONG CONTRACT OWNERSHIP'); +} + +#[test] +fn test_create_piggy_bank() { + let (caller, EthToken, this) = get_important_addresses(); + let contract_address = deploy_contract('piggyFactory', this); + let factory_dispatcher = IPiggyBankFactoryDispatcher{contract_address}; + let targetAmount = 10_000000000000000000; + + start_prank(contract_address, caller); + let user_piggy_1 = factory_dispatcher.createPiggyBank(targetOption::targetAmount, targetAmount); + let piggy_dispatcher = piggyBankTraitDispatcher{contract_address:user_piggy_1}; + let piggyOwner = piggy_dispatcher.get_owner(); + stop_prank(contract_address); + + assert(piggyOwner == caller, 'INCORECT PIGGYBANK OWNER'); +} + +#[test] +fn test_getAllPiggyBank() { + let (caller, EthToken, this) = get_important_addresses(); + let contract_address = deploy_contract('piggyFactory', this); + let factory_dispatcher = IPiggyBankFactoryDispatcher{contract_address}; + let targetAmount = 10_000000000000000000; + + start_prank(contract_address, caller); + let user_piggy_1 = factory_dispatcher.createPiggyBank(targetOption::targetAmount, targetAmount); + let piggy_dispatcher = piggyBankTraitDispatcher{contract_address:user_piggy_1}; + let piggyOwner = piggy_dispatcher.get_owner(); + stop_prank(contract_address); + + let piggy_bank_number = factory_dispatcher.getPiggyBanksNumber(); + let piggyAddr: ContractAddress = *factory_dispatcher.getAllPiggyBank().at(0); + + let piggyBanksLen = factory_dispatcher.getAllPiggyBank().len(); + let expectedPiggyBanksLen: u32 = 1; + + assert(piggyBanksLen == expectedPiggyBanksLen, 'INCORRECT BANK ARRAY LENGTH'); + assert(piggy_bank_number == expectedPiggyBanksLen.into(), 'INCORRECT PIGGYBANK NUMBER'); +} + +#[test] +fn test_track_user_piggy_bank() { + let (caller, EthToken, this) = get_important_addresses(); + let contract_address = deploy_contract('piggyFactory', this); + let factory_dispatcher = IPiggyBankFactoryDispatcher{contract_address}; + let targetAmount = 10_000000000000000000; + + start_prank(contract_address, caller); + let user_piggy_1 = factory_dispatcher.createPiggyBank(targetOption::targetAmount, targetAmount); + let piggy_dispatcher = piggyBankTraitDispatcher{contract_address:user_piggy_1}; + let piggyOwner = piggy_dispatcher.get_owner(); + stop_prank(contract_address); + + let piggyAddr: ContractAddress = *factory_dispatcher.getAllPiggyBank().at(0); + let usersBank: ContractAddress = factory_dispatcher.getPiggyBankAddr(caller); + + assert (usersBank == piggyAddr, 'FAULTY BANK ADDR TRACKING'); +} + From 2b8f70012426c1c22749472e5c168228bf6a7ae7 Mon Sep 17 00:00:00 2001 From: Nonnyjoe Date: Thu, 4 Jan 2024 02:34:02 +0100 Subject: [PATCH 2/2] complete migration to sepolia --- examples/piggy_bank/.gitignore | 4 +- examples/piggy_bank/Scarb.lock | 2 +- examples/piggy_bank/Scarb.toml | 13 ++- examples/piggy_bank/src/piggy_factory.cairo | 3 +- .../piggy_bank/tests/test_piggy_bank.cairo | 93 ++++++++++--------- .../piggy_bank/tests/test_piggy_factory.cairo | 18 ++-- 6 files changed, 68 insertions(+), 65 deletions(-) diff --git a/examples/piggy_bank/.gitignore b/examples/piggy_bank/.gitignore index 9d78812b7..73aa31e60 100644 --- a/examples/piggy_bank/.gitignore +++ b/examples/piggy_bank/.gitignore @@ -1,4 +1,2 @@ target -.snfoundry_cache -.env -env +.snfoundry_cache/ diff --git a/examples/piggy_bank/Scarb.lock b/examples/piggy_bank/Scarb.lock index 955e0c4a3..e5b8b5ba2 100644 --- a/examples/piggy_bank/Scarb.lock +++ b/examples/piggy_bank/Scarb.lock @@ -11,4 +11,4 @@ dependencies = [ [[package]] name = "snforge_std" version = "0.1.0" -source = "git+https://github.com/foundry-rs/starknet-foundry?tag=v0.10.1#2f1597fb724b7df3050468bd0e6a8a3a0e225001" +source = "git+https://github.com/foundry-rs/starknet-foundry?tag=v0.13.1#e1412ed040d10e66be0fd84115f72a667b57a116" diff --git a/examples/piggy_bank/Scarb.toml b/examples/piggy_bank/Scarb.toml index eaa5ce9d8..ba03fd288 100644 --- a/examples/piggy_bank/Scarb.toml +++ b/examples/piggy_bank/Scarb.toml @@ -1,20 +1,25 @@ [package] name = "piggy_bank" version = "0.1.0" +edition = "2023_10" # See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest.html [dependencies] -snforge_std = { git = "https://github.com/foundry-rs/starknet-foundry", tag = "v0.10.1" } -starknet = "2.3.1" +snforge_std = { git = "https://github.com/foundry-rs/starknet-foundry", tag = "v0.13.1" } +starknet = "2.4.1" [[target.starknet-contract]] casm = true [[tool.snforge.fork]] name = "GoerliFork" -url = "https://starknet-goerli.infura.io/v3/571aaed99608415397cb4eb46ca740c4" +url = "https://starknet-testnet.public.blastapi.io/rpc/v0_6" block_id.tag = "Latest" -RUST_BACKTRACE=1 +[[tool.snforge.fork]] +name = "SepoliaFork" +url = "https://starknet-sepolia.public.blastapi.io/rpc/v0_6" +block_id.tag = "Latest" +RUST_BACKTRACE=1 diff --git a/examples/piggy_bank/src/piggy_factory.cairo b/examples/piggy_bank/src/piggy_factory.cairo index 0a72aaf2b..2574b6cb2 100644 --- a/examples/piggy_bank/src/piggy_factory.cairo +++ b/examples/piggy_bank/src/piggy_factory.cairo @@ -1,6 +1,6 @@ use starknet::{ContractAddress, ClassHash}; use piggy_bank::piggy_bank::piggyBank::targetOption; -use array::ArrayTrait; + #[starknet::interface] trait IPiggyBankFactory { @@ -20,7 +20,6 @@ use piggy_bank::ownership_component::IOwnable; use core::serde::Serde; use starknet::{ContractAddress, ClassHash, get_caller_address, Zeroable}; use starknet::syscalls::deploy_syscall; - use dict::Felt252DictTrait; use super::targetOption; use piggy_bank::ownership_component::ownable_component; component!(path: ownable_component, storage: ownable, event: OwnableEvent); diff --git a/examples/piggy_bank/tests/test_piggy_bank.cairo b/examples/piggy_bank/tests/test_piggy_bank.cairo index 5f2702633..a14347431 100644 --- a/examples/piggy_bank/tests/test_piggy_bank.cairo +++ b/examples/piggy_bank/tests/test_piggy_bank.cairo @@ -6,7 +6,8 @@ use traits::TryInto; use starknet::{ContractAddress, get_contract_address, ClassHash}; use starknet::Felt252TryIntoContractAddress; use piggy_bank::piggy_bank::{piggyBankTraitDispatcher, piggyBankTraitDispatcherTrait, IERC20Dispatcher, IERC20DispatcherTrait, }; -use snforge_std::{declare, ContractClassTrait, start_prank, stop_prank, start_warp, stop_warp, env::var, ContractClass, get_class_hash}; +use snforge_std::{declare, ContractClassTrait, start_prank, stop_prank, start_warp, stop_warp, env::var, ContractClass, get_class_hash, CheatTarget}; +use snforge_std::BlockId; mod testStorage { const contract_address: felt252 = 0; @@ -23,9 +24,9 @@ fn deploy_contract_forked(name: felt252, owner: ContractAddress, token: Contract let deployed_contract_address: ContractAddress = 0x042f0284511fb30a93defacad0c7d2a8968bfe0700fb54785337753e3b12720a.try_into().unwrap(); // Precalculate the address to obtain the contract address before the constructor call (deploy) itself let contract_address = ContractClass{class_hash: get_class_hash(deployed_contract_address)}.precalculate_address(@calldata); - start_prank(contract_address, owner.try_into().unwrap()); + start_prank(CheatTarget::One(contract_address), owner.try_into().unwrap()); let deployedContract = ContractClass{class_hash: get_class_hash(deployed_contract_address)}.deploy(@calldata).unwrap(); - stop_prank(contract_address); + stop_prank(CheatTarget::One(contract_address)); deployedContract } @@ -43,16 +44,16 @@ fn deploy_contract(name: felt252, owner: ContractAddress, token: ContractAddress // Precalculate the address to obtain the contract address before the constructor call (deploy) itself let contract_address = contract.precalculate_address(@calldata); - start_prank(contract_address, owner.try_into().unwrap()); + start_prank(CheatTarget::One(contract_address), owner.try_into().unwrap()); let deployedContract = contract.deploy(@calldata).unwrap(); - stop_prank(contract_address); + stop_prank(CheatTarget::One(contract_address)); deployedContract } fn get_important_addresses() ->(ContractAddress, ContractAddress, ContractAddress,) { - let caller: ContractAddress = 0x048242eca329a05af1909fa79cb1f9a4275ff89b987d405ec7de08f73b85588f.try_into().unwrap(); + let caller: ContractAddress = 0x032e0bbab381cdc21c523699add33f9df9c80444ae174f81413f3122f4ed7b1f.try_into().unwrap(); let EthToken: ContractAddress = 0x049D36570D4e46f48e99674bd3fcc84644DdD6b96F7C741B1562B82f9e004dC7.try_into().unwrap(); let this: ContractAddress = get_contract_address(); return (caller, EthToken, this); @@ -84,22 +85,22 @@ fn test_expected_owner() { #[test] -#[fork("GoerliFork")] +#[fork("SepoliaFork")] fn test_deposit_into_Account() { let (caller, EthToken, this) = get_important_addresses(); let targetSavings = 10_000000000000000000; - let contract_address = deploy_contract_forked('piggyBank', caller, EthToken, this, 1, targetSavings); + let contract_address = deploy_contract('piggyBank', caller, EthToken, this, 1, targetSavings); let piggy_dispatcher = piggyBankTraitDispatcher { contract_address }; let eth_dispatcher = IERC20Dispatcher{ contract_address: EthToken}; let depositAmount: u128 = 1000000000000000000; - start_prank(EthToken, caller); + start_prank(CheatTarget::One(EthToken), caller); eth_dispatcher.approve(contract_address, depositAmount.into()); - stop_prank(EthToken); + stop_prank(CheatTarget::One(EthToken)); - start_prank(contract_address, caller); + start_prank(CheatTarget::One(contract_address), caller); piggy_dispatcher.deposit(depositAmount); - stop_prank(contract_address); + stop_prank(CheatTarget::One(contract_address)); let newBalance: u128 = eth_dispatcher.balanceOf(contract_address).try_into().unwrap(); let currentBalance = piggy_dispatcher.get_balance(); @@ -109,24 +110,24 @@ fn test_deposit_into_Account() { #[test] -#[fork("GoerliFork")] +#[fork("SepoliaFork")] fn test_withdraw_without_meeting_target_amount() { let (caller, EthToken, this) = get_important_addresses(); let targetSavings = 10_000000000000000000; - let contract_address = deploy_contract_forked('piggyBank', caller, EthToken, this, 1, targetSavings); + let contract_address = deploy_contract('piggyBank', caller, EthToken, this, 1, targetSavings); let piggy_dispatcher = piggyBankTraitDispatcher { contract_address }; let eth_dispatcher = IERC20Dispatcher{ contract_address: EthToken}; let depositAmount: u128 = 1000000000000000000; - start_prank(EthToken, caller); + start_prank(CheatTarget::One(EthToken), caller); eth_dispatcher.approve(contract_address, depositAmount.into()); - stop_prank(EthToken); + stop_prank(CheatTarget::One(EthToken)); - start_prank(contract_address, caller); + start_prank(CheatTarget::One(contract_address), caller); piggy_dispatcher.deposit(depositAmount); let managerBlanceBefore = eth_dispatcher.balanceOf(this); piggy_dispatcher.withdraw(depositAmount); - stop_prank(contract_address); + stop_prank(CheatTarget::One(contract_address)); let managerBlance = eth_dispatcher.balanceOf(this); let expectedManagerBlance = (depositAmount * 10) / 100; @@ -140,26 +141,26 @@ fn test_withdraw_without_meeting_target_amount() { #[test] -#[fork("GoerliFork")] +#[fork("SepoliaFork")] fn test_withdraw_after_meeting_target_amount() { let (caller, EthToken, this) = get_important_addresses(); let targetSavings = 10_000000000000000000; - let contract_address = deploy_contract_forked('piggyBank', caller, EthToken, this, 1, targetSavings); + let contract_address = deploy_contract('piggyBank', caller, EthToken, this, 1, targetSavings); let piggy_dispatcher = piggyBankTraitDispatcher { contract_address }; let eth_dispatcher = IERC20Dispatcher{ contract_address: EthToken}; let depositAmount: u128 = 10000000000000000000; - start_prank(EthToken, caller); + start_prank(CheatTarget::One(EthToken), caller); eth_dispatcher.approve(contract_address, depositAmount.into()); - stop_prank(EthToken); + stop_prank(CheatTarget::One(EthToken)); - start_prank(contract_address, caller); + start_prank(CheatTarget::One(contract_address), caller); piggy_dispatcher.deposit(depositAmount); let managerBlanceBefore = eth_dispatcher.balanceOf(this); piggy_dispatcher.withdraw(depositAmount); - stop_prank(contract_address); + stop_prank(CheatTarget::One(contract_address)); let managerBlance = eth_dispatcher.balanceOf(this); let expectedManagerBlance = 0; @@ -173,32 +174,32 @@ fn test_withdraw_after_meeting_target_amount() { #[test] -#[fork("GoerliFork")] +#[fork("SepoliaFork")] #[should_panic(expected: ('Caller is not the owner', ))] fn test_UnAuthorized_user_withdrawal_Attempt() { let (caller, EthToken, this) = get_important_addresses(); let targetSavings = 10_000000000000000000; - let contract_address = deploy_contract_forked('piggyBank', caller, EthToken, this, 1, targetSavings); + let contract_address = deploy_contract('piggyBank', caller, EthToken, this, 1, targetSavings); let piggy_dispatcher = piggyBankTraitDispatcher { contract_address }; let eth_dispatcher = IERC20Dispatcher{ contract_address: EthToken}; let depositAmount: u128 = 10000000000000000000; let unAuthorizedUser: ContractAddress = 123.try_into().unwrap(); - start_prank(EthToken, caller); + start_prank(CheatTarget::One(EthToken), caller); eth_dispatcher.approve(contract_address, depositAmount.into()); - stop_prank(EthToken); + stop_prank(CheatTarget::One(EthToken)); - start_prank(contract_address, caller); + start_prank(CheatTarget::One(contract_address), caller); piggy_dispatcher.deposit(depositAmount); - stop_prank(contract_address); + stop_prank(CheatTarget::One(contract_address)); let managerBlanceBefore = eth_dispatcher.balanceOf(this); let UUBlanceBefore = eth_dispatcher.balanceOf(unAuthorizedUser); let piggyBalanceBefore = piggy_dispatcher.get_balance(); - start_prank(contract_address, unAuthorizedUser); + start_prank(CheatTarget::One(contract_address), unAuthorizedUser); piggy_dispatcher.withdraw(depositAmount); - stop_prank(contract_address); + stop_prank(CheatTarget::One(contract_address)); let managerBlance = eth_dispatcher.balanceOf(this); let UUBlanceAfter = eth_dispatcher.balanceOf(unAuthorizedUser); @@ -210,28 +211,28 @@ fn test_UnAuthorized_user_withdrawal_Attempt() { #[test] -#[fork("GoerliFork")] +#[fork("SepoliaFork")] fn test_withdraw_after_meeting_target_time() { let (caller, EthToken, this) = get_important_addresses(); let targetTime = 1000; - let contract_address = deploy_contract_forked('piggyBank', caller, EthToken, this, 0, targetTime); + let contract_address = deploy_contract('piggyBank', caller, EthToken, this, 0, targetTime); let piggy_dispatcher = piggyBankTraitDispatcher { contract_address }; let eth_dispatcher = IERC20Dispatcher{ contract_address: EthToken}; let depositAmount: u128 = 10000000000000000000; let unAuthorizedUser: ContractAddress = 123.try_into().unwrap(); - start_prank(EthToken, caller); + start_prank(CheatTarget::One(EthToken), caller); eth_dispatcher.approve(contract_address, depositAmount.into()); - stop_prank(EthToken); + stop_prank(CheatTarget::One(EthToken)); - start_prank(contract_address, caller); - start_warp(contract_address, 100); + start_prank(CheatTarget::One(contract_address), caller); + start_warp(CheatTarget::One(contract_address), 100); piggy_dispatcher.deposit(depositAmount); let managerBlanceBefore = eth_dispatcher.balanceOf(this); - start_warp(contract_address, 2100); + start_warp(CheatTarget::One(contract_address), 2100); piggy_dispatcher.withdraw(depositAmount); - stop_prank(contract_address); + stop_prank(CheatTarget::One(contract_address)); let managerBlance = eth_dispatcher.balanceOf(this); let expectedManagerBlance = 0; @@ -244,25 +245,25 @@ fn test_withdraw_after_meeting_target_time() { } #[test] -#[fork("GoerliFork")] +#[fork("SepoliaFork")] fn test_withdraw_without_meeting_target_time() { let (caller, EthToken, this) = get_important_addresses(); let targetTime = 2000170827; - let contract_address = deploy_contract_forked('piggyBank', caller, EthToken, this, 0, targetTime); + let contract_address = deploy_contract('piggyBank', caller, EthToken, this, 0, targetTime); let piggy_dispatcher = piggyBankTraitDispatcher { contract_address }; let eth_dispatcher = IERC20Dispatcher{ contract_address: EthToken}; let depositAmount: u128 = 10000000000000000000; let unAuthorizedUser: ContractAddress = 123.try_into().unwrap(); - start_prank(EthToken, caller); + start_prank(CheatTarget::One(EthToken), caller); eth_dispatcher.approve(contract_address, depositAmount.into()); - stop_prank(EthToken); + stop_prank(CheatTarget::One(EthToken)); - start_prank(contract_address, caller); + start_prank(CheatTarget::One(contract_address), caller); piggy_dispatcher.deposit(depositAmount); let managerBlanceBefore = eth_dispatcher.balanceOf(this); piggy_dispatcher.withdraw(depositAmount); - stop_prank(contract_address); + stop_prank(CheatTarget::One(contract_address)); let managerBlance = eth_dispatcher.balanceOf(this); let expectedManagerBlance = (depositAmount * 10) / 100; diff --git a/examples/piggy_bank/tests/test_piggy_factory.cairo b/examples/piggy_bank/tests/test_piggy_factory.cairo index 042f10f48..f98007559 100644 --- a/examples/piggy_bank/tests/test_piggy_factory.cairo +++ b/examples/piggy_bank/tests/test_piggy_factory.cairo @@ -7,7 +7,7 @@ use starknet::{ContractAddress, get_contract_address, ClassHash}; use starknet::Felt252TryIntoContractAddress; use piggy_bank::piggy_bank::{piggyBankTraitDispatcher, piggyBankTraitDispatcherTrait, IERC20Dispatcher, IERC20DispatcherTrait, }; use piggy_bank::piggy_bank::piggyBank::targetOption; -use snforge_std::{declare, ContractClassTrait, start_prank, stop_prank, start_warp, stop_warp, env::var}; +use snforge_std::{declare, ContractClassTrait, start_prank, stop_prank, start_warp, stop_warp, env::var, CheatTarget}; use piggy_bank::piggy_factory::{IPiggyBankFactoryDispatcher, IPiggyBankFactoryDispatcherTrait}; use snforge_std::cheatcodes::contract_class::get_class_hash; @@ -26,9 +26,9 @@ fn deploy_contract(name: felt252, owner: ContractAddress) -> ContractAddress { let contract_address = contract.precalculate_address(@calldata); // Change the caller address to 123 before the call to contract.deploy - start_prank(contract_address, owner.try_into().unwrap()); + start_prank(CheatTarget::One(contract_address), owner.try_into().unwrap()); let deployedContract = contract.deploy(@calldata).unwrap(); - stop_prank(contract_address); + stop_prank(CheatTarget::One(contract_address)); deployedContract } @@ -56,11 +56,11 @@ fn test_create_piggy_bank() { let factory_dispatcher = IPiggyBankFactoryDispatcher{contract_address}; let targetAmount = 10_000000000000000000; - start_prank(contract_address, caller); + start_prank(CheatTarget::One(contract_address), caller); let user_piggy_1 = factory_dispatcher.createPiggyBank(targetOption::targetAmount, targetAmount); let piggy_dispatcher = piggyBankTraitDispatcher{contract_address:user_piggy_1}; let piggyOwner = piggy_dispatcher.get_owner(); - stop_prank(contract_address); + stop_prank(CheatTarget::One(contract_address)); assert(piggyOwner == caller, 'INCORECT PIGGYBANK OWNER'); } @@ -72,11 +72,11 @@ fn test_getAllPiggyBank() { let factory_dispatcher = IPiggyBankFactoryDispatcher{contract_address}; let targetAmount = 10_000000000000000000; - start_prank(contract_address, caller); + start_prank(CheatTarget::One(contract_address), caller); let user_piggy_1 = factory_dispatcher.createPiggyBank(targetOption::targetAmount, targetAmount); let piggy_dispatcher = piggyBankTraitDispatcher{contract_address:user_piggy_1}; let piggyOwner = piggy_dispatcher.get_owner(); - stop_prank(contract_address); + stop_prank(CheatTarget::One(contract_address)); let piggy_bank_number = factory_dispatcher.getPiggyBanksNumber(); let piggyAddr: ContractAddress = *factory_dispatcher.getAllPiggyBank().at(0); @@ -95,11 +95,11 @@ fn test_track_user_piggy_bank() { let factory_dispatcher = IPiggyBankFactoryDispatcher{contract_address}; let targetAmount = 10_000000000000000000; - start_prank(contract_address, caller); + start_prank(CheatTarget::One(contract_address), caller); let user_piggy_1 = factory_dispatcher.createPiggyBank(targetOption::targetAmount, targetAmount); let piggy_dispatcher = piggyBankTraitDispatcher{contract_address:user_piggy_1}; let piggyOwner = piggy_dispatcher.get_owner(); - stop_prank(contract_address); + stop_prank(CheatTarget::One(contract_address)); let piggyAddr: ContractAddress = *factory_dispatcher.getAllPiggyBank().at(0); let usersBank: ContractAddress = factory_dispatcher.getPiggyBankAddr(caller);