Analysis of Warp Finance hacked incident

Background

Attack analysis

function provideCollateral(uint256 _amount) public {        require(            LPtoken.allowance(msg.sender, address(this)) >= _amount,            "Vault must have enough allowance."        );        require(            LPtoken.balanceOf(msg.sender) >= _amount,            "Must have enough LP to provide"        );        LPtoken.transferFrom(msg.sender, address(this), _amount);        collateralizedLP[msg.sender] = collateralizedLP[msg.sender].add(            _amount        );
emit CollateralProvided(msg.sender, _amount); }
function borrowSC(address _StableCoin, uint256 _amount) public {     uint256 borrowedTotalInUSDC = getTotalBorrowedValue(msg.sender);     uint256 borrowLimitInUSDC = getBorrowLimit(msg.sender);     uint256 borrowAmountAllowedInUSDC = borrowLimitInUSDC.sub(         borrowedTotalInUSDC     );
uint256 borrowAmountInUSDC = getPriceOfToken(_StableCoin, _amount);
//require the amount being borrowed is less than or equal to the amount they are aloud to borrow require( borrowAmountAllowedInUSDC >= borrowAmountInUSDC, "Borrowing more than allowed" );
//retreive stablecoin vault address being borrowed from and instantiate it WarpVaultSCI WV = WarpVaultSCI(instanceSCTracker[_StableCoin]); //call _borrow function on the stablecoin warp vault WV._borrow(_amount, msg.sender); emit NewBorrow(msg.sender, _StableCoin, _amount); }
function getBorrowLimit(address _account) public returns (uint256) {     uint256 availibleCollateralValue = getTotalAvailableCollateralValue(         _account     );
return calcBorrowLimit(availibleCollateralValue); }
function getTotalAvailableCollateralValue(address _account)     public     returns (uint256){     //get the number of LP vaults the platform has     uint256 numVaults = lpVaults.length;     //initialize the totalCollateral variable to zero     uint256 totalCollateral = 0;     //loop through each lp wapr vault     for (uint256 i = 0; i < numVaults; ++i) {         //instantiate warp vault at that position         WarpVaultLPI vault = WarpVaultLPI(lpVaults[i]);         //retreive the address of its asset         address asset = vault.getAssetAdd();         //retrieve USD price of this asset         uint256 assetPrice = Oracle.getUnderlyingPrice(asset);
uint256 accountCollateral = vault.collateralOfAccount(_account); //emit DebugValues(accountCollateral, assetPrice);
//multiply the amount of collateral by the asset price and return it uint256 accountAssetsValue = accountCollateral.mul(assetPrice); //add value to total collateral totalCollateral = totalCollateral.add(accountAssetsValue); } //return total USDC value of all collateral return totalCollateral.div(1e18); }
function getUnderlyingPrice(address _lpToken) public returns (uint256) {     address[] memory oracleAdds = LPAssetTracker[_lpToken];     //retreives the oracle contract addresses for each asset that makes up a LP     UniswapLPOracleInstance oracle1 = UniswapLPOracleInstance(         oracleAdds[0]     );     UniswapLPOracleInstance oracle2 = UniswapLPOracleInstance(         oracleAdds[1]     );
(uint256 reserveA, uint256 reserveB) = UniswapV2Library.getReserves( factory, instanceTracker[oracleAdds[0]], instanceTracker[oracleAdds[1]] );
uint256 priceAsset1 = oracle1.consult( //SlowMist// instanceTracker[oracleAdds[0]], reserveA ); uint256 priceAsset2 = oracle2.consult( instanceTracker[oracleAdds[1]], reserveB );
// Get the total supply of the pool IERC20 lpToken = IERC20(_lpToken); uint256 totalSupplyOfLP = lpToken.totalSupply(); //SlowMist//
return _calculatePriceOfLP( totalSupplyOfLP, priceAsset1, priceAsset2, lpToken.decimals() ); //return USDC price of the pool divided by totalSupply of its LPs to get price //of one LP }
function _calculatePriceOfLP(     uint256 supply,     uint256 value0,     uint256 value1,     uint8 supplyDecimals ) public pure returns (uint256) {     uint256 totalValue = value0 + value1;     uint16 shiftAmount = supplyDecimals;     uint256 valueShifted = totalValue * uint256(10)**shiftAmount;     uint256 supplyShifted = supply;     uint256 valuePerSupply = valueShifted / supplyShifted;
return valuePerSupply; }

Analysis and verification

The complete attack process

Summary

About us

Focuses on Blockchain Ecosystem Security, have served over 1k+ customers.