From 098f403d12440f7ec6d9f0802c33354b20b1251f Mon Sep 17 00:00:00 2001 From: Adetula Olamide <67712894+LamsyA@users.noreply.github.com> Date: Fri, 19 Jul 2024 09:14:03 +0100 Subject: [PATCH] simple_vault test implementation (#220) --- listings/applications/simple_vault/Scarb.toml | 1 + .../applications/simple_vault/src/lib.cairo | 1 + .../simple_vault/src/simple_vault.cairo | 162 ++++++++++++++++-- 3 files changed, 147 insertions(+), 17 deletions(-) diff --git a/listings/applications/simple_vault/Scarb.toml b/listings/applications/simple_vault/Scarb.toml index 346b42bb..561214d3 100644 --- a/listings/applications/simple_vault/Scarb.toml +++ b/listings/applications/simple_vault/Scarb.toml @@ -5,6 +5,7 @@ edition = '2023_11' [dependencies] starknet.workspace = true +erc20 = { path = "../erc20" } [scripts] test.workspace = true diff --git a/listings/applications/simple_vault/src/lib.cairo b/listings/applications/simple_vault/src/lib.cairo index b08098a0..b5492840 100644 --- a/listings/applications/simple_vault/src/lib.cairo +++ b/listings/applications/simple_vault/src/lib.cairo @@ -1,4 +1,5 @@ mod simple_vault; + #[cfg(test)] mod tests; diff --git a/listings/applications/simple_vault/src/simple_vault.cairo b/listings/applications/simple_vault/src/simple_vault.cairo index 22cd61b9..e8c0191b 100644 --- a/listings/applications/simple_vault/src/simple_vault.cairo +++ b/listings/applications/simple_vault/src/simple_vault.cairo @@ -4,23 +4,34 @@ use starknet::ContractAddress; // we need to have the interface of the remote ERC20 contract defined to import the Dispatcher. #[starknet::interface] pub trait IERC20 { - fn name(self: @TContractState) -> felt252; - fn symbol(self: @TContractState) -> felt252; - fn decimals(self: @TContractState) -> u8; - fn total_supply(self: @TContractState) -> u256; - fn balance_of(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 get_name(self: @TContractState) -> felt252; + fn get_symbol(self: @TContractState) -> felt252; + fn get_decimals(self: @TContractState) -> u8; + fn get_total_supply(self: @TContractState) -> felt252; + fn balance_of(self: @TContractState, account: ContractAddress) -> felt252; + fn allowance( + self: @TContractState, owner: ContractAddress, spender: ContractAddress + ) -> felt252; + fn transfer(ref self: TContractState, recipient: ContractAddress, amount: felt252); fn transfer_from( - ref self: TContractState, sender: ContractAddress, recipient: ContractAddress, amount: u256 - ) -> bool; - fn approve(ref self: TContractState, spender: ContractAddress, amount: u256) -> bool; + ref self: TContractState, + sender: ContractAddress, + recipient: ContractAddress, + amount: felt252 + ); + fn approve(ref self: TContractState, spender: ContractAddress, amount: felt252); + fn increase_allowance(ref self: TContractState, spender: ContractAddress, added_value: felt252); + fn decrease_allowance( + ref self: TContractState, spender: ContractAddress, subtracted_value: felt252 + ); } #[starknet::interface] pub trait ISimpleVault { fn deposit(ref self: TContractState, amount: u256); fn withdraw(ref self: TContractState, shares: u256); + fn user_balance_of(ref self: TContractState, account: ContractAddress) -> u256; + fn contract_total_supply(ref self: TContractState) -> u256; } #[starknet::contract] @@ -51,11 +62,22 @@ pub mod SimpleVault { self.total_supply.write(self.total_supply.read() - shares); self.balance_of.write(from, self.balance_of.read(from) - shares); } + } #[abi(embed_v0)] impl SimpleVault of super::ISimpleVault { - fn deposit(ref self: ContractState, amount: u256) { + + fn user_balance_of(ref self: ContractState, account: ContractAddress) -> u256 { + self.balance_of.read(account) + } + + fn contract_total_supply(ref self: ContractState) -> u256 { + self.total_supply.read() + } + + + fn deposit(ref self: ContractState, amount: u256){ // a = amount // B = balance of token before deposit // T = total supply @@ -71,12 +93,15 @@ pub mod SimpleVault { if self.total_supply.read() == 0 { shares = amount; } else { - let balance = self.token.read().balance_of(this); + let balance: u256 = self.token.read().balance_of(this).try_into() + .unwrap(); shares = (amount * self.total_supply.read()) / balance; } - - PrivateFunctions::_mint(ref self, caller, shares); - self.token.read().transfer_from(caller, this, amount); + + PrivateFunctions::_mint(ref self, caller, shares); + + let amount_felt252: felt252 = amount.low.into(); + self.token.read().transfer_from(caller, this, amount_felt252); } fn withdraw(ref self: ContractState, shares: u256) { @@ -91,11 +116,114 @@ pub mod SimpleVault { let caller = get_caller_address(); let this = get_contract_address(); - let balance = self.token.read().balance_of(this); + let balance = self.user_balance_of(this); let amount = (shares * balance) / self.total_supply.read(); PrivateFunctions::_burn(ref self, caller, shares); - self.token.read().transfer(caller, amount); + let amount_felt252: felt252 = amount.low.into(); + self.token.read().transfer(caller, amount_felt252); } } } +// ANCHOR_END: simple_vault + +#[cfg(test)] +mod tests { + use core::traits::Into; + use super::{ + SimpleVault, ISimpleVaultDispatcher, ISimpleVaultDispatcherTrait, IERC20Dispatcher, + IERC20DispatcherTrait + }; + + // use erc20::token::IERC20; + use erc20::token::{IERC20DispatcherTrait as IERC20DispatcherTrait_token, + IERC20Dispatcher as IERC20Dispatcher_token + }; + + use core::num::traits::Zero; + + use starknet::testing::{set_contract_address, set_account_contract_address}; + use starknet::{ + ContractAddress, SyscallResultTrait, syscalls::deploy_syscall, get_caller_address, + contract_address_const + }; + + const token_name: felt252 = 'myToken'; + const decimals: u8 = 18; + const initial_supply: felt252 = 100000; + const symbols: felt252 = 'mtk'; + + fn deploy() -> (ISimpleVaultDispatcher, ContractAddress, IERC20Dispatcher_token) { + let _token_address: ContractAddress = contract_address_const::<'token_address'>(); + let caller = contract_address_const::<'caller'>(); + + let (token_contract_address, _) = deploy_syscall( + erc20::token::erc20::TEST_CLASS_HASH.try_into().unwrap(), + caller.into(), + array![caller.into(), 'myToken', '8', '1000'.into(), 'MYT'].span(), + false + ) + .unwrap_syscall(); + + let (contract_address, _) = deploy_syscall( + SimpleVault::TEST_CLASS_HASH.try_into().unwrap(), + 0, + array![token_contract_address.into()].span(), + false + ) + .unwrap_syscall(); + ( + ISimpleVaultDispatcher { contract_address }, + contract_address, + IERC20Dispatcher_token { contract_address: token_contract_address } + ) + } + + #[test] + fn test_deposit() { + let caller = contract_address_const::<'caller'>(); + let (dispatcher, vault_address, token_dispatcher) = deploy(); + + // Approve the vault to transfer tokens on behalf of the caller + let amount: felt252 = 10.into(); + token_dispatcher.approve(vault_address.into(), amount); + set_contract_address(caller); + + // Deposit tokens into the vault + let amount: u256 = 10.into(); + let _deposit = dispatcher.deposit(amount); + println!("deposit :{:?}", _deposit); + + // Check balances and total supply + let balance_of_caller = dispatcher.user_balance_of(caller); + let total_supply = dispatcher.contract_total_supply(); + + assert(balance_of_caller == amount, 'Deposit failed'); + assert(total_supply == amount, 'total supply mismatch'); + + } + + #[test] + fn test_deposit_withdraw() { + let caller = contract_address_const::<'caller'>(); + let (dispatcher, vault_address, token_dispatcher) = deploy(); + + // Approve the vault to transfer tokens on behalf of the caller + let amount: felt252 = 10.into(); + token_dispatcher.approve(vault_address.into(), amount); + set_contract_address(caller); + set_account_contract_address(vault_address); + + // Deposit tokens into the vault + let amount: u256 = 10.into(); + dispatcher.deposit(amount); + dispatcher.withdraw(amount); + + // Check balances of user in the vault after withdraw + let balance_of_caller = dispatcher.user_balance_of(caller); + + assert(balance_of_caller == 0.into(), 'withdraw failed'); + } + + +} \ No newline at end of file