Understanding MEV of Rebasing Tokens using Phalcon Fork
In this tutorial, I will show you how to use Phalcon Fork to understand the MEV of rebasing tokens. The code is released on the GitHub.
https://github.com/blocksecteam/phalcon_fork_examples/tree/main/lidoMEV
The transactions of the Phalcon Fork
https://app.blocksec.com/fork/scan/fork_db6ee35a9e844ecfa7f91b9b861d54a0
Background
What is MEV
The definition of MEV has been changed in the past years. Previously, it meant the Miner Extract Value. However, MEV means Maximal Extractable Value that can be extracted by manipulating the transaction order inside a block. You can refer to the document for more information.
What is a rebasing token
The rebasing token means the supply is adjusted based on some pre-defined algorithm. One rebasing method is to adjust the balance of each token holder perilously.
Lido's staked Ether token stETH
is a rebasing ERC20 rebasing token. The token holder's balance is changed daily. The balance of stETH of a token holder is calculated using the following formula.
Lido has an excellent document describing the rebasing mechanism.
In summary, the balance of stETH token holders will be increased daily.
Uniswap V2 pool
When swapping token X to token Y inside the Uniswap v2 pool, users usually interact with the Uniswap router contract, which will find the pool contract of the tokens. However, a user can directly invoke the swap
function inside a pool.
However, how to determine the price of the tokens? Uniswap uses the constant product formula for this purpose.
means the balance of token X inside the pool after and before the swap. means the balance of token Y after and before the swap.
However, each swap will have a fee (0.003 currently). So, the formula becomes the following (suppose we use Token X to swap Token Y -- X is the token into the pool, and Y is the token out of the pool).
The means the number of token X that has been transferred inside the pool, and means the number of token Y that will be swapped out.
In the Uniswap pool smart contract, it uses two variables _reserve0
and reserve1
to denote the balance before the swap, and use the balance0
and balance1
to denote the balance after the swap (but do not consider the fee yet -- we can ignore it here).
MEV Opportunity
The formula calculates the input token X inside the pool (line 19 in the code). This works perfectly in most cases since the reserves recorded inside the pool are equal to the balances of tokens before the swap.
However, for the rebasing token like stETH
the token balance increased periodically, which means the balance of stETH
in this pool will be increased. This creates a MEV opportunity because the rebasing creates a inside the pool, which could be used to swap token Y out by anyone.
A Real Example
This opportunity has been observed and actively taken. Let me use a transaction as an example. The hash of this transaction is 0x4b94095fe2c0014156d6b400e4fc405895cb508ab2802fa27b6135f939de5725
.
Through the balance change of this transaction in Phalcon Explorer, we can find that the address 0x7024960031000000e9f80000790090f61732277b got a profit of 0.01
Ether in this transaction, and paid 0.36
Ether as the bribe fee to FlashBot.
Why this transaction can make profit?
You can directly view this debug window using the following link.
Because the balance of stETH is bigger than reserve0
in the pool, the 0x7024 address invokes the swap
function to use the increased balance (0.38 stETH) to swap WETH.
3,950,436,974,827,841,051,750 - 3,950,055,013,348,304,070,261 = 381,961,479,536,981,489
As a result, 0.379 WETH was swapped out. The address keeps 0.01 Ether and bribed 0.36 Ether to FlashBot.
Deploy/Debug an MEV contract inside Phalcon Fork
From the on-chain data, we can only observe the flow of the MEV transaction. However, we do not have the source code of the contract (0x7024).
To fully understand this process, we can develop our own MEV contract and debug it in Phalcon Fork.
Create a Fork
First, we need to create a Fork inside the dashboard of Phalcon Fork.
Develop the Contract
We use Foundry as the development framework. Add the following information to the configuration file (foundry.toml
).
Add a .env
file to store the Phalcon Fork RPC, and API_KEY used to verify the contract. If you do not know the values, you can click the Configuration
button inside the Fork. The following screenshot shows the detailed RPC, API_KEY, and verifier URL.
The source code of the smart contract is in the following.
Deploy and Trigger the Contract
We use the Foundry script to deploy and trigger the contract.
The PRIVATE_KEY
is configured inside the .env
file. We need to import it before executing the script.
source .env
forge script script/MEV.s.sol:MEVScript --rpc-url $PHALCON_FORK_RPC_URL --broadcast --verify -vvvv
This will build, deploy, verify the contract, and invoke the trigger
function to issue the MEV transaction.
From the Phalcon Scan, we can find the deployed contract and issued transactions. Also, we can use the Phalcon Explorer to understand and debug the transaction.
Summary
In this document, we show an example of developing an MEV contract and deploying it inside Phalcon Fork.
In fact, using Phalcon Fork, you can develop and write your contract with real mainnet states. You can ensure everything is correct before deploying it on the mainnet. Besides, Phalcon Fork can be integrated into the CD pipeline through the API.
Last updated