Flash Loan Exploit in frens Function
mudgen opened this issue · comments
@samczsun reported a possible flash loan exploit with the frens
function in the StakingFacet.sol file.
Here is the frens function:
function frens(address _account) public view returns (uint256 frens_) {
Account memory account = s.accounts[_account];
uint256 poolGhst;
if (account.uniV2PoolTokens > 0) {
// Calculated from the burn function of the UniswapV2Pair.sol contract
// https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2Pair.sol#L144
uint256 poolContractGhstBalance = IERC20(s.ghstContract).balanceOf(s.uniV2PoolContract);
// multiply the poolGhst by 2 because the user is also supplying Eth for the pool
poolGhst = ((account.uniV2PoolTokens * poolContractGhstBalance) / IERC20(s.uniV2PoolContract).totalSupply()) * 2;
}
// 86400 the number of seconds in 1 day
// frens are generated 1 fren for each GHST over 24 hours
frens_ = account.frens + ((account.ghst + poolGhst) * (block.timestamp - account.lastUpdate)) / 86400;
}
It is possible to use a flash load to temporarily inflate the amount of GHST in the uniswap pool in order to generate more frens points.
Here are the steps of such an exploit:
- buy GHST
- supply GHST and ETH to pool
- deposit LP tokens
- wait a week
- flash loan eth, buy ghst from balancer, transfer ghst to uniswap, update frens, skim ghst out of uniswap, sell ghst on balancer, return eth
GHST can be transferred directly to the the uniswap pool, bypassing uniswap contract logic. Later uniswap's skim()
function can be called to remove GHST from the pool.
The flash loan is used to increase the value of poolContractGhstBalance
, without increasing the value of IERC20(s.uniV2PoolContract).totalSupply()
in order to increase the amount of frens points generated.
This exploit does not result in the loss of funds or a contract being frozen. @samczsun is awarded 2,000 DAI for finding and reporting this issue.
The code for the frens
function is being updated to fix the issue.