Assignment - SafeMath

Bank Contract w SafeMath integrated:

pragma solidity 0.8.0;

pragma abicoder v2;
import "./Ownable.sol";
import "Safemath.sol";

contract Bank is Ownable {

    using SafeMath for uint256;
    
    mapping(address => uint) balance;
    address[] customers;
    
    event depositDone(uint amount, address indexed depositedTo);
    
    function deposit() public payable returns (uint)  {
        balance[msg.sender] += msg.value;
        emit depositDone(msg.value, msg.sender);
        return balance[msg.sender];
    }
    
    function withdraw(uint amount) public onlyOwner returns (uint){
        require(balance[msg.sender] >= amount);
        balance[msg.sender] -= amount;
        payable(msg.sender).transfer(amount);
        return balance[msg.sender];
    }
    
    function getBalance() public view returns (uint){
        return balance[msg.sender];
    }
    
    function transfer(address recipient, uint amount) public {
        require(balance[msg.sender] >= amount, "Balance not sufficient");
        require(msg.sender != recipient, "Don't transfer money to yourself");
        
        uint previousSenderBalance = balance[msg.sender];
        
        _transfer(msg.sender, recipient, amount);
        
        assert(balance[msg.sender] == previousSenderBalance - amount);
    }
    
    function _transfer(address from, address to, uint amount) private {
        balance[from] -= amount;
        balance[to] += amount;
    }
    
}

2 Likes
pragma solidity 0.8.0;
pragma abicoder v2;
import "./ownable.sol";
import "./Safemath.sol";

contract Bank is Ownable {

    using SafeMath for uint256;
   
    mapping(address => uint) balance;
    address[] customers;
   
    event depositDone(uint amount, address indexed depositedTo);
   
    function deposit() public payable returns (uint)  {
        balance[msg.sender] = balance[msg.sender].add(msg.value); //change the syntax for add/ subtract lines
        emit depositDone(msg.value, msg.sender);
        return balance[msg.sender];
    }
   
    function withdraw(uint amount) public onlyOwner returns (uint){
        require(balance[msg.sender] >= amount);
        balance[msg.sender] = balance[msg.sender].sub(amount);  // change
        payable(msg.sender).transfer(amount);
        return balance[msg.sender];
    }
   
    function getBalance() public view returns (uint){
        return balance[msg.sender];
    }
   
    function transfer(address recipient, uint amount) public {
        require(balance[msg.sender] >= amount, "Balance not sufficient");
        require(msg.sender != recipient, "Don't transfer money to yourself");
       
        uint previousSenderBalance = balance[msg.sender];
       
        _transfer(msg.sender, recipient, amount);
       
        assert(balance[msg.sender] == previousSenderBalance - amount);
    }
   
    function _transfer(address from, address to, uint amount) private {
        balance[from] = balance[from].sub(amount);  //change
        balance[to] = balance[from].add(amount);  //change
    }
   
}
1 Like

niceee mann. i really like this solution because you are experimenting with interfaces. well done. its a good sign that u understand their purpose this early on and how you can use interfaces to access functions in a smart contract without having to import the whole thing so great job. one thing you could do just to clean up your declaration of government is to make the address either a public or private global var (visibility is up to you)

address public GOVERNMENT_ADDRESS = 0xd8b934580fcE35a11B58C6D73aDeE468a2833fa8;
GovermentInterface govermentInstance =  GovermentInterface(GOVERNMENT_ADDRESS );

but this is just a nit pick. one other thing you can do is to make a require in your deposit function to make sure the user cannot input a negative or 0 amount

function deposit() public payable returns (uint){`
        require(msg.value > 0 , "amount too low");
        balance[msg.sender] = SafeMath.add(balance[msg.sender], msg.value);  
        emit depositDone(msg.value, msg.sender);
        return balance[msg.sender];
    }

you also dont need to return uints or addresses on state changing functions as you cannnot access return vars from such a function. sometimes a common approach is to return a bool like returns (bool _success) and if you function passes return this bool. but other than this great solution man keep it up

1 Like

Here is my solution for the assignment

1 Like

Hello, this is my solution for the assignment

// SPDX-License-Identifier: UNLICENSED

pragma solidity 0.7.5;

pragma abicoder v2;

import "./Ownable.sol";

import "./safemath.sol";

contract Bank is Ownable {

   

    using SafeMath for uint256;

    mapping(address => uint256) balance;

    address[] customers;

   

    event depositDone(uint amount, address indexed depositedTo);

   

    function deposit() public payable returns (uint)  {

         balance[msg.sender] = balance[msg.sender].add(msg.value);

        emit depositDone(msg.value, msg.sender);

        return balance[msg.sender];

    }

   

    function withdraw(uint amount) public OnlyOwner returns (uint){

        require(balance[msg.sender] >= amount);

        //balance[msg.sender] -= amount;

         balance[msg.sender] = balance[msg.sender].sub(amount);

        payable(msg.sender).transfer(amount);

        return balance[msg.sender];

    }

   

    function getBalance() public view returns (uint){

        return balance[msg.sender];

    }

   

    function transfer(address recipient, uint amount) public {

        require(balance[msg.sender] >= amount, "Balance not sufficient");

        require(msg.sender != recipient, "Don't transfer money to yourself");

       

        uint previousSenderBalance = balance[msg.sender];

       

        _transfer(msg.sender, recipient, amount);

       

        assert(balance[msg.sender] == previousSenderBalance - amount);

    }

   

    function _transfer(address from, address to, uint amount) private {

          balance[from] = balance[from].sub(amount);// balance[from] -= amount;

          balance[to] = balance[to].add(amount);   //balance[to] += amount;

    }

   

}
1 Like

nice. you know you can copy and paste your code and directly paste it into the text editor here properly formatted

pragma solidity 0.8.0;
pragma abicoder v2;
import "./Ownable.sol";
import "./safemath.sol";

contract Bank is Ownable {
    
    mapping(address => uint) balance;
    address[] customers;

    using SafeMath for uint256;
    
    event depositDone(uint amount, address indexed depositedTo);
    
    function deposit() public payable returns (uint)  {
        balance[msg.sender] += msg.value;
        emit depositDone(msg.value, msg.sender);
        return balance[msg.sender];
    }
    
    function withdraw(uint amount) public onlyOwner returns (uint){
        require(balance[msg.sender] >= amount);
        balance[msg.sender] -= amount;
        payable(msg.sender).transfer(amount);
        return balance[msg.sender];
    }
    
    function getBalance() public view returns (uint){
        return balance[msg.sender];
    }
    
    function transfer(address recipient, uint amount) public {
        require(balance[msg.sender] >= amount, "Balance not sufficient");
        require(msg.sender != recipient, "Don't transfer money to yourself");
        
        uint previousSenderBalance = balance[msg.sender];
        
        _transfer(msg.sender, recipient, amount);
        
        assert(balance[msg.sender] == previousSenderBalance - amount);
    }
    
    function _transfer(address from, address to, uint amount) private {
        balance[from] -= amount;
        balance[to] += amount;
    }
    
}
1 Like

My only differences with your solutions are the following 2 :

  • I editted the assert statement as follow : assert(balance[msg.sender] == sub(previousSenderBalance, amount);

  • I introduced the library using uint256 instead of just uint.

Does this make any difference ?

//SPDX-License-Identifier: UNLICENSED 
pragma solidity 0.8.7;
pragma abicoder v2;
import "./Ownable.sol";
import "./Safemath.sol";


contract Bank is Ownable {

    using SafeMath for uint256;
    
    mapping(address => uint) balance;
    address[] customers;
    
    event depositDone(uint amount, address indexed depositedTo);
    
    function deposit() public payable returns (uint)  {
        balance[msg.sender] =  balance[msg.sender].add(msg.value) //balance[msg.sender] += msg.value;
        emit depositDone(msg.value, msg.sender);
        return balance[msg.sender];
    }
    
    function withdraw(uint amount) public onlyOwner returns (uint){
        require(balance[msg.sender] >= amount);
        balance[msg.sender] = balance[msg.sender].sub(amount)//balance[msg.sender] -= amount;
        payable(msg.sender).transfer(amount);
        return balance[msg.sender];
    }
    
    function getBalance() public view returns (uint){
        return balance[msg.sender];
    }
    
    function transfer(address recipient, uint amount) public {
        require(balance[msg.sender] >= amount, "Balance not sufficient");
        require(msg.sender != recipient, "Don't transfer money to yourself");
        
        uint previousSenderBalance = balance[msg.sender];
        
        _transfer(msg.sender, recipient, amount);
        
        //assert(balance[msg.sender] == previousSenderBalance - amount);
        assert(balance[msg.sender] == sub(previousSenderBalance, amount);
    }
    
    function _transfer(address from, address to, uint amount) private {
        balance[from] = balance[from].sub(amount);//balance[from] -= amount;
        balance[to] = balance[to].add(amount);//balance[to] += amount;
    }
    
}
1 Like

While testing regular or unsafe math, I noticed when subtracting from 0, it seemed to revert at least starting in solidity 0.8.0 can anyone comment on this? I tested addition with uint8 and found the the it also reverts

Here is my code for the assignment

pragma solidity 0.8.0;
pragma abicoder v2;
import "./Ownable.sol";
import "./Safemath.sol";

contract Bank is Ownable {
    using SafeMath for uint;

    mapping(address => uint) balance;
    address[] customers;
    
    event depositDone(uint amount, address indexed depositedTo);
    
    function deposit() public payable returns (uint)  {
        balance[msg.sender] = balance[msg.sender].add(msg.value);
        // balance[msg.sender] += msg.value;
        emit depositDone(msg.value, msg.sender);
        return balance[msg.sender];
    }
    
    function withdraw(uint amount) public onlyOwner returns (uint){
        require(balance[msg.sender] >= amount);
        balance[msg.sender] = balance[msg.sender].sub(amount);
        payable(msg.sender).transfer(amount);
        return balance[msg.sender];
    }
    
    function getBalance() public view returns (uint){
        return balance[msg.sender];
    }
    
    function transfer(address recipient, uint amount) public {
        require(balance[msg.sender] >= amount, "Balance not sufficient");
        require(msg.sender != recipient, "Don't transfer money to yourself");
        
        uint previousSenderBalance = balance[msg.sender];
        
        _transfer(msg.sender, recipient, amount);
        
        assert(balance[msg.sender] == previousSenderBalance - amount);
    }
    
    function _transfer(address from, address to, uint amount) private {
        balance[from] = balance[from].sub(amount);
        balance[to] = balance[to].add(amount);
    }
    
}```
1 Like
pragma solidity 0.8.0;

//pragma abicoder v2;
import "./Ownable.sol";
import "./SafeMath.sol";

contract Bank is Ownable {

    using SafeMath for uint256;
    
    mapping(address => uint) balance;
    address[] customers;
    
    event depositDone(uint amount, address indexed depositedTo);
    
    function deposit() public payable returns (uint)  {
        balance[msg.sender].add(msg.value);
        emit depositDone(msg.value, msg.sender);
        return balance[msg.sender];
    }
    
    function withdraw(uint amount) public onlyOwner returns (uint){
        require(balance[msg.sender] >= amount);
        balance[msg.sender].sub(amount);
        payable(msg.sender).transfer(amount);
        return balance[msg.sender];
    }
    
    function getBalance() public view returns (uint){
        return balance[msg.sender];
    }
    
    function transfer(address recipient, uint amount) public {
        require(balance[msg.sender] >= amount, "Balance not sufficient");
        require(msg.sender != recipient, "Don't transfer money to yourself");
        
        uint previousSenderBalance = balance[msg.sender];
        
        _transfer(msg.sender, recipient, amount);
        
        assert(balance[msg.sender] == previousSenderBalance.sub(amount));
    }
    
    function _transfer(address from, address to, uint amount) private view{
        balance[from].sub(amount);
        balance[to].add(amount);
    }
    
}
1 Like

thanks!! I’ll look into that
later on in the course I found this warning that I don’t really knows what it means
the line that throws the warning is : msg.sender.call{value:_amount}("");
and the warning is: Return value of low-level calls not used.
Thanks in advance
Ale

1 Like

Here is my SafeMath implementation:

pragma solidity 0.8.0;
pragma abicoder v2;
import "./Ownable.sol";
import "./Safemath.sol";

contract Bank is Ownable {

    using SafeMath for uint;
    
    mapping(address => uint) balance;
    address[] customers;
    
    event depositDone(uint amount, address indexed depositedTo);
    
    function deposit() public payable returns (uint)  {
        balance[msg.sender] = balance[msg.sender].add(msg.value);
        emit depositDone(msg.value, msg.sender);
        return balance[msg.sender];
    }
    
    function withdraw(uint amount) public onlyOwner returns (uint){
        require(balance[msg.sender] >= amount);
        balance[msg.sender] = balance[msg.sender].sub(msg.value);
        payable(msg.sender).transfer(amount);
        return balance[msg.sender];
    }
    
    function getBalance() public view returns (uint){
        return balance[msg.sender];
    }
    
    function transfer(address recipient, uint amount) public {
        require(balance[msg.sender] >= amount, "Balance not sufficient");
        require(msg.sender != recipient, "Don't transfer money to yourself");
        
        uint previousSenderBalance = balance[msg.sender];
        
        _transfer(msg.sender, recipient, amount);
        
        assert(balance[msg.sender] == previousSenderBalance - amount);
    }
    
    function _transfer(address from, address to, uint amount) private {
        balance[from] = balance[from].add(amount);
        balance[to] = balance[to].sub(amount);
    }
    
}

If something i wrong, please let me know

pragma solidity 0.8.0;
pragma abicoder v2;
import "./Ownable.sol";
import "./safemath.sol"

contract Bank is Ownable {

    using SafeMath for uint256
    
    mapping(address => uint) balance;
    address[] customers;
    
    event depositDone(uint amount, address indexed depositedTo);
    
    function deposit() public payable returns (uint)  {
        balance[msg.sender] += msg.value;
        emit depositDone(msg.value, msg.sender);
        return balance[msg.sender];
    }
    
    function withdraw(uint amount) public onlyOwner returns (uint){
        require(balance[msg.sender] >= amount);
        balance[msg.sender] -= amount;
        payable(msg.sender).transfer(amount);
        return balance[msg.sender];
    }
    
    function getBalance() public view returns (uint){
        return balance[msg.sender];
    }
    
    function transfer(address recipient, uint amount) public {
        require(balance[msg.sender] >= amount, "Balance not sufficient");
        require(msg.sender != recipient, "Don't transfer money to yourself");
        
        uint previousSenderBalance = balance[msg.sender];
        
        _transfer(msg.sender, recipient, amount);
        
        assert(balance[msg.sender] == previousSenderBalance - amount);
    }
    
    function _transfer(address from, address to, uint amount) private {
        balance[from] -= amount;
        balance[to] += amount;
    }
    
}
1 Like

hey Mildo can u past your exact code for this ill take a look

Safemath Code

pragma solidity 0.8.0;
pragma abicoder v2;
import "./Ownable.sol";
import "./Safemath.sol"

contract Bank is Ownable {
    using SafeMath for uint256

    mapping(address => uint) balance;
    address[] customers;
    
    event depositDone(uint amount, address indexed depositedTo);
    
    function deposit() public payable returns (uint)  {
        balance[msg.sender] = balance[msg.sender].add(msg.value);
        emit depositDone(msg.value, msg.sender);
        return balance[msg.sender];
    }
    
    function withdraw(uint amount) public onlyOwner returns (uint){
        require(balance[msg.sender] >= amount);
        balance[msg.sender] = balance[msg.sender].sub(msg.value);
        payable(msg.sender).transfer(amount);
        return balance[msg.sender];
    }
    
    function getBalance() public view returns (uint){
        return balance[msg.sender];
    }
    
    function transfer(address recipient, uint amount) public {
        require(balance[msg.sender] >= amount, "Balance not sufficient");
        require(msg.sender != recipient, "Don't transfer money to yourself");
        
        uint previousSenderBalance = balance[msg.sender];
        
        _transfer(msg.sender, recipient, amount);
        
        assert(balance[msg.sender] == previousSenderBalance - amount);
    }
    
    function _transfer(address from, address to, uint amount) private {
        balance[from] = balance[from].add(amount);
        balance[to] = balance[to].sub(amount)
    }
    
}


1 Like

Hello @mcgrane5
this is the contract where the warning/error appears and i don’t understand it

// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.14;

import "@openzeppelin/contracts/utils/Counters.sol";
import "@openzeppelin/contracts/access/AccessControl.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";

contract Wallet is AccessControl, ReentrancyGuard{
    using Counters for Counters.Counter;
    using SafeMath for uint256;

    bytes32 public constant TOKEN_REGISTRATOR_ROLE = keccak256("TOKEN_REGISTRATOR_ROLE");
    bytes32 public constant TOKEN_REGISTRATOR_ADMIN_ROLE = keccak256("TOKEN_REGISTRATOR_ADMIN_ROLE");
    bytes32 public constant CONTRACT_DESTROYER_ROLE = keccak256("CONTRACT_DESTROYER_ROLE");

    // maps address to token-ticker to amounts
    // usa bytes32 en lugar de string por que en solidity no se pueden comparar strings
    mapping(address => mapping(bytes32 => uint256)) public balances;

    struct Token{
        bytes32 ticker;
        address tokenAddress;
    }

    bytes32[] public tokenList; // List with all the tickers registered -- ability to iterate thru all the tokens
    mapping(bytes32 => Token) public tokenMapping; //for each ticker get the token 
    
    event TokenRegisteredEvent(bytes32 indexed ticker, address indexed tokenAddress);
    event TokenDepositApproved(bytes32 indexed ticker, uint amount, address account);
    event TokenDepositRejected(bytes32 indexed ticker, uint amount, address account);
    event TokenDepositDone(bytes32 indexed ticker, uint amount, address account);

    event DebugBalanceOf(bytes32 indexed ticker, uint amount, address account);

    modifier tokenExist(bytes32 token){
        require(tokenMapping[token].tokenAddress != address(0), "Token should be registered first");
        _;
    }

    constructor(){
        _grantRole(TOKEN_REGISTRATOR_ADMIN_ROLE, _msgSender());
        _grantRole(TOKEN_REGISTRATOR_ROLE, _msgSender());
        _grantRole(DEFAULT_ADMIN_ROLE, _msgSender());
        _setRoleAdmin(TOKEN_REGISTRATOR_ROLE, TOKEN_REGISTRATOR_ADMIN_ROLE);
        _grantRole(CONTRACT_DESTROYER_ROLE, _msgSender());
    }

    function balanceOf(bytes32 _ticker, address user) public returns (uint256){
        emit DebugBalanceOf(_ticker, balances[user][_ticker] , user);
        return balances[user][_ticker];
    }

    function registerToken(bytes32 _ticker, address _tokenAddress) external onlyRole(TOKEN_REGISTRATOR_ROLE){
        tokenMapping[_ticker] =Token(_ticker, _tokenAddress);
        tokenList.push(_ticker);
        emit TokenRegisteredEvent(_ticker, _tokenAddress);
    }

    function deposit(uint _amount, bytes32 _ticker) tokenExist(_ticker) external {
        
        balances[msg.sender][_ticker] = SafeMath.add(balances[msg.sender][_ticker], _amount);
        IERC20 token = IERC20(tokenMapping[_ticker].tokenAddress);
        uint allowence = token.allowance(_msgSender(), address(this)); 
        if (allowence >= _amount){
            emit TokenDepositApproved(_ticker, _amount, msg.sender);
            IERC20(tokenMapping[_ticker].tokenAddress).transferFrom(msg.sender, address(this), _amount);
            emit TokenDepositDone(_ticker, _amount, msg.sender);
        }else{
            emit TokenDepositRejected(_ticker, _amount, msg.sender);
            balances[msg.sender][_ticker] = SafeMath.sub(balances[msg.sender][_ticker], _amount);
        }
        
    }
    function depositEth() payable external {
        balances[msg.sender][bytes32("ETH")] = SafeMath.add(balances[msg.sender][bytes32("ETH")], msg.value);
    }

    function withdrawEth(uint _amount) payable external nonReentrant {
        require(balances[msg.sender][bytes32("ETH")] > _amount, "Insufficient balance");
        balances[msg.sender][bytes32("ETH")] = SafeMath.sub(balances[msg.sender][bytes32("ETH")], msg.value);
        msg.sender.call{value:_amount}("");
    }

    function withdraw(uint _amount, bytes32 _ticker) tokenExist(_ticker) external{
        require( balances[msg.sender][_ticker] >= _amount, "balance should be bigger than the amount");

        balances[msg.sender][_ticker] = SafeMath.sub(balances[msg.sender][_ticker], _amount);
        IERC20(tokenMapping[_ticker].tokenAddress).transfer(msg.sender, _amount);
    }
    
    function destroy()  onlyRole(CONTRACT_DESTROYER_ROLE) external {
        selfdestruct(payable(_msgSender()));
    }
}

Regards
Mildo

1 Like

i looked into this. and this was just a warning so you dont need to worry. what its refferring to is thr msg.sender.call() has a boolean return value based on if the transfer has failed or not. this return value can be used to error handle. but since your not using it here thats why the warning is getting thrown

1 Like

Bank with Safemath

Summary
pragma solidity 0.8.0;
pragma abicoder v2;
import "./Ownable.sol";
import "./safemath.sol";

contract Bank is Ownable {
    
    using SafeMath for uint256;

    mapping(address => uint256) balance;
    address[] customers;
    
    event depositDone(uint256 amount, address indexed depositedTo);
    
    function deposit() public payable returns (uint256)  {
        balance[msg.sender] = balance[msg.sender].add(msg.value);
        emit depositDone(msg.value, msg.sender);
        return balance[msg.sender];
    }
    
    function withdraw(uint256 amount) public onlyOwner returns (uint256){
        require(balance[msg.sender] >= amount);
        balance[msg.sender] = balance[msg.sender].sub(amount);
        payable(msg.sender).transfer(amount);
        return balance[msg.sender];
    }
    
    function getBalance() public view returns (uint256){
        return balance[msg.sender];
    }
    
    function transfer(address recipient, uint256 amount) public {
        require(balance[msg.sender] >= amount, "Balance not sufficient");
        require(msg.sender != recipient, "Don't transfer money to yourself");
        
        uint previousSenderBalance = balance[msg.sender];
        
        _transfer(msg.sender, recipient, amount);
        
        assert(balance[msg.sender] == previousSenderBalance - amount);
    }
    
    function _transfer(address from, address to, uint256 amount) private {
        balance[from] = balance[from].sub(amount);
        balance[to] = balance[to].add(amount);
    }
    
}
1 Like

Here’s my solution for using Safemath on the Bank contract:

pragma solidity 0.8.0;
pragma abicoder v2;
import "Ownable.sol";
import "Safemath.sol";

contract Bank is Ownable {

    using SafeMath for uint;
    
    mapping(address => uint) balance;
    address[] customers;
    
    event depositDone(uint amount, address indexed depositedTo);
    
    function deposit() public payable returns (uint)  {
        balance[msg.sender] = balance[msg.sender].add(msg.value);//balance[msg.sender] += msg.value;
        emit depositDone(msg.value, msg.sender);
        return balance[msg.sender];
    }
    
    function withdraw(uint amount) public onlyOwner returns (uint){
        require(balance[msg.sender] >= amount);
        balance[msg.sender] = balance[msg.sender].sub(amount);//balance[msg.sender] -= amount;
        payable(msg.sender).transfer(amount);
        return balance[msg.sender];
    }
    
    function getBalance() public view returns (uint){
        return balance[msg.sender];
    }
    
    function transfer(address recipient, uint amount) public {
        require(balance[msg.sender] >= amount, "Balance not sufficient");
        require(msg.sender != recipient, "Don't transfer money to yourself");
        
        uint previousSenderBalance = balance[msg.sender];
        
        _transfer(msg.sender, recipient, amount);
        
        assert(balance[msg.sender] == previousSenderBalance - amount);
    }
    
    function _transfer(address from, address to, uint amount) private {
        balance[from] = balance[from].sub(amount);//balance[from] -= amount;
        balance[to] = balance[to].add(amount);//balance[to] += amount;
    }
    
}

Also, I’ve a question for the team:

What do you think are best practices for not loosing files in Remix? Any thoughts on how to best organize a massive workflow here?

I just accidently lost some files. Probably because I cleared my browser history of the last hour, which I only do in emergencies, like being stuck on an error page in this forum and not being able to go back. Unfortunately downloading my workspace didn’t help for recovery. I guess because all files were just free floating inside the workspace and not archived in the default contracts folder.
Of course Remix is for editing and learning, so there’s no problem starting over. But I just like to keep track of my files for future study reference.

Here is my assignment for Safemath

pragma solidity 0.8.7;
pragma abicoder v2;
import "./Ownable.sol";
import "safemath.sol";

contract Bank is Ownable {
    
    using safemath for uint;

    mapping(address => uint) balance;
    address[] customers;
    
    event depositDone(uint amount, address indexed depositedTo);
    
    function deposit() public payable returns (uint)  {
        balance[msg.sender] += msg.value;
        emit depositDone(msg.value, msg.sender);
        return balance[msg.sender];
    }
    
    function withdraw(uint amount) public onlyOwner returns (uint){
        require(balance[msg.sender] >= amount);
        balance[msg.sender] -= amount;
        payable(msg.sender).transfer(amount);
        return balance[msg.sender];
    }
    
    function getBalance() public view returns (uint){
        return balance[msg.sender];
    }
    
    function transfer(address recipient, uint amount) public {
        require(balance[msg.sender] >= amount, "Balance not sufficient");
        require(msg.sender != recipient, "Don't transfer money to yourself");
        
        uint previousSenderBalance = balance[msg.sender];
        
        _transfer(msg.sender, recipient, amount);
        
        assert(balance[msg.sender] == previousSenderBalance - amount);
    }
    
    function _transfer(address from, address to, uint amount) private {
        balance[from] -= amount;
        balance[to] += amount;
    }
    
}