Events Assignment

Hi @Jaka,

Your transfer event and corresponding emit statement are both correct and 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:

pragma solidity 0.7.5;

contract Bank {
    
    mapping (address => uint) balance;
    address owner;

    event balanceAdded(uint amount, address indexed deposiotedTo);
    event transferDone(uint amount, address indexed sentTo, address indexed sentFrom);

    ...

    function transer(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 transferDone(amount, recipient, msg.sender);
    }

...

}

1 Like

Hi @VBence99,

Your transfer event and corresponding emit statement are both correct and 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:

1 Like

Hi, this is my solution:

// SPDX-License-Identifier: MIT

pragma solidity 0.7.5;

contract Bank {
    mapping(address => uint) balance;
    address owner;

    event balanceAdded(address indexed depositedTo, uint balance);
    event fundTransfered(address indexed, address indexed to, uint balance);

    constructor() {
        owner = msg.sender;
    }

    modifier onlyOwner() {
        require(msg.sender == owner, "Only owner can execute this function");
        _;
    }

    function addBalance(address _recipient, uint _amount) public onlyOwner {
        balance[_recipient] += _amount;
        emit balanceAdded(_recipient, _amount);
    }

    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(_amount > 0, "fund should be greater than 0");
        require(msg.sender != _recipient, "Don't transfer fund to yourself");

        _transfer(msg.sender, _recipient, _amount);
        emit fundTransfered(msg.sender, _recipient, _amount);
    }

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

Hi @codingluan,

Your transfer event and corresponding emit statement are mostly well coded (see comments below). The emit statement is in the correct position in the transfer() function body and logs appropriate data when the transfer() function is successfully executed :ok_hand:


Improvements that can be made to your transfer event declaration:

(1)ā€‚Youā€™ve named the parameter for the recipient address (to), but you havenā€™t named the parameter for the sender address. All three event data values are still emitted and logged, but if you look at the logs in the transaction receipt you will notice that only two are named. Naming the event data isnā€™t mandatory, but it will make it clearer and easier to identify, especially where you have more than one parameter with the same data type.

Marking event parameters as indexed allows their names to be used as search parameters to filter logged event data and search for specific events in the frontend/UI using a library such as web3.js. So, there is no point marking a parameter as indexed if you donā€™t also give it a name.

Hereā€™s a link to a helpful discussion about indexing, which I think explains quite well how this works in practice:

https://ethereum.stackexchange.com/questions/8658/what-does-the-indexed-keyword-do/8659

(2)ā€‚In both of your event declarations your balance parameter corresponds to the amount transferred or added, and not the resulting balance of the recipient (unless their previous balance was zero). So, to avoid any potential confusion, a more appropriate/accurate name for this parameter would be amount.


Some additional feedback ā€¦

  • Your adaptation of the addBalance() function to also allow an address to deposit amounts to other address balances in the contract, and not just to their own, is a good one. The only drawback is that if the function caller wants to deposit an amount to their own address balance in the contract, then they have to input their own address as the _recipient parameter, instead of this just being referenced by msg.sender.
  • You are right that the addBalance() function doesnā€™t need to return a value.
  • Your require() statement in the transfer() function, which prevents the sender transferring a zero amount, is a nice addition.

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 indexed amount, address indexed depositedTo);

event balanceTransfer(address sender, address recipient, uint indexed amount);

modifier onlyOwner {

require(msg.sender == owner);

_; //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, "Dont transfer money to yourself");

uint previousSenderBalance = balance[msg.sender];

transfer(msg.sender, recipient, amount);



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

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

}  

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

balance[from] -= amount;

balance[to] += amount;

}

}

1 Like

Hi @c1cag1b3,

Your transfer event and corresponding emit statement are both correct and 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 ā€¦

You have given the transfer() helper function exactly the same name as the main transfer() function. This doesnā€™t throw an error, and your contract still compiles and works as it should, because Solidity allows function polymorphism (otherwise known as function overloading). This is where two functions can have the same name as long as they have a different number of parameters, or their parameters are of different data types. This the case with your two transfer() functions due to the fact that one has an additional address parameter.

However, for clarity, I would suggest prefixing the name of the private helper function with an underscore: ā€‚_transfer
This will give the functions different names, whilst keeping it clear that they are associated.

Also, please format all of your code before posting it, not just bits of it, and donā€™t forget to include appropriate indentation. This will improve presentation and make your code easier to read. Follow the instructions in this FAQ: How to post code in the forum

Let me know if you have any questions :slight_smile:

Here is my solution: specifically, I created an emit balanceTransfered(amount, msg.sender); line in the transfer function to track the amount and from whom the balance is transferred from. I couldnā€™t seem to get both the person sending it and the person receiving it as an eventā€¦is it possible to have been able to pass in 3 params and log those?

pragma solidity 0.7.5;

contract HelloWorld {

    mapping(address => uint) balance;
    address owner;

    // define event
        // indexed = by eth nodes, can use params to search/query for events in the past
    event balanceAdded(uint amount, address indexed depositedTo);

    event balanceTransfered(uint amount, address indexed depositedTo);

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

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

    constructor() {
        owner = msg.sender;
    }

    function addBalance(uint _toAdd) public onlyOwner returns (uint) {
        balance[msg.sender] += _toAdd;
        // add event 
        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);

       // add event 
       emit balanceTransfered(amount, msg.sender);

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

    function _transfer(address from, address to, uint amount) private {
        balance[from] -= amount;
        balance[to] += amount;
    }
}

Itā€™s a mistake. I didnā€™t do it on purpose. I should be more careful, I am programming money now!

Yes, I name them wrong, amount is an appropriate name to both of the parameters.

Thatā€™s right!
I will rewrite the function. Itā€™s inconvenient to put your own address here.

Thank you for all of your feedback, Jonathan!

// SPDX-License-Identifier: MIT

pragma solidity 0.7.5;

contract Bank {
    mapping(address => uint) balance;
    address owner;

    event newMoneyMinted(uint amount);
    event fundTransfered(address indexed from, address indexed to, uint amount);

    constructor() {
        owner = msg.sender;
    }

    modifier onlyOwner() {
        require(msg.sender == owner, "Only owner can execute this function");
        _;
    }

    function mint(uint _amount) public onlyOwner {
        balance[msg.sender] += _amount;
        emit newMoneyMinted(_amount);
    }

    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(_amount > 0, "fund should be greater than 0");
        require(msg.sender != _recipient, "Don't transfer fund to yourself");
        
        _transfer(msg.sender, _recipient, _amount);
        emit fundTransfered(msg.sender, _recipient, _amount);
    }

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

Hey Luan,

Nice corrections/modifications! :ok_hand:

I think referring to the concept of minting in the names of the addBalance() function and its associated event is very appropriate, because only the contract owner can perform this operation. I also think it makes sense to remove the address parameter from the newMoneyMinted event, because your contract owner can no longer mint funds and allocate them directly to another user all within the same mint() function, which makes the address parameter irrelevant as this will always be the contract ownerā€™s. The subsequent allocation of the minted funds to other users is performed by the transfer() function, and as users can then continue to use this function to transfer their own funds amongst themselves, it is necessary for the transfer event to have two address parameters (the sender and the recipient).

Keep up the great coding! :muscle:

1 Like

Hi @InterstellarX,

As you say, this emit statement will log the amount transferred and the address of the user the amount is transferred from. This data will be logged when your transfer() function is successfully executed. But the name youā€™ve given to your second parameter in the corresponding event declaration, and the name that will therefore appear next to the amount transferred in the logged data (see the logs in the transaction receipt thatā€™s generated in the Remix terminal when you successfully execute this function), doesnā€™t reflect thisā€¦

This should beā€‚depositedFrom , or even betterā€‚transferredFromā€‚or justā€‚from

Yes, you just need to add the extra address parameter to the event declaration e.g.

event balanceTransferred(uint amount, address indexed from, address to);

ā€¦and then add a reference to the recipientā€™s address to the emit statement, making sure its position corresponds to that of the corresponding parameter in the event declaration (i.e. 3rd in this example) ā€¦

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

A couple of additional 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 anything is unclear, or if you have any further questions about these points :slight_smile:

1 Like

Hi @jon_m,

Thank you very much for review and tips, well noted!

1 Like

Answer at event transfer function.

pragma solidity 0.7.5;
import "./Ownable.sol";

contract Bank is Ownable { 

    event balanceAdded (uint amount, address indexed depositTo);
    event transferSuccess (address indexed sender, address indexed reciever, uint amount);
    event withdrawSuccess (address indexed withdrawFrom, uint money);
    
     mapping(address => uint) balance;
     function addBalance(uint _toAdd) public onlyOwner returns(uint){
        //this function will run "onlyOwner" func. before "addBalance" func.
        balance[msg.sender] = balance[msg.sender] + _toAdd;
        //put into log event by use emit
        emit balanceAdded(_toAdd, msg.sender);
        return balance[msg.sender];
    }  
    function transfer(address recipient, uint amount) public {
        require(balance[msg.sender]>= amount, "Your balance is insufficient");
        require(msg.sender != recipient, "Do not transfer money back to your address");

        uint previousSenderBalance = balance[msg.sender];

        //operate with the private function +- amount
        _transfer(msg.sender, recipient, amount);
        emit transferSuccess(msg.sender, recipient, amount); //Answer
       
        //assert() use for check internal error (what's code should do) and condition should always true
        assert(balance[msg.sender] == previousSenderBalance - amount);
    }

    //private function = variable or function can executed only inside contract itself
    function _transfer(address from, address to, uint amount) private {
        balance[from] -= amount;
        balance[to] += amount;
    }


}
1 Like

Hi @thanasornsawan,

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
    event transferComplete(address indexed from, address indexed to, uint amount);
    function transfer( address recipient, uint amount) public  {
        // check balance of msg.sender and validate amount exists
        require(balance[msg.sender] >= amount, "Balance not sufficient");
        require(msg.sender != recipient, "Don't transfer money to yourself");// don't send money to ourselves

        uint previousSenderBalance = balance[msg.sender];

        _transfer(msg.sender, recipient, amount);

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

        // event logs and further checks
        emit transferComplete(msg.sender, recipient, amount);
    }

    function _transfer(address from, address to, uint amount) private {
        balance[from] -= amount;
        balance[to] += amount;  
    }
1 Like

Some events around here and there:

pragma solidity 0.7.5;

contract Bank {

    //state variable
    mapping(address => uint) myBalance;
    address owner;
    
    event balanceAdded(uint amount, address indexed sender);
    event balanceTransfered(uint amount, address indexed sender, address indexed recipient);

    modifier onlyOwner {
        require(msg.sender == owner, "You're not the owner!");
        _; //runs the function next
    }

    constructor(){
        owner = msg.sender;
    }

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

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

    function transfer(address _recipient, uint _amount) public {
        require(myBalance[msg.sender] > _amount, "Balance insuficient!");
        require(msg.sender != _recipient, "Don't transfer balance to yourself!");

        uint prevSenderBalance = myBalance[msg.sender];

        _transfer(msg.sender, _recipient, _amount);

        assert(myBalance[msg.sender] == prevSenderBalance - _amount);
    }

    function _transfer(address _sender, address _recipient, uint _amount) private {
        myBalance[_sender] -= _amount;
        myBalance[_recipient] += _amount;
        emit balanceTransfered(_amount, _sender, _recipient);
    }
}```
1 Like

Nice solution @JayM700 :ok_hand:

Your transfer event and corresponding emit statement are both correct and 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.

Just one observation ā€¦

Your assert() statement is one the final/further checks. Itā€™s correct to place it before the emit statement, but have the comment refer to both of them ā€¦

  _transfer(msg.sender, recipient, amount);
  
  // event logs and further checks
  assert(balance[msg.sender] == previousSenderBalance - amount);
  emit transferComplete(msg.sender, recipient, amount);

Let me know if you have any questions.

Hi @JP-C,

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

Just a couple of comments ā€¦

  • Itā€™s better to emit the event at the very end of the function which completes the transaction i.e. transfer() not _transfer().
    _transfer() is what we call a helper function.
    Another important factor here is that if you emit an event in a helper function, you are restricting your ability to reuse that helper function. It will be more reuseable if we can call it from another function when we may not want to emit the same event ā€” either a different one, or no event at all. That way we can reuse the helper function whenever we just want its functionality (i.e. the operations, or computation, that it performs).

  • In general an emit statement is probably better placed after an assert statement.

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

pragma solidity 0.7.5;

contract helloworld{

    //storage - means permanent storage of data (persistant data)
    //memory - temporare data storage (is stored temporarely as long as the function executes)
    //calldata - similar to memory, but READ-ONLY
    
    mapping (address => uint)balance;
    
    address owner;

    event balanceAdded(uint amount, address depositedTo);
    event balanceTransfered(uint amount, address fromAddress, address toAddress);

    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);
    require(msg.sender != recipient);
    uint previousSenderBalance = balance[msg.sender];
    _transfer(msg.sender, recipient, amount);
    assert(balance[msg.sender] == previousSenderBalance - amount);
    emit balanceTransfered(amount, recipient, msg.sender);
    
    }
    function _transfer(address from, address to, uint amount) private{
        balance[from] -= amount;
        balance[to] += amount;

    }
}

Added the event and Emit transferDone in the transfer function

pragma solidity 0.8.11;

import "./Destroyable.sol";

contract Bank is Destroyable {

    mapping(address => uint) balance;

    event depositDone(uint amount, address depositedTo);
    event transferDone(uint amount, address transferedFrom, address transferedTo);

    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 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, "Dont transfer money to yourself");
   
        uint previousSenderBalance = balance[msg.sender];
        
        _transfer(msg.sender, recipient, amount);
        
        assert(balance[msg.sender] == previousSenderBalance - amount);
        emit transferDone(amount, msg.sender, recipient);
    }

    function _transfer(address from, address to, uint amount) private {
        balance[from] -= amount;
        balance[to] += amount;
    }

    function getContractBalance() public view returns(uint) {
    return address(this).balance;
    }
}
1 Like