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
  • Msg.sender
  • Use of msg.sender in Router
  1. Solidity Patterns

Router // batch

Msg.sender

Pool

contract Pool {

    uint256 public num;
    address public msgSender;

    function setVars(uint256 _num, address onBehalfOf) public {
        num = _num;
        msgSender = onBehalfOf;
    }
}
  • msgSender here will be empty 0x0, on deployment

Router

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

contract Router {

    Pool public pool;

    /// @dev Helper function to extract a useful revert message from a failed call.
    /// If the returned data is malformed or not correctly abi encoded then this call can fail itself.
    function getRevertMsg(bytes memory returnData) internal pure returns (string memory)
    {
        // If the _res length is less than 68, then the transaction failed silently (without a revert message)
        if (returnData.length < 68) return "Transaction reverted silently";

        assembly {
            // Slice the sighash.
            returnData := add(returnData, 0x04)
        }

        return abi.decode(returnData, (string)); // All that remains is the revert string
    }

    /// @dev Allows batched call to self (this contract).
    /// @param calls An array of inputs for each call.
    function batch(bytes[] memory calls) public payable returns(bytes[] memory results) {

        results = new bytes[](calls.length);

        for (uint256 i; i < calls.length; i++) {

            (bool success, bytes memory result) = address(this).delegatecall(calls[i]);
            if (!success) revert(getRevertMsg(result));
            results[i] = result;
        }
    }


    function test(uint _num, address onBehalfOf) public {

        bytes memory payload = abi.encodeWithSignature("setVars(uint256,address)", _num, onBehalfOf);
        
        bytes[] memory allCalls = new bytes[](1);
        allCalls[0] = payload;

        batch(allCalls);
    }


    function setVars(uint _num, address onBehalfOf) external payable {
        pool.setVars(_num, onBehalfOf);
    }

    function setPool(address pool_) public {
        pool = Pool(pool_);
    }
}
  • First we connect the Router to the Pool contract by calling setPool on the Router.

  • Then we call test, passing in values for num and some address of choice.

  • Notice that msgSender in Pool was updated with our input value.

Hence, the batch fn in Router, does pass on the correct input values through delegateCall.

Use of msg.sender in Router

What if we pass msg.sender in batch, instead of defining it as an input address?

In this example, we modify test() to use msg.sender

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

contract Router {

    Pool public pool;


    /// @dev Helper function to extract a useful revert message from a failed call.
    /// If the returned data is malformed or not correctly abi encoded then this call can fail itself.
    function getRevertMsg(bytes memory returnData) internal pure returns (string memory)
    {
        // If the _res length is less than 68, then the transaction failed silently (without a revert message)
        if (returnData.length < 68) return "Transaction reverted silently";

        assembly {
            // Slice the sighash.
            returnData := add(returnData, 0x04)
        }

        return abi.decode(returnData, (string)); // All that remains is the revert string
    }

    /// @dev Allows batched call to self (this contract).
    /// @param calls An array of inputs for each call.
    function batch(bytes[] memory calls) public payable returns(bytes[] memory results) {

        results = new bytes[](calls.length);

        for (uint256 i; i < calls.length; i++) {

            (bool success, bytes memory result) = address(this).delegatecall(calls[i]);

            if (!success) revert(getRevertMsg(result));

            results[i] = result;
        }

    }


    function test(uint _num) public {

        bytes memory payload = abi.encodeWithSignature("setVars(uint256,address)", _num, msg.sender);
        
        bytes[] memory allCalls = new bytes[](1);
        allCalls[0] = payload;

        batch(allCalls);
    }


    function setVars(uint _num, address onBehalfOf) external payable {
        pool.setVars(_num, onBehalfOf);
    }

    function setPool(address pool_) public {
        pool = Pool(pool_);
    }
}
contract Pool {

    uint256 public num;
    address public msgSender;

    function setVars(uint256 _num, address onBehalfOf) public {
        num = _num;
        msgSender = onBehalfOf;
    }
}
  • msgSender in Pool reflects the wallet address that initiated the function.

  • meaning to say, batch() in Router does forward the correct msg.sender value to Pool.

Previouschecks-effects-interactions patternNextclaimDelegate: stack unique owners

Last updated 1 year ago