diff --git a/protocol/contracts/beanstalk/farm/TractorFacet.sol b/protocol/contracts/beanstalk/farm/TractorFacet.sol index b03dda3284..9dfc80a5e1 100644 --- a/protocol/contracts/beanstalk/farm/TractorFacet.sol +++ b/protocol/contracts/beanstalk/farm/TractorFacet.sol @@ -18,7 +18,7 @@ import {ReentrancyGuard} from "contracts/beanstalk/ReentrancyGuard.sol"; /** * @title TractorFacet handles tractor and blueprint operations. - * @author funderberker, 0xm00neth + * @author funderberker */ contract TractorFacet is Invariable, ReentrancyGuard { using LibBytes for bytes32; diff --git a/protocol/contracts/libraries/LibTractor.sol b/protocol/contracts/libraries/LibTractor.sol index 11c507a592..d77d926519 100644 --- a/protocol/contracts/libraries/LibTractor.sol +++ b/protocol/contracts/libraries/LibTractor.sol @@ -8,7 +8,7 @@ import {C} from "contracts/C.sol"; /** * @title Lib Tractor - * @author funderbrker, 0xm00neth + * @author funderbrker **/ library LibTractor { enum CounterUpdateType { diff --git a/protocol/contracts/libraries/Oracle/LibUsdOracle.sol b/protocol/contracts/libraries/Oracle/LibUsdOracle.sol index 67570a6016..1e05a576e7 100644 --- a/protocol/contracts/libraries/Oracle/LibUsdOracle.sol +++ b/protocol/contracts/libraries/Oracle/LibUsdOracle.sol @@ -123,7 +123,16 @@ library LibUsdOracle { 0, lookback ); - return tokenPrice.mul(chainlinkTokenPrice).div(CHAINLINK_DENOMINATOR); + + // if token decimals != 0, Beanstalk is attempting to query the USD/TOKEN price, and + // thus the price needs to be inverted. + if (tokenDecimals != 0) { + tokenPrice = (10 ** (6 + tokenDecimals)) / tokenPrice; + return (tokenPrice * chainlinkTokenPrice) / (10 ** tokenDecimals); + } else { + // return the TOKEN/USD price. + return (tokenPrice * chainlinkTokenPrice) / CHAINLINK_DENOMINATOR; + } } // If the oracle implementation address is not set, use the current contract. diff --git a/protocol/contracts/mocks/MockChecker.sol b/protocol/contracts/mocks/MockChecker.sol deleted file mode 100644 index ff9240f972..0000000000 --- a/protocol/contracts/mocks/MockChecker.sol +++ /dev/null @@ -1,26 +0,0 @@ -/* - SPDX-License-Identifier: MIT -*/ - -pragma solidity ^0.8.20; - -/** - * @author 0xm00neth - * @title Mock Contract which checks external function approval - **/ -contract MockChecker { - bool approve; - - function setApprove(bool _approve) external { - approve = _approve; - } - - function check( - address, - bytes calldata, - bytes calldata, - bytes calldata _stateData - ) external view returns (bytes memory) { - return abi.encode(approve, _stateData); - } -} diff --git a/protocol/test/foundry/silo/Oracle.t.sol b/protocol/test/foundry/silo/Oracle.t.sol index 869ec83954..2f2b83d3b4 100644 --- a/protocol/test/foundry/silo/Oracle.t.sol +++ b/protocol/test/foundry/silo/Oracle.t.sol @@ -32,29 +32,7 @@ contract OracleTest is TestHelper { uint256 price = OracleFacet(BEANSTALK).getUsdTokenPrice(WBTC); assertEq(price, 0.00002e8, "price using encode type 0x01"); - // change encode type to 0x02: - vm.prank(BEANSTALK); - bs.updateOracleImplementationForToken( - WBTC, - IMockFBeanstalk.Implementation( - WBTC_USDC_03_POOL, - bytes4(0), - bytes1(0x02), - abi.encode(LibChainlinkOracle.FOUR_HOUR_TIMEOUT) - ) - ); - - // also uniswap relies on having a chainlink oracle for the dollar-denominated token, in this case USDC - vm.prank(BEANSTALK); - bs.updateOracleImplementationForToken( - C.USDC, - IMockFBeanstalk.Implementation( - USDC_USD_CHAINLINK_PRICE_AGGREGATOR, - bytes4(0), - bytes1(0x01), - abi.encode(LibChainlinkOracle.FOUR_DAY_TIMEOUT) - ) - ); + setupUniswapWBTCOracleImplementation(); price = OracleFacet(BEANSTALK).getTokenUsdPrice(WBTC); // 1 USDC will get ~500 satoshis of BTC at $50k @@ -66,6 +44,28 @@ contract OracleTest is TestHelper { assertApproxEqRel(price, 50000e6, 0.001e18, "price using encode type 0x02"); } + function test_uniswap_external() public { + setupUniswapWBTCOracleImplementation(); + + // exercise TokenUsd price and UsdToken price + uint256 tokenUsdPriceFromExternal = OracleFacet(BEANSTALK).getTokenUsdPriceFromExternal( + WBTC, + 0 + ); + assertApproxEqRel( + tokenUsdPriceFromExternal, + 50000e6, + 0.001e18, + "tokenUsdPriceFromExternal" + ); + + uint256 usdTokenPriceFromExternal = OracleFacet(BEANSTALK).getUsdTokenPriceFromExternal( + WBTC, + 0 + ); + assertEq(usdTokenPriceFromExternal, 0.00002e6, "usdTokenPriceFromExternal"); + } + /** * @notice verifies functionality with LSDChainlinkOracle.sol. */ @@ -259,4 +259,29 @@ contract OracleTest is TestHelper { uint256 priceWBTC = OracleFacet(BEANSTALK).getUsdTokenPrice(WBTC); assertEq(priceWBTC, 0.00002e8); // adjusted to 8 decimals } + + function setupUniswapWBTCOracleImplementation() public { + vm.prank(BEANSTALK); + bs.updateOracleImplementationForToken( + WBTC, + IMockFBeanstalk.Implementation( + WBTC_USDC_03_POOL, + bytes4(0), + bytes1(0x02), + abi.encode(LibChainlinkOracle.FOUR_HOUR_TIMEOUT) + ) + ); + + // also uniswap relies on having a chainlink oracle for the dollar-denominated token, in this case USDC + vm.prank(BEANSTALK); + bs.updateOracleImplementationForToken( + C.USDC, + IMockFBeanstalk.Implementation( + USDC_USD_CHAINLINK_PRICE_AGGREGATOR, + bytes4(0), + bytes1(0x01), + abi.encode(LibChainlinkOracle.FOUR_DAY_TIMEOUT) + ) + ); + } }