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
  • balanceOf()
  • _msgSender()
  • _transfer()
  • A bit more on Unchecked:
  • _mint()
  • _burn()
  • _spendAllowance()
  1. ERCs & EIPs
  2. ERC-20.sol

Core functions

PreviousERC-20.solNexttransfer()

Last updated 2 years ago

balanceOf()

  • Allows you to check the token balance of an address. Returns token balance as uint.

  • Public function that anyone can call.

  • View function in that it does not modify the blockchain state - just reads from it.

_msgSender()

_msgSender() is inherited from Context.sol, which is an abstract contract, defined as follows: function _msgSender() internal view virtual returns (address) { return msg.sender; }

Initially, this seems trivial as we could directly call msg.sender. However, as the documentation explains, they should not be accessed in such a direct manner, since when dealing with meta-transactions the account sending and paying for execution may not be the actual sender (as far as an application is concerned).

For regular transactions it returns msg.sender and for meta transactions it can be used to return the end user (rather than the relayer).

_transfer()

We will need to understand this function well, before we can move to appreciating what either transfer() or transferFrom() do.

In a nutshell, _transfer() updates both the token balance states of from and to , as provided. It is called on by both transfer() and transferFrom() -- which are commonly used in other Smart Contracts.

Both _beforeTokenTransfer and _afterTokenTransfer are hooks  — empty function shells where we can use to inject our own custom functionality; without modifying _transfer() as it has been securely implemented.

It is often useful to perform some function each time tokens change hands. To that end, we should not modify _transfer as it is easy to write it insecurely. The solution therefore is to introduce hooks for custom functionality.

  • First two require statements are sanity checks.

  • The third ensures that you (address from), has the necessary balance to fulfil the transfer amount.

  • Subsequently, the token sender’s balance is updated to reflect the post-transaction figure. This is wrapped inside unchecked{}, to save gas.

  • The receiver’s token balance is incremented accordingly.

  • Finally the Transfer event is emitted.

A bit more on Unchecked:

The reason the "unchecked" keyword exists is to allow Solidity developers to write more efficient programs.

The default "checked" behaviour costs more gas when executing arithmetic operations, because under-the-hood those checks are implemented as a series of opcodes that, prior to performing the actual arithmetic, check for under/overflow and revert if it is detected.

If you are working on Solidity v0.8.0 or greater, and you are able to determine there is no possible way for your arithmetic to under/overflow (in this case, our 3rd require statement), then you can surround the arithmetic in an "unchecked" block.

_mint()

  • _beforeTokenTransfer() and _afterTokenTransfer are hooks - empty functions for customization.

  • internal modifier means that the function can only be called within the contract itself and any derived contracts.

  • In this form, anyone can call _mint, which is not ideal. A typical implementation would be as follows, where the onlyOwner modifier is inherited from Ownable.sol

_burn()

  1. First is a sanity check, we obioculy cannot burn from a 0 address.

  2. _beforeTokenTransfer is a hook, as is _afterTokenTransfer

  3. Record current token balance of address

  4. Check that balance exceeds burn

  5. Unchecked to save gas since require statement was qualified: subtract burn amt from address balance

  6. Update token’s total supply.

  7. Emit Transfer event.

Similar to _mint, _burn in this form would be callable by anyone, hence onlyOwner is useful.

_spendAllowance()

  • Stores current allowance into currentAllowance variable

  • If statement checks if currentAllowance is set to the maximum possible figure, else it ensures that currentAllowance is more than equals to the amount.

onlyOwner can mint