Smart Contract Development
  • Introduction
    • What is a Transaction
    • Accounts and Signing
    • What is a smart contract
  • Learning Solidity
    • Introduction
    • Module 1
      • Variable Types
      • Variable Scope: State & Local variables
      • Global variables
      • Functions
        • View and Pure
        • Shadowing in Fuctions
      • Mapping
      • Require
      • Events
    • Project #1: Simple Registry
    • Module 2
      • Constructor
      • Data Location: Value & Reference
      • Interface
      • Import
        • Importing in Foundry
      • Inheritance
      • ERC-20
      • Checks-effect-interaction pattern
    • Project #2: Basic Vault
    • Module 3
      • Payable
      • Receive
      • Fallback
      • Returns
    • Project #3: ERC20+ETH Wrapper
    • Module 4
      • Immutable and Constant
      • Fixed-point Math
      • Abstract contracts
      • ERC-4626
      • Modifier + Inheritance +Ownable
      • Type
    • Project #4: Fractional Wrapper
    • Module 5
      • If-else
      • Libraries
        • TransferHelper
      • Chainlink Oracle
    • Project #5: Collateralized Vault
  • Compendium
    • Solidity Basics
      • Variable Types
      • Value Types
        • address
        • enum
      • Reference Types
        • strings
        • mappings
        • struct
        • Arrays
        • Multi-Dimensional arrays
      • Global Objects
      • Functions
        • Function types
        • Constructor Function
        • Transaction vs Call
        • Require, Revert, Assert
      • Function signature + selectors
      • Payable
        • Payable + withdraw
        • msg.value & payable functions
      • Receive
      • Fallback function (sol v 0.8)
        • Fallback function (sol v 0.6)
      • call, staticcall, delegatecall
    • Return & Events
    • Control Variable Visibility
    • Local Variables (Storage v Memory)
    • Data Location and Assignment Behaviors
    • Modifiers & Inheritance & Import
      • import styles
    • Interface & Abstract Contracts
    • ABI & Debugging
    • Libraries
    • Conditional(ternary) operators
    • Smart Contract Life-cycle
      • Pausing Smart Contracts
      • Destroying Smart Contracts
    • Merkle Trie and MPT
    • Merkle Tree Airdrop
  • Try & catch
  • Ethereum Signatures
  • EVM, Storage, Opcodes
    • EVM
    • Wei, Ether, Gas
    • Storage
    • ByteCode and Opcodes
    • Transaction costs & Execution costs
  • Reading txn input data
  • Data Representation
  • Yul
    • Yul
      • Intro
      • Basic operations
      • Storage Slots
      • Storage of Arrays and Mappings
      • Memory Operations
      • Memory: how solidity uses memory
      • Memory: Return, Require, Tuples and Keccak256
      • Memory: Logs and Events
      • Inter-contract calls
      • calldata
      • free memory pointer
    • Yul Exercises
      • read state variable
      • read mapping
      • iterate Array, Return Sum
    • memory-safe
  • Upgradable Contracts
    • Upgradability & Proxies
    • UUPS Example
    • Minimal Proxy Example
    • TPP Example
    • 🚧Diamond
      • On Storage
  • Gas Opt
    • Block Limit
    • gasLimit & min cost
    • Solidity Optimiser
    • Memory v calldata
    • Memory caching vs direct storage vs pointers
    • < vs <=
    • reverting early
    • X && Y, ||
    • constant and immutable
    • caching sload into mload
    • Syntactic Sugar
    • using unchecked w/o require
    • Compact Strings
    • Calling a view function
    • Custom errors over require
    • usage of this.
      • multiple address(this)
  • ERCs & EIPs
    • ERC-20.sol
      • Core functions
      • transfer()
      • transferFrom()
      • TLDR transfer vs transferFrom
    • Landing
      • ERC721.sol
      • EIP-721
        • LooksRare
        • Page 1
      • ERC-1271
      • EIP-2981
      • ERC-165
      • EIP-1167: Minimal Proxy Contract
    • VRFConsumerBase
    • UniswapV2Library
  • Yield Mentorship 2022
    • Projects
      • #1 Simple Registry
      • #2 Basic Vault
      • #3 ERC20+ETH Wrapper
        • setFailTransferTrue
      • #4 Fractional Wrapper
      • #5 Collateralized Vault
        • Process
        • Vault.sol
        • Testing
        • Chainlink Oracles
        • Pricing + Decimal scaling
        • Refactor for Simplicity
      • #9 Flash Loan Vault
        • Implementing ERC3156
        • Full code for lender
        • Ex-rate calculation
    • State Inheritance Testing
    • Testing w/ Mocks
    • Yield Style Guide
    • Github Actions
    • TransferHelper.sol
    • math logic + internal fn
    • Interfaces: IERC20
  • Foundry
    • Overview
    • Importing Contracts
    • Testing
      • stdError.arithmeticError
      • assume vs bound
      • Traces
      • label & console2
      • std-storage
  • Smart Contract Security
    • Damn Vulnerable Defi
      • 1. Unstoppable
      • 2. Naive receiver
      • 3. Truster
      • 4. Side Entrance
      • 5. The Rewarder
      • 6. Selfie
      • 7. Compromised
      • 8. Puppet
      • 9. Puppet V2
      • 10 - Free Rider
    • Merkle Tree: shortened proof attack
  • Fixed-Point Math
    • AMM Math
  • Solidity Patterns
    • checks-effects-interactions pattern
    • Router // batch
    • claimDelegate: stack unique owners
    • claimDelegate: cache previous user
  • Array: dup/ascending check
  • Deployment
    • Behind the Scenes
    • Interacting with External Contracts
    • Logging, Events, Solidity, Bloom Filter
  • Misc
    • Mnemonic Phrases
    • Bidul Ideas
  • Archive
    • Brownie Framework
      • Brownie basics
        • storing wallets in .env
        • Deployment to ganache
        • Interacting with contract
        • Unit Testing
        • Testnet deployment
        • Interacting w/ deployed contract
        • Brownie console
      • Brownie Advanced
        • Dependencies: import contracts
        • helpful_scripts.py
        • verify and publish
        • Forking and Mocking
        • Mocking
        • Forking
      • Testing
      • Scripts Framework
        • deploy.py
        • get_accounts
        • deploy_mocks()
        • fund_with_<token>()
      • Brownie Networks
    • Brownie Projects
      • SharedWallet
        • Multiple Beneficiaries
        • Common Code Contract
        • Adding Events
        • Renounce Ownership
        • Separate Files
      • Supply Chain
        • ItemManager()
        • Adding Events
        • Adding unique address to each item
      • Lottery
      • Aave - Lending and Borrowing
        • Approve & Deposit
        • Borrow
      • NFT
      • Advanced Collectible
        • adv_deploy() + Testing
        • Create Metadata
        • Setting the TokenURI
    • node npm
    • Ganache
    • Truffle
    • Remix
    • Installing Env
Powered by GitBook
On this page
  • Returns
  • Functions without pure, view, constant modifiers
  • Functions that are pure, view, constant
  • Example
  • Events
  • Use cases
  • Events as Return Values
  • Events as Trigger
  • Events as Data storage
  1. Compendium

Return & Events

Returns

  • Functions can have an optional return statement; not restricted to pure & view only.

  • If function is not (pure,view,constant) -> returned-value are restricted to on-chain usage.

  • If function is (pure,view,constant) -> returned-values can be off-chain.

Functions without pure, view, constant modifiers

Returned values can only be fetched by on-chain calls (contract functions), but not by off-chain calls (Externally Owned Address/wallets).

When you call such function from off-chain you are returned the transaction hash.

  • This is because it is unknown when the transaction will be mined and added to the blockchain.

  • Only when it is successfully mined and computed, do we reach the actual value of the returns statement in the function.

  • This value from the returns statement can be used only inside the blockchain (contract functions).

  • If you want this value to be accessible off-chain, you need to generate an event (inside the Solidity function) to emit it to listeners.

no way for a transaction from an EOA to return a value that can be read, even by examining the blockchain.

Functions that are pure, view, constant

  • These functions do not alter states or interact with the blockchain. As such, there is no transaction hash involved, as nothing is submitted for mining.

  • These "read-only" functions can return values for off-chain usage.

Example

If you want to return true, as below, the user interacting with it will not receive it as output. To achieve this, use events.

//SPDX-License-Identifier: MIT
pragma solidity 0.8.3;

contract EventExampel {
mapping(address => uint) public tokenBalance;

constructor(){
    tokenBalance[msg.sender] = 100;
    }

function sendToken(address _to, uint _amount) public returns(bool){
    require(tokenBalance[msg.sender] >= _amount, "Not enough tokens");
    tokenBalance[msg.sender] -= _amount;
    tokenBalance[_to] += _amount;

    return true;
    }
}
//SPDX-License-Identifier: MIT
pragma solidity 0.8.3;
contract EventExampel {

mapping(address => uint) public tokenBalance;
event TokenSent(address _from, address _to, uint _amount);

constructor(){
    tokenBalance[msg.sender] = 100;
}

function sendToken(address _to, uint _amount) public returns(bool){
    require(tokenBalance[msg.sender] >= _amount, "Not enough tokens");
    tokenBalance[msg.sender] -= _amount;
    tokenBalance[_to] += _amount;

    emit TokenSent(msg.sender, _to, _amount);
    return true;
    }
}
  • Create event TokenSent, taking in parameters that we want to emit to the outside world.

  • Then we emit the event before we are returning from the function.

Events

Events allow us to “print” information on the blockchain in a way that is more searchable and gas efficient than just saving to public storage variables in our smart contracts.

Events are not stored in a contract like regular storage, but rather in a special logs section of a transaction.

Logs are gas efficient way in Ethereum to check for specific data that's not required for the contract itself. Cannot be accessed by smart contracts

Applications (outside of blockchain) can subscribe and listen to these events through the RPC interface of an event client.

// Format:
// can take up to 3 indexed parameters
event MyEvent(uint _arg1, address indexed _arg2)
  • Event arguments marked as indexed can be searched for

    • Up to 3 parameters can be indexed.

    • if you declare an argument to be indexed -> it will be hashed, and can search for them on the side-chain.

  • Logs and their events data cannot be retrievable from within contracts.

  • Events are inheritable members of a contract.

  • Events are cheap.

Example

    // emit event when name is registered or relinquished
    event NameRegistered(address indexed owner, string indexed name);
    event NameRelinquished(address indexed owner, string indexed name);

    // register an available name
    function registerName(string memory _name) public {
        require(nameOwner[_name] == address(0), "The provided name has already been registered!");
        nameOwner[_name] = msg.sender;
        emit NameRegistered(msg.sender, _name);
    }
  • topic[0] always refers to the hash of the hash of the event itself keccak-256(NameRegistered(<address>, <name>))

Indexing strings: Fundamentally, it can be done.

Indexed event arguments are stored in topics, and must be of fixed size; Solidity hashes the string and stored it in the topic. Filtering by the hash value of string would work.

However, hash functions are one-way. We cannot decode the hashes of a specific address to get its list of names. Hence, I decided to not index string in my revised code.

Further reading:

Use cases

Since returns in transactions cannot return values.

  • Used for return values from transactions

  • Used externally to trigger functionality in other SC

  • Used as a cheap data storage

Events as Return Values

  • Writing Functions cannot return data externally

  • Instead they return a transaction hash

  • Transactions can take long or may fail

Events are used to inform the external user that something has happened, since writing functions cannot return data externally.

Events as Trigger

When Alice withdraws 3 ETH from the 2/2 Multi-Sig wallet, an event will be emitted to inform Bob of this.

Bob would be using an external application listening for these events to alert him to approve the request accordingly.

Events as Data storage

Problem: Storing data on Ethereum is extremely expensive.

Solutions:

  • Store data off-chain, and store only the proof(hash) on the chain.

  • Store data on another blockchain like IPFS

  • Store data in Event logs if not necessary.

    • If data is not needed directly by the smart contract put it in a log

Further reading:

Previouscall, staticcall, delegatecallNextControl Variable Visibility

Last updated 2 years ago

Reference:

https://ethereum.stackexchange.com/questions/6840/indexed-event-with-string-not-getting-logged
https://blog.chain.link/events-and-logging-in-solidity/#:~:text=One%20such%20important%20piece%20of,data%20structure%20on%20the%20blockchain.
https://soliditydeveloper.com/solidity-fast-track-2
https://blog.chain.link/events-and-logging-in-solidity/#:~:text=One%20such%20important%20piece%20of,data%20structure%20on%20the%20blockchain.
https://soliditydeveloper.com/solidity-fast-track-2/
https://kovan.etherscan.io/address/0x136607f1f09312d041b2e60396105f58bd063d66#events