Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TradingLibrary.verifyPrice is using a deprecated ChainLink API, which can lead to a stale price being returned. #466

Closed
code423n4 opened this issue Dec 16, 2022 · 2 comments
Labels
2 (Med Risk) Assets not at direct risk, but function/availability of the protocol could be impacted or leak value bug Something isn't working duplicate-655 satisfactory satisfies C4 submission criteria; eligible for awards

Comments

@code423n4
Copy link
Contributor

Lines of code

https://github.com/code-423n4/2022-12-tigris/blob/588c84b7bb354d20cbca6034544c4faa46e6a80e/contracts/utils/TradingLibrary.sol#L113

Vulnerability details

Impact

TradingLibrary.verifyPrice is using the Chainlink latestAnswer function to retrieve an asset price. This function is deprecated, and does not implement any round check to ensure the price is not stale.

This means verifyPrice might have _priceData.price pass the checks with a stale price, ultimately leading to unhealthy trades opened or closed in Trading.

Proof of Concept

The library function verifyPrice calls the ChainLink API:

112:         if (_chainlinkEnabled && _chainlinkFeed != address(0)) {
113:             int256 assetChainlinkPriceInt = IPrice(_chainlinkFeed).latestAnswer();
114:             if (assetChainlinkPriceInt != 0) {
115:                 uint256 assetChainlinkPrice = uint256(assetChainlinkPriceInt) * 10**(18 - IPrice(_chainlinkFeed).decimals());
116:                 require(
117:                     _priceData.price < assetChainlinkPrice+assetChainlinkPrice*2/100 &&
118:                     _priceData.price > assetChainlinkPrice-assetChainlinkPrice*2/100, "!chainlinkPrice"
119:                 );
120:             }
121:         }

The library function is called by TradingExtension.getVerifyPrice:

163: function getVerifiedPrice(
164:         uint _asset,
165:         PriceData calldata _priceData,
166:         bytes calldata _signature,
167:         uint _withSpreadIsLong
168:     ) 
169:         public view
170:         returns(uint256 _price, uint256 _spread) 
171:     {
172:         TradingLibrary.verifyPrice(
173:             validSignatureTimer,
174:             _asset,
175:             chainlinkEnabled,
176:             pairsContract.idToAsset(_asset).chainlinkFeed,
177:             _priceData,
178:             _signature,
179:             isNode
180:         );
181:         _price = _priceData.price;

Which is used to compute the price of assets in all the functions of Trading:

163:     function initiateMarketOrder(
164:         TradeInfo calldata _tradeInfo,
165:         PriceData calldata _priceData,
166:         bytes calldata _signature,
167:         ERC20PermitData calldata _permitData,
168:         address _trader
169:     )
170:         external
171:     {
...
182:         (uint256 _price,) = tradingExtension.getVerifiedPrice(_tradeInfo.asset, _priceData, _signature, _isLong);
222:     function initiateCloseOrder(
223:         uint _id,
224:         uint _percent,
225:         PriceData calldata _priceData,
226:         bytes calldata _signature,
227:         address _stableVault,
228:         address _outputToken,
229:         address _trader
230:     )
231:         external
232:     {
...
239:         (uint256 _price,) = tradingExtension.getVerifiedPrice(_trade.asset, _priceData, _signature, 0);
413:     function removeMargin(
414:         uint256 _id,
415:         address _stableVault,
416:         address _outputToken,
417:         uint256 _removeMargin,
418:         PriceData calldata _priceData,
419:         bytes calldata _signature,
420:         address _trader
421:     )
422:         external
423:     {
...
433:         (uint _assetPrice,) = tradingExtension.getVerifiedPrice(_trade.asset, _priceData, _signature, 0);

Tools Used

Manual Review

Recommended Mitigation Steps

Use the latestRoundData function instead, and implement sufficient checks to ensure the price returned is valid, by checking roundId and answeredInRound.

@code423n4 code423n4 added 2 (Med Risk) Assets not at direct risk, but function/availability of the protocol could be impacted or leak value bug Something isn't working labels Dec 16, 2022
code423n4 added a commit that referenced this issue Dec 16, 2022
@c4-judge
Copy link
Contributor

GalloDaSballo marked the issue as duplicate of #655

@c4-judge c4-judge added the satisfactory satisfies C4 submission criteria; eligible for awards label Jan 22, 2023
@c4-judge
Copy link
Contributor

GalloDaSballo marked the issue as satisfactory

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
2 (Med Risk) Assets not at direct risk, but function/availability of the protocol could be impacted or leak value bug Something isn't working duplicate-655 satisfactory satisfies C4 submission criteria; eligible for awards
Projects
None yet
Development

No branches or pull requests

2 participants