When we talk about DeFi, we are essentially talking about a financial system that is independent of centralized (third- party) entities. This means that we are relying on reliable deterministic smart contracts that would eventually execute as the stated conditions in the contract are met.
Hence, to unify the efforts of the developers and to bring standardization, the Ethereum community comes up with EIPs (Ethereum Improvement Proposals). One such proposal was for Tokenized Vaults which became effective as ERC- 4626.
Tokenized Vaults lacked standardization leading to diverse implementation details. This makes the integration difficult at the aggregator or plugin layer for protocols which need to conform to many standards, and is basically inefficient.
ERC-4626 addresses this issue as it allows for the implementation of a standard API for tokenized vaults representing shares of a single underlying EIP-20 token and provides basic functionality for depositing and withdrawing tokens and reading balances. Shares represent the stake in the vault and are dependent upon the ratio of total assets and total shares in the vault.
However, innovation and challenges often go hand in hand and one such vulnerability is the “Inflation Attack”.
What is an “Inflation Attack”?
Let’s take the example of Uniswap – a DEX that runs on AMM algorithm. Users can create their liquidity pools, provide liquidity to the pools and in return they get shares – a representation of their stake in the pool, generally known as “LP tokens”. These shares can later be redeemed to get the liquidity out.
This is where anyone can become prone to Inflation Attack as while depositing tokens, the number of shares a user receives is rounded down since they do not exist in float, for example 0.9 shares would mean 0 shares.
The Attack Scenario
First and foremost, it’s essential to understand the formula that would help us calculate the no. of shares (LP tokens) that a user (say Julie), receives when depositing a certain amount of assets in a pool –
totalAssets / totalShares = assetsToDeposit/ sharesToReceive
Step 1: Creation of Vault
Total Assets=0
Total Shares= 0
Step2: Initial Deposit
The attacker creates the pool with a single token
Total Assets= 1
He has all the shares, hence Total Shares = 1
Step3: The Attack
The attacker deposits 10,000 tokens to the pool without minting any shares. This is done to imbalance the pool and lay the foundation for the Inflation attack-
Total Assets in vault= 1 + 10,000= 10001
Total Shares in vault = 1
Step 4: LP’s Deposit
Julie (LP) decides to add liquidity and deposits 10,000 tokens.
Using the formula,
totalAssets / totalShares = assetsToDeposit/ sharesToReceive
We get-
10001/1 = 10000/ sharesToReceive
sharesToReceive = 0.99990000999
As it is less than 1, due to rounding down Julie receives 0 shares. This means that the attacker can now withdraw the liquidity of all the 20001 tokens.
Solution to mitigate this problem
OpenZeppelin has introduced “offset” functionality to fix this vulnerability. Using this implementation, the formula gets modified into-
totalAsset / shares + 10^offset = assetsToDeposit / sharesToReceive
This means that now total shares= shares + 10^offset
Let’s assume offset= 3.
Step 1: Initial Deposit
The attacker creates the pool with a single token
Total Assets= 1
Total Shares=0 + 10^(3)= 1000
Step 2: LP’s Deposit
Julie deposits 10,000 tokens while the attacker tries to frontrun by transferring 10,000 tokens.
Total Assets= 1 + 10000= 10001
Total Shares= shares + 10^(3) offset
= 1000 + 1000 = 2000
Using the formula, totalAsset / shares + 10^offset = assetsToDeposit / sharesToReceive
We get-
10001/ 2000= 10000/ sharesToReceive
sharesToReceive= 1999.8 ~ 1999 shares
Now, if the attacker wants to eat the entire new liquidity and ensure that Julie receives less than 1 share, he has to take the total asset balance to 20,000,000 as described below-
Total shares = 1000 + 1000= 2000
Assets to Deposit= 10000
sharesToReceive= (assetsToDeposit* shares + 10^offset)/ totalAsset < 1
= (10000 * 2000) / totalAsset < 1
= totalAsset > 20,000,000
For an attacker to make sure the LP has 0 shares, he has to donate/transfer around 19,990,000 tokens to the pool so that the total asset balance is 20,000,000 through front run!!
This does not make much financial sense for the attacker and hence prevents pools from inflation attacks. Uniswap V2 also utilizes a similar concept wherein it burns the first 1e-15 (0.000000000000001) pool shares that are minted (1000 times the minimum quantity of pool shares), sending them to the zero address instead of to the minter.
There was some math used in here, but we are hopeful that you feel good after understanding the mechanics behind it.