5/5
_Follow along the course with this video._ --- ### EVM Encoding What we've learnt so far is that any `EVM compatible` chain is looking for the `bytecode` of a transaction in order to understand how it's supposed to respond. We've learnt as well that the global functionality of `abi.encode`, `abi.encodePacked` and `abi.decode` can be used to convert almost any data into this `bytecode` format. What these two things combined mean is that we can encode our own function calls as data that we send to a contracts address.  If we view a function call on Etherscan, we can see the input data in a human readable form as well as its original form, which is the `bytecode` representing that function (`function selector`).  The ability to do this empowers us as developers to do a lot of cool low-level things like making arbitrary function calls. I've said previously that in order to send a transaction you're always going to need two things: 1. ABI 2. Contract Address Originally we were referring to the human-readable ABI. Human-readable ABI ```json [ { "inputs": [], "name": "multiEncode", "outputs": [ { "internalType": "bytes", "name": "", "type": "bytes" } ], "stateMutability": "pure", "type": "function" }, { "inputs": [], "name": "multiEncodePacked", "outputs": [ { "internalType": "bytes", "name": "", "type": "bytes" } ], "stateMutability": "pure", "type": "function" }, { "inputs": [], "name": "multiStringCastPacked", "outputs": [ { "internalType": "string", "name": "", "type": "string" } ], "stateMutability": "pure", "type": "function" } ] ``` We can also accomplish our goals with the `bytecode` version directly. All you _really_ need to send a function call is the name of a function and the input types. Two questions arise: **_How do we send transactions that call functions with just the data field populated?_** **_How do we populate the data field?_** We're going to answer these by leveraging additional low-level keywords offered by Solidity, `staticcall` and `call`. We've used call previously... if this code rings a bell: ```solidity function withdraw(address recentWinner) public { (bool success, ) = recentWinner.call{value: address(this).balance}(""); require(success, "Transfer Failed"); } ``` **call:** How we call functions to change the state of the blockchain **staticcall:** How we call view or pure functions > ❗ **PROTIP** > `send` and `delegatecall` also exist as options for low-level calling to the blockchain, but we'll go over these in greater detail later! When we write `recentWinner.call{value: address(this).balance}("");` we're directly updating the value property of the transaction we're sending. The parenthesis at the end of this call are where we provide our transaction data. - within `{}` we're able to pass specific fields of a transaction, like `value` - within `()` we can pass the data needed to call a specific function. ### Wrap Up Whew, this is heavy, but it's advanced. The power provided by low-level function calls cannot be overstated. Now that we have some understanding of how encoding can be using in sending transactions, let's take a step back in the next lesson to recap what we've gone over
Follow along the course with this video.
What we've learnt so far is that any EVM compatible
chain is looking for the bytecode
of a transaction in order to understand how it's supposed to respond. We've learnt as well that the global functionality of abi.encode
, abi.encodePacked
and abi.decode
can be used to convert almost any data into this bytecode
format.
What these two things combined mean is that we can encode our own function calls as data that we send to a contracts address.
If we view a function call on Etherscan, we can see the input data in a human readable form as well as its original form, which is the bytecode
representing that function (function selector
).
The ability to do this empowers us as developers to do a lot of cool low-level things like making arbitrary function calls.
I've said previously that in order to send a transaction you're always going to need two things:
ABI
Contract Address
Originally we were referring to the human-readable ABI.
Human-readable ABI
We can also accomplish our goals with the bytecode
version directly. All you really need to send a function call is the name of a function and the input types.
Two questions arise:
How do we send transactions that call functions with just the data field populated?
How do we populate the data field?
We're going to answer these by leveraging additional low-level keywords offered by Solidity, staticcall
and call
.
We've used call previously... if this code rings a bell:
call: How we call functions to change the state of the blockchain
staticcall: How we call view or pure functions
❗ PROTIP
send
anddelegatecall
also exist as options for low-level calling to the blockchain, but we'll go over these in greater detail later!
When we write recentWinner.call{value: address(this).balance}("");
we're directly updating the value property of the transaction we're sending. The parenthesis at the end of this call are where we provide our transaction data.
within {}
we're able to pass specific fields of a transaction, like value
within ()
we can pass the data needed to call a specific function.
Whew, this is heavy, but it's advanced. The power provided by low-level function calls cannot be overstated.
Now that we have some understanding of how encoding can be using in sending transactions, let's take a step back in the next lesson to recap what we've gone over
A practical refresher on Recap: Solidity Encoding, EVM Basics, and Low-Level Calls - Contrast `abi.encode` with `abi.encodePacked`, grasp EVM compilation outputs (bytecode/ABI), and see how transaction data enables contract interaction, preparing for low-level `.call()` usage.
Previous lesson
Previous
Next lesson
Next
Give us feedback
Course Overview
About the course
Advanced smart contract development
How to develop a stablecoin
How to develop a DeFi protocol
How to develop a DAO
Advanced smart contracts testing
Fuzz testing
Manual verification
Web3 Developer Relations
$85,000 - $125,000 (avg. salary)
Web3 developer
$60,000 - $150,000 (avg. salary)
Smart Contract Engineer
$100,000 - $150,000 (avg. salary)
Smart Contract Auditor
$100,000 - $200,000 (avg. salary)
Security researcher
$49,999 - $120,000 (avg. salary)
Web3 engineer, educator, and Cyfrin co-founder. Patrick's smart contract development and security courses have helped hundreds of thousands of engineers kickstarting their careers into web3.
Guest lecturers:
Last updated on July 10, 2025
Duration: 36min
Duration: 3h 06min
Duration: 5h 02min
Duration: 6h 02min
Duration: 2h 47min
Duration: 1h 23min
Duration: 4h 28min
Duration: 1h 19min
Duration: 1h 10min
Course Overview
About the course
Advanced smart contract development
How to develop a stablecoin
How to develop a DeFi protocol
How to develop a DAO
Advanced smart contracts testing
Fuzz testing
Manual verification
Web3 Developer Relations
$85,000 - $125,000 (avg. salary)
Web3 developer
$60,000 - $150,000 (avg. salary)
Smart Contract Engineer
$100,000 - $150,000 (avg. salary)
Smart Contract Auditor
$100,000 - $200,000 (avg. salary)
Security researcher
$49,999 - $120,000 (avg. salary)
Web3 engineer, educator, and Cyfrin co-founder. Patrick's smart contract development and security courses have helped hundreds of thousands of engineers kickstarting their careers into web3.
Guest lecturers:
Last updated on July 10, 2025