get_virtual_price() was originally considered to be a manipulation-resistant price - suitable as a price oracle, but it was later found to be vulnerable to a read-only reentrancy attack, where the Curve contract could be put into a partially-modified state, and an attacker could gain control via the raw external call remove_liquidity() makes. The attacker could use this to artificially inflate the price of the LP token/its balance, and use the inflated balance to take out loans which become undercollateralized at the end of the transaction, or to buy assets at exchange rates not actually available on the open market. In order to protect against the attack, many protocols call uint256[2] calldata amts; ICurvePool(token).remove_liquidity(0, amts); prior to calling get_virtual_price() since calling remove_liquidity() will ensure, via a reentrancy guard, that the user isnβt currently manipulating the value, and since amounts are zero, it has no other effect. Another alternative is to call v1 pool.claim_admin_fees() or to call v2 ICurveOwner(pool.owner()).withdraw_admin_fees(address(pool)).
File: contracts/oracle/implementations/ARBTriCryptoOracle.sol
117 function _get() internal view returns (uint256 _maxPrice) {
118 uint256 _vp = TRI_CRYPTO.get_virtual_price();
119
120 // Get the prices from chainlink and add 10 decimals
121 uint256 _btcPrice = uint256(BTC_FEED.latestAnswer()) * 1e10;
122 uint256 _wbtcPrice = uint256(WBTC_FEED.latestAnswer()) * 1e10;
123 uint256 _ethPrice = uint256(ETH_FEED.latestAnswer()) * 1e10;
124 uint256 _usdtPrice = uint256(USDT_FEED.latestAnswer()) * 1e10;
125
126 uint256 _minWbtcPrice = (_wbtcPrice < 1e18)
127 ? (_wbtcPrice * _btcPrice) / 1e18
128 : _btcPrice;
129
130 uint256 _basePrices = (_minWbtcPrice * _ethPrice * _usdtPrice);
131
132 _maxPrice = (3 * _vp * FixedPointMathLib.cbrt(_basePrices)) / 1 ether;
133
134 // ((A/A0) * (gamma/gamma0)**2)** (1/3)
135 uint256 _g = (TRI_CRYPTO.gamma() * 1 ether) / GAMMA0;
136 uint256 _a = (TRI_CRYPTO.A() * 1 ether) / A0;
137 uint256 _discount = Math.max((_g ** 2 / 1 ether) * _a, 1e34); // handle qbrt nonconvergence
138 // if discount is small, we take an upper bound
139 _discount = (FixedPointMathLib.sqrt(_discount) * DISCOUNT0) / 1 ether;
140
141 _maxPrice -= (_maxPrice * _discount) / 1 ether;
142: }
other
The text was updated successfully, but these errors were encountered:
All reactions