Events Assignment

event amountTransferred(address transferredTo, address transferredFrom, uint amount);
function transfer (address recipient, uint amount) public {
        require(balance[msg.sender]>=amount);
        require(msg.sender!=recipient);
        
        uint previousSenderBalance = balance[msg.sender];
        _transfer(msg.sender,recipient, amount);
        
        emit amountTransferred (recipient, msg.sender, amount);
        
        assert (balance[msg.sender] == previousSenderBalance - amount);
    }
1 Like

Hi @moise,

Your transfer event declaration is well coded, but can we also see how you’ve coded the corresponding emit statement, and where you’ve placed it?

Your additional modifier — to prevent funds being transferred to the same address they are sent from — looks good. Can we see how you’ve implemented that as well?

Hi @ballack13r ,

Your transfer event and corresponding emit statement are both well coded, and the emit statement will log appropriate data when the transfer() function is successfully executed.

Just one observation…
In general an emit statement is probably better placed after an assert statement.

Just let me know if you have any questions :slight_smile:

1 Like
pragma solidity 0.7.5;
contract Bank {
  
     mapping(address => uint) balance;
     address owner;
     
     event balanceAdded(uint amount, address indexed depositedTo);
     event transferComplete(address owner, address indexed recipient, uint amount);
     modifier onlyOwner {
         require(msg.sender == owner);
         _;// underscore means run the function
     }
     constructor(){
         owner = msg.sender;
         
     }
    function addBalance(uint _toAdd) public onlyOwner returns (uint){
        
        balance[msg.sender] += _toAdd;
        emit balanceAdded(_toAdd, msg.sender);
        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, "Transferring funds to yourself is prohibited.");
       
        uint previousSenderBalance = balance[msg.sender];
        
    
        _transfer(msg.sender, recipient, amount);
        
        
        assert(balance[msg.sender] == previousSenderBalance - amount);
        
        emit transferComplete(msg.sender, recipient, amount);
        // event logs and further checks
    }
    
    function _transfer(address from, address to, uint amount) private {
                balance[from] -= amount;
                balance[to] += amount;
    }
}
1 Like

Hi @Gry,

Your transfer event and corresponding emit statement are both well coded. The emit statement is in the correct position in the transfer() function body and will log appropriate data when the transfer() function is successfully executed :ok_hand:

Just one observation…

I don’t think it’s a good idea to name the first address parameter owner, because that is the name of the state variable which stores the contract owner’s address (the address that deployed the contract). Only the contract owner can deposit funds into the contract, so only the contract owner can perform the first transfer. But after that initial transfer, the number of addresses with balances can gradually increase as more transfers are made to different addresses. So, because any address with funds can call the transfer() function and successfully transfer funds to a recipient, a more appropriate name for the first address parameter in the transfer event would be something like transferFrom, transferredFrom, sender etc.

Let me know if you have any questions.

Hi sorry, i thought i copied all the code. here is all the code.

pragma solidity ^0.8.7;
contract Events{
    
    mapping(address=>uint) balance;
    address owner;
    // emit on call of the addBalance function
    event balanceAdded(uint _amount,address depositor);
    // emit on call of transfert function
    event transfertDone(uint indexed _amount,address indexed sender,address indexed recipient);
    
    constructor(){
        owner=msg.sender;
    }
    
    modifier onlyOwner(){
        require(msg.sender==owner);
        _;
    }
    
    // disable the self transfert
    modifier noReentrance(address _sender, address _recipient){
        require(_sender!=_recipient,"cannot send funds to yourself");
        _;
    }
    
    //check the balance of the caller
    modifier checkBalance(address _sender,uint _amount){
        require(balance[_sender]>_amount,"You don't have enough money");
        _;
    }        
    
   
    
    function addBalance(uint _amount) public onlyOwner{
        balance[msg.sender]+=_amount;
        //emit on addBalance function call
        emit balanceAdded(_amount,msg.sender);
    }
    
    function transfert(address _recipient,uint _amount) public {
        _transfert(msg.sender,_recipient,_amount);
        //emit the event to log transfert function call
        emit transfertDone(_amount,msg.sender,_recipient);
    }
    
    // this function use the noReentrance modifier to prevent transfer to self account
   // It use the checkBalance  Modifier to verify that the senders has enough amount in his balance
    function _transfert(address _sender,address _recipient,uint _amount) private noReentrance(_sender,_recipient) checkBalance(_sender,_amount){
        balance[_sender]-=_amount;
        balance[_recipient]+=_amount;
    }
    
    function getBalance() public view returns(uint){
        return balance[msg.sender];
    }
}
1 Like

Hi @moise,

Your transfer event and corresponding emit statement are both well coded. The emit statement is in the correct position in the transfer() function body and will log appropriate data when the transfer() function is successfully executed :ok_hand:

Your additional modifiers (checkBalance and noReentrance) and their implementation in the function header are also, on the whole, well coded and provide the necessary input restrictions. However, the following improvements can be made:

  • Your checkBalance condition will evaluate to false, and the transfer transaction will revert, if the sender tries to transfer their whole balance. But this should be allowed. Only amounts greater (and not equal to) their balance should be prevented. A simple modification to the comparison operator will fix this.

  • If input values need to be checked, this should be the first operation which is performed during the execution of a function; and require() statements should be executed as early as possible so that, if one fails, the amount of gas refunded is maximised. As well as the gas cost of executing the require statement which fails, any gas consumed before revert is triggered will also not be refunded. The transfer amount, and the sender and recipient addresses are first input when the main transfer() function is called externally, and so the two modifiers should be applied to that function header, instead of the header of the _transfer() helper function.

The term re-entrancy refers to a type of attack, which you will learn about in the courses after this one. I would, therefore, change the name of your noReentrance modifier to something else, so it’s not misinterpreted as being code implemented to prevent a re-entrancy attack.

I would also recommend leaving a space between your operators and their operands, and also after the commas separating your arguments and parameter definitions. This will make your code clearer and easier to read, especially as you like to use a lot of underscores in your identifiers e.g.

balance[_recipient] += _amount;

  instead of …

emit transfertDone(_amount, msg.sender, _recipient);

  instead of …

  and

function transfert(address _recipient,  uint _amount) public { ... }

  instead of …

Let me know if anything is unclear, or if you have any questions.

Thank you for the remarks. it is clear

1 Like

Here’s my solution:

pragma solidity 0.8.9;

contract Bank {

mapping(address => uint) balance;
address owner; 
event balanceAdded(uint amount, address indexed depositedTo);
event balanceTransferred(uint amount, address indexed depositedFrom, address indexed depositedTo);

modifier onlyOwner {
    require(msg.sender == owner);
    _;
}

constructor (){
    owner = msg.sender;
}

function addBalance (uint _toAdd) public onlyOwner returns (uint) {
    balance[msg.sender] += _toAdd;
    emit balanceAdded(_toAdd, msg.sender);
    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);
     
     emit balanceTransferred(amount, msg.sender, recipient);
     
     assert(balance[msg.sender] == previousSenderBalance - amount);
 }
 
 function _transfer(address from, address to, uint amount) private {
     balance[from] -= amount;
     balance[to] += amount;
 }

}

1 Like

Hi @skawal22,

Your transfer event and corresponding emit statement are both well coded, and the emit statement will log appropriate data when the transfer() function is successfully executed.

Just one observation…
In general an emit statement is probably better placed after an assert statement.

Just let me know if you have any questions :slight_smile:

1 Like

Thank you @jon_m. I will try to practice this going forward

1 Like
pragma solidity 0.7.5;
contract Bank {
  
     mapping(address => uint) balance;
     address owner;
     
     event balanceAdded(uint amount, address indexed depositedTo);
     event transferComplete(address owner, address indexed recipient, uint amount);
     modifier onlyOwner {
         require(msg.sender == owner);
         _;// underscore means run the function
     }
     constructor(){
         owner = msg.sender;
         
     }
    function addBalance(uint _toAdd) public onlyOwner returns (uint){
        
        balance[msg.sender] += _toAdd;
        emit balanceAdded(_toAdd, msg.sender);
        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, "Transferring funds to yourself is prohibited.");
       
        uint previousSenderBalance = balance[msg.sender];
        
    
        _transfer(msg.sender, recipient, amount);
        
        
        assert(balance[msg.sender] == previousSenderBalance - amount);
        
        emit transferComplete(msg.sender, recipient, amount);
        // event logs and further checks
    }
    
    function _transfer(address from, address to, uint amount) private {
                balance[from] -= amount;
                balance[to] += amount;
    }
}
1 Like

Hi @Joeyj007,

Your transfer event and corresponding emit statement are both well coded. The emit statement is in the correct position in the transfer() function body and will log appropriate data when the transfer() function is successfully executed :ok_hand:

Just one observation … perhaps owner isn’t the best choice of identifier for the first parameter in your transfer event, because owner already refers to the contract owner’s address stored in the owner state variable; and so this could potentially cause confusion. In contrast, the address you are referring to in this first parameter can be that of any user who calls the transfer() function (msg.sender) in order to make an internal transfer within the contract to another user (recipient).

Let me know if you have any questions.

event creation:

event fundsSent(uint amount, address indexed recipient);

using the event inside function “transfer”:

function transfer(address recipient, uint amount) public {
     require(balance[msg.sender] >= amount, "Balance not enough!");
     require(msg.sender != recipient, "Can't send money to yourself!");
     
     uint prevSenderBalance = balance[msg.sender];

     _transfer(msg.sender, recipient, amount);
     
     emit fundsSent(amount, recipient); // EMIT EVENT HERE!!

    assert(balance [msg.sender] == prevSenderBalance - amount);
} 
1 Like

Hi @zajiramu1062,

Your transfer event and corresponding emit statement are both accurately coded, and the emit statement will log the data when the transfer() function is successfully executed.

A couple of observations…

  • An emit statement should be placed at the end of a function, after the event itself has occurred, but before a return statement if there is one. Generally speaking, it’s probably also better to place an emit statement after an assert statement if there is one.

  • Where the addBalance function executes a transaction that only involves 1 user address (the depositer), the transfer() function executes a transaction that involves 2 user addresses (the sender and the recipient). So, it would be useful to include the sender’s address, as well as the recipient’s address, within the data emitted for the transfer event.

Let me know if you have any questions :slight_smile:

pragma solidity 0.7.5;

contract Bank {

    mapping(address => uint) balance;

    address owner;

    constructor() {
        owner = msg.sender;
    }

    modifier onlyOwner {
        require(msg.sender == owner);
        _;
    }

    modifier costs(uint price) {
        require(msg.value >= price);
        _;
    }

    event balanceAdded(uint _amount, address indexed _depositedTo); 

    event transferDetails(uint _amount, address indexed _from, address indexed _to);

    function addBalance(uint _toAdd) public onlyOwner {
        balance[msg.sender] += _toAdd;
        emit balanceAdded(_toAdd, msg.sender); 
    }

    function getBalance() public view returns(uint) {
        return balance[msg.sender];
    }

    function transfer(address _recipient, uint _amount) public {
        require(balance[msg.sender] >= _amount, "You do NOT have enough funds");
        require(msg.sender != _recipient, "You can NOT send money to yourself");

        uint previousSenderBalance = balance[msg.sender];

        _transfer(msg.sender, _recipient, _amount);

        // we emit the transferDetails event
        emit transferDetails(_amount, msg.sender, _recipient);

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

    function _transfer(address _from, address _to, uint _amount) private {
        balance[_from] -= _amount;
        balance[_to] += _amount;
    }

}
1 Like

Hi @DNC,

Your transfer event and corresponding emit statement are both well coded, and the emit statement will log appropriate data when the transfer() function is successfully executed :ok_hand:

A couple of observations …

  • In general, an emit statement is probably better placed after an assert statement if there is one.

  • You have included a costs modifier, but not applied it to any functions. In fact, this modifier only becomes relevant when we send an ether value to the contract. But we don’t do that until the next section, so you can remove this modifier from this contract, but include it in your contract for the next assignment.

Just let me know if you have any questions :slight_smile:

Thank you very much Jon.
It makes sense to place the emit after the assert because, this way, I would know for sure that the code works in its entirety and the event is valid.

1 Like

Hi Dan,

While this is true, if we place the emit statement before the assert statement (as you did) and assert() fails, then the transaction would revert, including the emission of the event, and so the event would still not be logged. However, as the emit statement itself doesn’t affect the evaluation of the condition in the assert statement, I think it’s just cleaner, makes more sense, and also the most secure option, to place the emit statement after assert().

// SPDX-License-Identifier: UNLICENSED

pragma solidity 0.8.10;

contract EtherBank {

    mapping(address => uint) balance;

    address owner;

    event balanceAdded(uint amount, address indexed depositedTo);

    event balanceTransferred(uint amount, address indexed depositedFrom, address indexed depositedTo);

    modifier onlyOwner {

    require(msg.sender == owner);

    _;

    }

    constructor (){

    owner = msg.sender;

    }

    function addBalance (uint _toAdd) public onlyOwner returns (uint) {

    balance[msg.sender] += _toAdd;

    emit balanceAdded(_toAdd, msg.sender);

    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);

     emit balanceTransferred(amount, msg.sender, recipient);

    }

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

     balance[from] -= amount;

     balance[to] += amount;

    }  

}
1 Like