diff --git a/packages/contracts/package.json b/packages/contracts/package.json index 04224756f..28baf9cc0 100644 --- a/packages/contracts/package.json +++ b/packages/contracts/package.json @@ -14,7 +14,6 @@ "url": "https://github.com/ubiquity/ubiquity-dollar.git" }, "dependencies": { - "@chainlink/contracts": "^0.8.0", "@types/command-line-args": "5.2.0", "command-line-args": "5.2.1", "dotenv": "^16.0.3", diff --git a/packages/contracts/src/dollar/facets/UbiquityPoolFacet.sol b/packages/contracts/src/dollar/facets/UbiquityPoolFacet.sol index dff34bce9..52c6486e2 100644 --- a/packages/contracts/src/dollar/facets/UbiquityPoolFacet.sol +++ b/packages/contracts/src/dollar/facets/UbiquityPoolFacet.sol @@ -136,9 +136,14 @@ contract UbiquityPoolFacet is IUbiquityPool, Modifiers { /// @inheritdoc IUbiquityPool function addCollateralToken( address collateralAddress, + address chainLinkPriceFeedAddress, uint256 poolCeiling ) external onlyAdmin { - LibUbiquityPool.addCollateralToken(collateralAddress, poolCeiling); + LibUbiquityPool.addCollateralToken( + collateralAddress, + chainLinkPriceFeedAddress, + poolCeiling + ); } /// @inheritdoc IUbiquityPool @@ -147,21 +152,15 @@ contract UbiquityPoolFacet is IUbiquityPool, Modifiers { } /// @inheritdoc IUbiquityPool - function setCollateralPrice( - uint256 collateralIndex, - uint256 newPrice - ) external onlyAdmin { - LibUbiquityPool.setCollateralPrice(collateralIndex, newPrice); - } - - /// @inheritdoc IUbiquityPool - function setCollateralChainLinkPriceFeedAddress( + function setCollateralChainLinkPriceFeed( address collateralAddress, - address chainLinkPriceFeedAddress + address chainLinkPriceFeedAddress, + uint256 stalenessThreshold ) external onlyAdmin { - LibUbiquityPool.setCollateralChainLinkPriceFeedAddress( + LibUbiquityPool.setCollateralChainLinkPriceFeed( collateralAddress, - chainLinkPriceFeedAddress + chainLinkPriceFeedAddress, + stalenessThreshold ); } diff --git a/packages/contracts/src/dollar/interfaces/IUbiquityPool.sol b/packages/contracts/src/dollar/interfaces/IUbiquityPool.sol index 7d3b9a769..5e91ddc9c 100644 --- a/packages/contracts/src/dollar/interfaces/IUbiquityPool.sol +++ b/packages/contracts/src/dollar/interfaces/IUbiquityPool.sol @@ -142,10 +142,12 @@ interface IUbiquityPool { /** * @notice Adds a new collateral token * @param collateralAddress Collateral token address + * @param chainLinkPriceFeedAddress Chainlink's price feed address * @param poolCeiling Max amount of available tokens for collateral */ function addCollateralToken( address collateralAddress, + address chainLinkPriceFeedAddress, uint256 poolCeiling ) external; @@ -156,23 +158,15 @@ interface IUbiquityPool { function removeAmoMinter(address amoMinterAddress) external; /** - * @notice Sets collateral token price in USD - * @param collateralIndex Collateral token index - * @param newPrice New USD price (precision 1e6) - */ - function setCollateralPrice( - uint256 collateralIndex, - uint256 newPrice - ) external; - - /** - * @notice Sets collateral ChainLink price feed address + * @notice Sets collateral ChainLink price feed params * @param collateralAddress Collateral token address * @param chainLinkPriceFeedAddress ChainLink price feed address + * @param stalenessThreshold Threshold in seconds when chainlink answer should be considered stale */ - function setCollateralChainLinkPriceFeedAddress( + function setCollateralChainLinkPriceFeed( address collateralAddress, - address chainLinkPriceFeedAddress + address chainLinkPriceFeedAddress, + uint256 stalenessThreshold ) external; /** diff --git a/packages/contracts/src/dollar/libraries/LibUbiquityPool.sol b/packages/contracts/src/dollar/libraries/LibUbiquityPool.sol index efc5b05b0..2f2a90a35 100644 --- a/packages/contracts/src/dollar/libraries/LibUbiquityPool.sol +++ b/packages/contracts/src/dollar/libraries/LibUbiquityPool.sol @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later pragma solidity 0.8.19; +import {AggregatorV3Interface} from "@chainlink/interfaces/AggregatorV3Interface.sol"; import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; @@ -10,7 +11,6 @@ import {IERC20Ubiquity} from "../interfaces/IERC20Ubiquity.sol"; import {UBIQUITY_POOL_PRICE_PRECISION} from "./Constants.sol"; import {LibAppStorage} from "./LibAppStorage.sol"; import {LibTWAPOracle} from "./LibTWAPOracle.sol"; -import {AggregatorV3Interface} from "@chainlink/interfaces/AggregatorV3Interface.sol"; /** * @notice Ubiquity pool library @@ -42,7 +42,11 @@ library LibUbiquityPool { address[] collateralAddresses; // collateral address -> collateral index mapping(address collateralAddress => uint256 collateralIndex) collateralIndex; - // Stores price of the collateral + // collateral index -> chainlink price feed addresses + address[] collateralPriceFeedAddresses; + // collateral index -> threshold in seconds when chainlink answer should be considered stale + uint256[] collateralPriceFeedStalenessThresholds; + // collateral index -> collateral price uint256[] collateralPrices; // array collateral symbols string[] collateralSymbols; @@ -83,8 +87,6 @@ library LibUbiquityPool { bool[] isMintPaused; // whether redeeming is paused for a particular collateral index bool[] isRedeemPaused; - // Collateral price feed contract address - address[] collateralPriceFeedAddresses; } /// @notice Struct used for detailed collateral information @@ -92,6 +94,8 @@ library LibUbiquityPool { uint256 index; string symbol; address collateralAddress; + address collateralPriceFeedAddress; + uint256 collateralPriceFeedStalenessThreshold; bool isEnabled; uint256 missingDecimals; uint256 price; @@ -126,13 +130,14 @@ library LibUbiquityPool { event AmoMinterAdded(address amoMinterAddress); /// @notice Emitted when AMO minter is removed event AmoMinterRemoved(address amoMinterAddress); - /// @notice Emitted on setting a collateral price - event CollateralPriceSet(uint256 collateralIndex, uint256 newPrice); - /// @notice Emitted on setting a collateral price feed address + /// @notice Emitted on setting a chainlink's collateral price feed params event CollateralPriceFeedSet( uint256 collateralIndex, - address priceFeedAddress + address priceFeedAddress, + uint256 stalenessThreshold ); + /// @notice Emitted on setting a collateral price + event CollateralPriceSet(uint256 collateralIndex, uint256 newPrice); /// @notice Emitted on enabling/disabling a particular collateral token event CollateralToggled(uint256 collateralIndex, bool newState); /// @notice Emitted when fees are updated @@ -221,6 +226,8 @@ library LibUbiquityPool { index, poolStorage.collateralSymbols[index], collateralAddress, + poolStorage.collateralPriceFeedAddresses[index], + poolStorage.collateralPriceFeedStalenessThresholds[index], poolStorage.isCollateralEnabled[collateralAddress], poolStorage.missingDecimals[index], poolStorage.collateralPrices[index], @@ -333,6 +340,8 @@ library LibUbiquityPool { "Minting is paused" ); + // update Dollar price from Curve's Dollar Metapool + LibTWAPOracle.update(); // prevent unnecessary mints require( getDollarPriceUsd() >= poolStorage.mintPriceThreshold, @@ -341,7 +350,8 @@ library LibUbiquityPool { // update collateral price updateChainLinkCollateralPrice(collateralIndex); - // get amount of collateral for incoming Dollars + + // get amount of collateral for minting Dollars collateralNeeded = getDollarInCollateral(collateralIndex, dollarAmount); // subtract the minting fee @@ -402,6 +412,8 @@ library LibUbiquityPool { "Redeeming is paused" ); + // update Dollar price from Curve's Dollar Metapool + LibTWAPOracle.update(); // prevent unnecessary redemptions that could adversely affect the Dollar price require( getDollarPriceUsd() <= poolStorage.redeemPriceThreshold, @@ -416,9 +428,10 @@ library LibUbiquityPool { ) .div(UBIQUITY_POOL_PRICE_PRECISION); - //update collateral price + // update collateral price updateChainLinkCollateralPrice(collateralIndex); + // get collateral output for incoming Dollars collateralOut = getDollarInCollateral(collateralIndex, dollarAfterFee); // checks @@ -503,6 +516,51 @@ library LibUbiquityPool { } } + /** + * @notice Updates collateral token price in USD from ChainLink price feed + * @param collateralIndex Collateral token index + */ + function updateChainLinkCollateralPrice(uint256 collateralIndex) internal { + UbiquityPoolStorage storage poolStorage = ubiquityPoolStorage(); + + AggregatorV3Interface priceFeed = AggregatorV3Interface( + poolStorage.collateralPriceFeedAddresses[collateralIndex] + ); + + // fetch latest price + ( + , + // roundId + int256 answer, // startedAt + , + uint256 updatedAt, + + ) = // answeredInRound + priceFeed.latestRoundData(); + + // fetch number of decimals in chainlink feed + uint256 priceFeedDecimals = priceFeed.decimals(); + + // validation + require(answer > 0, "Invalid price"); + require( + block.timestamp - updatedAt < + poolStorage.collateralPriceFeedStalenessThresholds[ + collateralIndex + ], + "Stale data" + ); + + // convert chainlink price to 6 decimals + uint256 price = uint256(answer).mul(UBIQUITY_POOL_PRICE_PRECISION).div( + 10 ** priceFeedDecimals + ); + + poolStorage.collateralPrices[collateralIndex] = price; + + emit CollateralPriceSet(collateralIndex, price); + } + //========================= // AMO minters functions //========================= @@ -565,10 +623,12 @@ library LibUbiquityPool { /** * @notice Adds a new collateral token * @param collateralAddress Collateral token address + * @param chainLinkPriceFeedAddress Chainlink's price feed address * @param poolCeiling Max amount of available tokens for collateral */ function addCollateralToken( address collateralAddress, + address chainLinkPriceFeedAddress, uint256 poolCeiling ) internal { UbiquityPoolStorage storage poolStorage = ubiquityPoolStorage(); @@ -607,11 +667,16 @@ library LibUbiquityPool { poolStorage.isRedeemPaused.push(false); poolStorage.isBorrowPaused.push(false); - // pool ceiling + // set pool ceiling poolStorage.poolCeilings.push(poolCeiling); - // price feed - poolStorage.collateralPriceFeedAddresses.push(address(0)); + // set price feed address + poolStorage.collateralPriceFeedAddresses.push( + chainLinkPriceFeedAddress + ); + + // set price feed staleness threshold in seconds + poolStorage.collateralPriceFeedStalenessThresholds.push(1 days); } /** @@ -627,66 +692,37 @@ library LibUbiquityPool { } /** - * @notice Sets exact collateral token price in USD - * @param collateralIndex Collateral token index - * @param newPrice New USD price (precision 1e6) - */ - function setCollateralPrice( - uint256 collateralIndex, - uint256 newPrice - ) internal { - UbiquityPoolStorage storage poolStorage = ubiquityPoolStorage(); - - poolStorage.collateralPrices[collateralIndex] = newPrice; - - emit CollateralPriceSet(collateralIndex, newPrice); - } - - /** - * @notice Sets collateral ChainLink price feed address + * @notice Sets collateral ChainLink price feed params * @param collateralAddress Collateral token address * @param chainLinkPriceFeedAddress ChainLink price feed address + * @param stalenessThreshold Threshold in seconds when chainlink answer should be considered stale */ - function setCollateralChainLinkPriceFeedAddress( + function setCollateralChainLinkPriceFeed( address collateralAddress, - address chainLinkPriceFeedAddress + address chainLinkPriceFeedAddress, + uint256 stalenessThreshold ) internal { UbiquityPoolStorage storage poolStorage = ubiquityPoolStorage(); uint256 collateralIndex = poolStorage.collateralIndex[ collateralAddress ]; + + // set price feed address poolStorage.collateralPriceFeedAddresses[ collateralIndex ] = chainLinkPriceFeedAddress; - emit CollateralPriceFeedSet(collateralIndex, chainLinkPriceFeedAddress); - } - - /** - * @notice Updates collateral token price in USD from ChainLink price feed - * @param collateralIndex Collateral token index - */ - function updateChainLinkCollateralPrice(uint256 collateralIndex) internal { - UbiquityPoolStorage storage poolStorage = ubiquityPoolStorage(); + // set staleness threshold in seconds when chainlink answer should be considered stale + poolStorage.collateralPriceFeedStalenessThresholds[ + collateralIndex + ] = stalenessThreshold; - AggregatorV3Interface priceFeed = AggregatorV3Interface( - poolStorage.collateralPriceFeedAddresses[collateralIndex] - ); - ( - uint80 roundID, - int256 price, - , - uint256 updatedAt, - uint80 answeredInRound - ) = priceFeed.latestRoundData(); - require( - price >= 0 && updatedAt != 0 && answeredInRound >= roundID, - "Invalid ChainLink price" + emit CollateralPriceFeedSet( + collateralIndex, + chainLinkPriceFeedAddress, + stalenessThreshold ); - - poolStorage.collateralPrices[collateralIndex] = uint256(price); - emit CollateralPriceSet(collateralIndex, uint256(price)); } /** diff --git a/packages/contracts/src/dollar/mocks/MockChainLinkFeed.sol b/packages/contracts/src/dollar/mocks/MockChainLinkFeed.sol index 3e3d87d3b..872b7ab87 100644 --- a/packages/contracts/src/dollar/mocks/MockChainLinkFeed.sol +++ b/packages/contracts/src/dollar/mocks/MockChainLinkFeed.sol @@ -10,16 +10,15 @@ contract MockChainLinkFeed is AggregatorV3Interface { uint256 updatedAt; uint80 answeredInRound; + uint8 public decimals; + constructor() { roundId = 0; answer = 0; startedAt = block.timestamp; updatedAt = block.timestamp; answeredInRound = 0; - } - - function decimals() external pure override returns (uint8) { - return 18; + decimals = 8; } function description() external pure override returns (string memory) { @@ -38,13 +37,7 @@ contract MockChainLinkFeed is AggregatorV3Interface { override returns (uint80, int256, uint256, uint256, uint80) { - return ( - roundId, - answer, - block.timestamp, - block.timestamp, - answeredInRound - ); + return (roundId, answer, startedAt, updatedAt, answeredInRound); } function latestRoundData() @@ -53,22 +46,24 @@ contract MockChainLinkFeed is AggregatorV3Interface { override returns (uint80, int256, uint256, uint256, uint80) { - return ( - roundId, - answer, - block.timestamp, - block.timestamp, - answeredInRound - ); + return (roundId, answer, startedAt, updatedAt, answeredInRound); + } + + function updateDecimals(uint8 _newDecimals) public { + decimals = _newDecimals; } function updateMockParams( uint80 _roundId, int256 _answer, + uint256 _startedAt, + uint256 _updatedAt, uint80 _answeredInRound ) public { roundId = _roundId; answer = _answer; + startedAt = _startedAt; + updatedAt = _updatedAt; answeredInRound = _answeredInRound; } } diff --git a/packages/contracts/test/diamond/facets/UbiquityPoolFacet.t.sol b/packages/contracts/test/diamond/facets/UbiquityPoolFacet.t.sol index a86efbb82..de8946d67 100644 --- a/packages/contracts/test/diamond/facets/UbiquityPoolFacet.t.sol +++ b/packages/contracts/test/diamond/facets/UbiquityPoolFacet.t.sol @@ -6,8 +6,8 @@ import {DiamondTestSetup} from "../DiamondTestSetup.sol"; import {IDollarAmoMinter} from "../../../src/dollar/interfaces/IDollarAmoMinter.sol"; import {IMetaPool} from "../../../src/dollar/interfaces/IMetaPool.sol"; import {LibUbiquityPool} from "../../../src/dollar/libraries/LibUbiquityPool.sol"; -import {MockERC20} from "../../../src/dollar/mocks/MockERC20.sol"; import {MockChainLinkFeed} from "../../../src/dollar/mocks/MockChainLinkFeed.sol"; +import {MockERC20} from "../../../src/dollar/mocks/MockERC20.sol"; import {MockMetaPool} from "../../../src/dollar/mocks/MockMetaPool.sol"; contract MockDollarAmoMinter is IDollarAmoMinter { @@ -26,11 +26,17 @@ contract UbiquityPoolFacetTest is DiamondTestSetup { MockChainLinkFeed collateralTokenPriceFeed; MockMetaPool curveDollarMetaPool; MockERC20 curveTriPoolLpToken; + address user = address(1); // Events event AmoMinterAdded(address amoMinterAddress); event AmoMinterRemoved(address amoMinterAddress); + event CollateralPriceFeedSet( + uint256 collateralIndex, + address priceFeedAddress, + uint256 stalenessThreshold + ); event CollateralPriceSet(uint256 collateralIndex, uint256 newPrice); event CollateralToggled(uint256 collateralIndex, bool newState); event FeesSet( @@ -70,18 +76,24 @@ contract UbiquityPoolFacetTest is DiamondTestSetup { uint256 poolCeiling = 50_000e18; // max 50_000 of collateral tokens is allowed ubiquityPoolFacet.addCollateralToken( address(collateralToken), + address(collateralTokenPriceFeed), poolCeiling ); - ubiquityPoolFacet.setCollateralChainLinkPriceFeedAddress( - address(collateralToken), - address(collateralTokenPriceFeed) + // set collateral price feed mock params + collateralTokenPriceFeed.updateMockParams( + 1, // round id + 100_000_000, // answer, 100_000_000 = $1.00 (chainlink 8 decimals answer is converted to 6 decimals pool price) + block.timestamp, // started at + block.timestamp, // updated at + 1 // answered in round ); - MockChainLinkFeed(collateralTokenPriceFeed).updateMockParams( - 1, - 1_000_000, - 2 + // set price feed for collateral token + ubiquityPoolFacet.setCollateralChainLinkPriceFeed( + address(collateralToken), // collateral token address + address(collateralTokenPriceFeed), // price feed address + 1 days // price feed staleness threshold in seconds ); // enable collateral at index 0 @@ -174,6 +186,11 @@ contract UbiquityPoolFacetTest is DiamondTestSetup { assertEq(info.index, 0); assertEq(info.symbol, "CLT"); assertEq(info.collateralAddress, address(collateralToken)); + assertEq( + info.collateralPriceFeedAddress, + address(collateralTokenPriceFeed) + ); + assertEq(info.collateralPriceFeedStalenessThreshold, 1 days); assertEq(info.isEnabled, true); assertEq(info.missingDecimals, 0); assertEq(info.price, 1_000_000); @@ -517,6 +534,68 @@ contract UbiquityPoolFacetTest is DiamondTestSetup { assertEq(collateralToken.balanceOf(user), 97.02e18); } + function testUpdateChainLinkCollateralPrice_ShouldRevert_IfChainlinkAnswerIsInvalid() + public + { + // set invalid answer from chainlink + collateralTokenPriceFeed.updateMockParams( + 1, // round id + 0, // invalid answer + block.timestamp, // started at + block.timestamp, // updated at + 1 // answered in round + ); + + vm.expectRevert("Invalid price"); + ubiquityPoolFacet.updateChainLinkCollateralPrice(0); + } + + function testUpdateChainLinkCollateralPrice_ShouldRevert_IfChainlinkAnswerIsStale() + public + { + // set stale answer from chainlink + collateralTokenPriceFeed.updateMockParams( + 1, // round id + 100_000_000, // answer, 100_000_000 = $1.00 + block.timestamp, // started at + block.timestamp, // updated at + 1 // answered in round + ); + + // wait 1 day + vm.warp(block.timestamp + 1 days); + + vm.expectRevert("Stale data"); + ubiquityPoolFacet.updateChainLinkCollateralPrice(0); + } + + function testUpdateChainLinkCollateralPrice_ShouldUpdateCollateralPrice() + public + { + // before + LibUbiquityPool.CollateralInformation memory info = ubiquityPoolFacet + .collateralInformation(address(collateralToken)); + assertEq(info.price, 1_000_000); + + // set answer from chainlink + collateralTokenPriceFeed.updateMockParams( + 1, // round id + 99_000_000, // answer, 99_000_000 = $0.99 + block.timestamp, // started at + block.timestamp, // updated at + 1 // answered in round + ); + + // update collateral price + ubiquityPoolFacet.updateChainLinkCollateralPrice(0); + + // after + info = ubiquityPoolFacet.collateralInformation( + address(collateralToken) + ); + assertEq(info.price, 990_000); + } + //========================= // AMO minters functions //========================= @@ -597,6 +676,11 @@ contract UbiquityPoolFacetTest is DiamondTestSetup { assertEq(info.index, 0); assertEq(info.symbol, "CLT"); assertEq(info.collateralAddress, address(collateralToken)); + assertEq( + info.collateralPriceFeedAddress, + address(collateralTokenPriceFeed) + ); + assertEq(info.collateralPriceFeedStalenessThreshold, 1 days); assertEq(info.isEnabled, true); assertEq(info.missingDecimals, 0); assertEq(info.price, 1_000_000); @@ -618,22 +702,39 @@ contract UbiquityPoolFacetTest is DiamondTestSetup { vm.stopPrank(); } - function testSetCollateralPrice_ShouldSetCollateralPriceInUsd() public { + function testSetCollateralChainLinkPriceFeed_ShouldSetPriceFeed() public { vm.startPrank(admin); LibUbiquityPool.CollateralInformation memory info = ubiquityPoolFacet .collateralInformation(address(collateralToken)); - assertEq(info.price, 1_000_000); + assertEq( + info.collateralPriceFeedAddress, + address(collateralTokenPriceFeed) + ); + assertEq(info.collateralPriceFeedStalenessThreshold, 1 days); - uint256 newCollateralPrice = 1_100_000; + address newPriceFeedAddress = address(1); + uint256 newStalenessThreshold = 2 days; vm.expectEmit(address(ubiquityPoolFacet)); - emit CollateralPriceSet(0, newCollateralPrice); - ubiquityPoolFacet.setCollateralPrice(0, newCollateralPrice); + emit CollateralPriceFeedSet( + 0, + newPriceFeedAddress, + newStalenessThreshold + ); + ubiquityPoolFacet.setCollateralChainLinkPriceFeed( + address(collateralToken), + newPriceFeedAddress, + newStalenessThreshold + ); info = ubiquityPoolFacet.collateralInformation( address(collateralToken) ); - assertEq(info.price, newCollateralPrice); + assertEq(info.collateralPriceFeedAddress, newPriceFeedAddress); + assertEq( + info.collateralPriceFeedStalenessThreshold, + newStalenessThreshold + ); vm.stopPrank(); } @@ -777,113 +878,4 @@ contract UbiquityPoolFacetTest is DiamondTestSetup { vm.stopPrank(); } - - function testCollateralTwap() public { - vm.startPrank(admin); - - // use mocked meta pool for collateral twap - MockMetaPool collateralCurveMetaPool; - - collateralCurveMetaPool = new MockMetaPool( - address(collateralToken), - address(curveTriPoolLpToken) - ); - - uint256[2] memory price_cumulative_last = [ - uint256(1e18), - uint256(1e18) - ]; - uint256 last_block_timestamp = 100000; - uint256[2] memory twap_balances = [uint256(1e18), uint256(1e18)]; - uint256[2] memory dy_values = [uint256(1e18), uint256(1e18)]; - - collateralCurveMetaPool.updateMockParams( - price_cumulative_last, - last_block_timestamp, - twap_balances, - dy_values - ); - - uint256[2] memory current_twap = collateralCurveMetaPool - .get_twap_balances(twap_balances, twap_balances, 1); - - console.log(current_twap[0]); - console.log(current_twap[1]); - - vm.stopPrank(); - } - - function testCollateralPriceFeed_ShouldUpdatePrice() public { - vm.startPrank(admin); - - LibUbiquityPool.CollateralInformation memory info = ubiquityPoolFacet - .collateralInformation(address(collateralToken)); - assertEq(info.price, 1_000_000); - - int256 mockedPriceFeedPrice = 1_000_123; - - MockChainLinkFeed(collateralTokenPriceFeed).updateMockParams( - 1, - mockedPriceFeedPrice, - 3 - ); - - ubiquityPoolFacet.updateChainLinkCollateralPrice(0); - - info = ubiquityPoolFacet.collateralInformation( - address(collateralToken) - ); - assertEq(info.price, uint256(mockedPriceFeedPrice)); - - vm.stopPrank(); - } - - function testCollateralPriceFeed_ShouldWorkWithMultipleCollateralTokens() - public - { - vm.startPrank(admin); - - LibUbiquityPool.CollateralInformation memory info = ubiquityPoolFacet - .collateralInformation(address(collateralToken)); - assertEq(info.price, 1_000_000); - - // init collateral token - MockERC20 collateralToken2 = new MockERC20("COLLATERAL2", "CLT2", 18); - - // init collateral price feed and set price to 0.999999 - MockChainLinkFeed collateralTokenPriceFeed2 = new MockChainLinkFeed(); - MockChainLinkFeed(collateralTokenPriceFeed2).updateMockParams( - 1, - 999_999, - 2 - ); - // add second collateral token to the pool - uint256 poolCeiling = 5_000e18; - ubiquityPoolFacet.addCollateralToken( - address(collateralToken2), - poolCeiling - ); - - // enable collateral at index 1 - ubiquityPoolFacet.toggleCollateral(1); - - ubiquityPoolFacet.setCollateralChainLinkPriceFeedAddress( - address(collateralToken2), - address(collateralTokenPriceFeed2) - ); - - ubiquityPoolFacet.updateChainLinkCollateralPrice(1); - - info = ubiquityPoolFacet.collateralInformation( - address(collateralToken) - ); - assertEq(info.price, 1_000_000); - - info = ubiquityPoolFacet.collateralInformation( - address(collateralToken2) - ); - assertEq(info.price, 999_999); - - vm.stopPrank(); - } } diff --git a/yarn.lock b/yarn.lock index 90707cc95..a82fb4672 100644 --- a/yarn.lock +++ b/yarn.lock @@ -270,18 +270,6 @@ __metadata: languageName: node linkType: hard -"@chainlink/contracts@npm:^0.8.0": - version: 0.8.0 - resolution: "@chainlink/contracts@npm:0.8.0" - dependencies: - "@eth-optimism/contracts": ^0.5.21 - "@openzeppelin/contracts": ~4.3.3 - "@openzeppelin/contracts-upgradeable-4.7.3": "npm:@openzeppelin/contracts-upgradeable@v4.7.3" - "@openzeppelin/contracts-v0.7": "npm:@openzeppelin/contracts@v3.4.2" - checksum: 4165aa7fa5d28c2ebef4da72e117f78889da292cff03d736d5738e2a3842d5fd162718106c2c04e9acb41298813edc99a27c456217a00bfdd4b0dfb758802cd0 - languageName: node - linkType: hard - "@coinbase/wallet-sdk@npm:^3.5.4": version: 3.6.5 resolution: "@coinbase/wallet-sdk@npm:3.6.5" @@ -1313,43 +1301,6 @@ __metadata: languageName: node linkType: hard -"@eth-optimism/contracts@npm:^0.5.21": - version: 0.5.40 - resolution: "@eth-optimism/contracts@npm:0.5.40" - dependencies: - "@eth-optimism/core-utils": 0.12.0 - "@ethersproject/abstract-provider": ^5.7.0 - "@ethersproject/abstract-signer": ^5.7.0 - peerDependencies: - ethers: ^5 - checksum: 11dde466c90b886efe8b5fd123fa5893187a4ff84839213d417f90ae4e45bf00b2f62d56e4ebe23ba5dd7ec33beed22c4c41e206add35fce0db073fe2dbae6ba - languageName: node - linkType: hard - -"@eth-optimism/core-utils@npm:0.12.0": - version: 0.12.0 - resolution: "@eth-optimism/core-utils@npm:0.12.0" - dependencies: - "@ethersproject/abi": ^5.7.0 - "@ethersproject/abstract-provider": ^5.7.0 - "@ethersproject/address": ^5.7.0 - "@ethersproject/bignumber": ^5.7.0 - "@ethersproject/bytes": ^5.7.0 - "@ethersproject/constants": ^5.7.0 - "@ethersproject/contracts": ^5.7.0 - "@ethersproject/hash": ^5.7.0 - "@ethersproject/keccak256": ^5.7.0 - "@ethersproject/properties": ^5.7.0 - "@ethersproject/providers": ^5.7.0 - "@ethersproject/rlp": ^5.7.0 - "@ethersproject/transactions": ^5.7.0 - "@ethersproject/web": ^5.7.0 - bufio: ^1.0.7 - chai: ^4.3.4 - checksum: 1c820107c44bdbb46becb1b00fd0dabb44f3ac8f54e6da7872a5a134411fad26f53b193225da55e79d6a8d7f0d01cc16a123db5d41ebaf02ca78360249a4b52a - languageName: node - linkType: hard - "@ethersproject/abi@npm:5, @ethersproject/abi@npm:5.7.0, @ethersproject/abi@npm:^5.0.0, @ethersproject/abi@npm:^5.0.12, @ethersproject/abi@npm:^5.1.2, @ethersproject/abi@npm:^5.5.0, @ethersproject/abi@npm:^5.7.0": version: 5.7.0 resolution: "@ethersproject/abi@npm:5.7.0" @@ -1456,7 +1407,7 @@ __metadata: languageName: node linkType: hard -"@ethersproject/contracts@npm:5.7.0, @ethersproject/contracts@npm:^5.7.0": +"@ethersproject/contracts@npm:5.7.0": version: 5.7.0 resolution: "@ethersproject/contracts@npm:5.7.0" dependencies: @@ -1577,7 +1528,7 @@ __metadata: languageName: node linkType: hard -"@ethersproject/providers@npm:5.7.2, @ethersproject/providers@npm:^5, @ethersproject/providers@npm:^5.6.8, @ethersproject/providers@npm:^5.7.0": +"@ethersproject/providers@npm:5.7.2, @ethersproject/providers@npm:^5, @ethersproject/providers@npm:^5.6.8": version: 5.7.2 resolution: "@ethersproject/providers@npm:5.7.2" dependencies: @@ -2711,20 +2662,6 @@ __metadata: languageName: node linkType: hard -"@openzeppelin/contracts-upgradeable-4.7.3@npm:@openzeppelin/contracts-upgradeable@v4.7.3": - version: 4.7.3 - resolution: "@openzeppelin/contracts-upgradeable@npm:4.7.3" - checksum: c9ffb40cb847a975d440204fc6a811f43af960050242f707332b984d29bd16dc242ffa0935de61867aeb9e0357fadedb16b09b276deda5e9775582face831021 - languageName: node - linkType: hard - -"@openzeppelin/contracts-v0.7@npm:@openzeppelin/contracts@v3.4.2": - version: 3.4.2 - resolution: "@openzeppelin/contracts@npm:3.4.2" - checksum: 0c90f029fe50a49643588e4c8670dae3bbf31795133a6ddce9bdcbc258486332700bb732287baabf7bf807f39182fe8ea2ffa19aa5caf359b1b9c0f083280748 - languageName: node - linkType: hard - "@openzeppelin/contracts@npm:3.4.1-solc-0.7-2": version: 3.4.1-solc-0.7-2 resolution: "@openzeppelin/contracts@npm:3.4.1-solc-0.7-2" @@ -2739,13 +2676,6 @@ __metadata: languageName: node linkType: hard -"@openzeppelin/contracts@npm:~4.3.3": - version: 4.3.3 - resolution: "@openzeppelin/contracts@npm:4.3.3" - checksum: 73eb23e7acc8531931076d11251629bdc8579c99ef921a3facbd8abf7b860bc214c97a4bd56cd67db7c9d1db837765132640f24987aac8097a13960bb41ca6d1 - languageName: node - linkType: hard - "@pedrouid/environment@npm:^1.0.1": version: 1.0.1 resolution: "@pedrouid/environment@npm:1.0.1" @@ -3819,7 +3749,6 @@ __metadata: version: 0.0.0-use.local resolution: "@ubiquity/contracts@workspace:packages/contracts" dependencies: - "@chainlink/contracts": ^0.8.0 "@types/command-line-args": 5.2.0 "@types/node": ^18.11.18 "@types/react-transition-group": ^4 @@ -6244,13 +6173,6 @@ __metadata: languageName: node linkType: hard -"bufio@npm:^1.0.7": - version: 1.2.1 - resolution: "bufio@npm:1.2.1" - checksum: b6e1216f4a5877617a3580b83807d8b96c794c015bc2d5eb9e70e152dc79fe923517472bd96df3d5b8feb59a0e25e2aa3cd8a70b8f90905b92d86f2e5719ed68 - languageName: node - linkType: hard - "bunyan-blackhole@npm:^1.1.1": version: 1.1.1 resolution: "bunyan-blackhole@npm:1.1.1" @@ -6397,21 +6319,6 @@ __metadata: languageName: node linkType: hard -"chai@npm:^4.3.4": - version: 4.3.10 - resolution: "chai@npm:4.3.10" - dependencies: - assertion-error: ^1.1.0 - check-error: ^1.0.3 - deep-eql: ^4.1.3 - get-func-name: ^2.0.2 - loupe: ^2.3.6 - pathval: ^1.1.1 - type-detect: ^4.0.8 - checksum: 536668c60a0d985a0fbd94418028e388d243a925d7c5e858c7443e334753511614a3b6a124bac9ca077dfc4c37acc367d62f8c294960f440749536dc181dfc6d - languageName: node - linkType: hard - "chai@npm:^4.3.7": version: 4.3.7 resolution: "chai@npm:4.3.7" @@ -6462,15 +6369,6 @@ __metadata: languageName: node linkType: hard -"check-error@npm:^1.0.3": - version: 1.0.3 - resolution: "check-error@npm:1.0.3" - dependencies: - get-func-name: ^2.0.2 - checksum: e2131025cf059b21080f4813e55b3c480419256914601750b0fee3bd9b2b8315b531e551ef12560419b8b6d92a3636511322752b1ce905703239e7cc451b6399 - languageName: node - linkType: hard - "chokidar@npm:3.5.3, chokidar@npm:^3.4.0, chokidar@npm:^3.5.2, chokidar@npm:^3.5.3": version: 3.5.3 resolution: "chokidar@npm:3.5.3" @@ -7344,7 +7242,7 @@ __metadata: languageName: node linkType: hard -"deep-eql@npm:^4.1.2, deep-eql@npm:^4.1.3": +"deep-eql@npm:^4.1.2": version: 4.1.3 resolution: "deep-eql@npm:4.1.3" dependencies: @@ -8816,13 +8714,6 @@ __metadata: languageName: node linkType: hard -"get-func-name@npm:^2.0.1, get-func-name@npm:^2.0.2": - version: 2.0.2 - resolution: "get-func-name@npm:2.0.2" - checksum: 3f62f4c23647de9d46e6f76d2b3eafe58933a9b3830c60669e4180d6c601ce1b4aa310ba8366143f55e52b139f992087a9f0647274e8745621fa2af7e0acf13b - languageName: node - linkType: hard - "get-intrinsic@npm:^1.0.2, get-intrinsic@npm:^1.1.1, get-intrinsic@npm:^1.1.3, get-intrinsic@npm:^1.2.0": version: 1.2.0 resolution: "get-intrinsic@npm:1.2.0" @@ -10632,15 +10523,6 @@ __metadata: languageName: node linkType: hard -"loupe@npm:^2.3.6": - version: 2.3.7 - resolution: "loupe@npm:2.3.7" - dependencies: - get-func-name: ^2.0.1 - checksum: 96c058ec7167598e238bb7fb9def2f9339215e97d6685d9c1e3e4bdb33d14600e11fe7a812cf0c003dfb73ca2df374f146280b2287cae9e8d989e9d7a69a203b - languageName: node - linkType: hard - "lru-cache@npm:^4.0.1": version: 4.1.5 resolution: "lru-cache@npm:4.1.5" @@ -14482,7 +14364,7 @@ __metadata: languageName: node linkType: hard -"type-detect@npm:^4.0.0, type-detect@npm:^4.0.5, type-detect@npm:^4.0.8": +"type-detect@npm:^4.0.0, type-detect@npm:^4.0.5": version: 4.0.8 resolution: "type-detect@npm:4.0.8" checksum: 62b5628bff67c0eb0b66afa371bd73e230399a8d2ad30d852716efcc4656a7516904570cd8631a49a3ce57c10225adf5d0cbdcb47f6b0255fe6557c453925a15