Platform: Code4rena
Start Date: 16/09/2021
Pot Size: $200,000 SUSHI
Total HM: 26
Participants: 16
Period: 14 days
Judge: alcueca
Total Solo HM: 13
Id: 29
League: ETH
Rank: 12/16
Findings: 2
Award: $1,467.16
🌟 Selected for report: 3
🚀 Solo Findings: 0
14.5161 SUSHI - $181.45
gpersoon
The function _update() of ConstantProductPool.sol verifies if blockTimestampLast == 0. The value of blockTimestampLast is also passed in the parameter _blockTimestampLast (note: with extra _ ) So _blockTimestampLast could also be used, which saves a bit of gas.
https://github.com/sushiswap/trident/blob/master/contracts/pool/ConstantProductPool.sol#L264 function _update(... uint32 _blockTimestampLast) internal { ... if (blockTimestampLast == 0) { // could also use _blockTimestampLast
replace
if (blockTimestampLast == 0) {
with
if (_blockTimestampLast == 0) {
🌟 Selected for report: gpersoon
32.2581 SUSHI - $403.23
gpersoon
In the function _powApprox of IndexPool.sol a few gas savings are possible, see suggestion below.
https://github.com/sushiswap/trident/blob/master/contracts/pool/IndexPool.sol#L286
Suggestion for optimization: function _powApprox(uint256 base, uint256 exp, uint256 precision) internal pure returns (uint256 sum) { uint256 a = exp; (uint256 x, bool xneg) = _subFlag(base, BASE); uint256 term = BASE; sum = term; bool negative; uint256 bigK=0; // initially 0 for (uint256 i = 1; term >= precision; i++) { (uint256 c, bool cneg) = _subFlag(a, bigK)); // now bigK = (i-1) * BASE; term = _mul(term, _mul(c, x)); bigK += BASE; // now bigK = i * BASE; term = _div(term, bigK); if (term == 0) break; negative = negative != xneg; // more predictable gas usage & slightly lower gas negative = negative != cneg; // more predictable gas usage & slightly lower gas sum = (negative ? sum - term : sum + term); // slightly less instructions } }
#0 - maxsam4
2021-09-22T08:50:24Z
I haven't run the numbers but I accept your code might be a few gas units (double digits) optimal. However, we'd stick with the current code as it is well tested and more legible IMO.
🌟 Selected for report: gpersoon
70.5984 SUSHI - $882.48
gpersoon
The callback functions in TridentRouter.sol check "msg.sender == cachedPool" on the function entry. At the end of the function cachedMsgSender is reset to 1. However cachedPool is not reset to 1. This means tridentSwapCallback / tridentMintCallback could be called again. I couldn't find a scenario to misuse this, but maybe setting cachedPool to address(1) is worth the trouble.
https://github.com/sushiswap/trident/blob/master/contracts/TridentRouter.sol#L19
/// @dev Used to ensure that tridentSwapCallback
is called only by the authorized address.
/// These are set when someone calls a flash swap and reset afterwards.
address internal cachedMsgSender;
address internal cachedPool;
function tridentSwapCallback(bytes calldata data) external { require(msg.sender == cachedPool, "UNAUTHORIZED_CALLBACK"); ... cachedMsgSender = address(1); }
function tridentMintCallback(bytes calldata data) external { require(msg.sender == cachedPool, "UNAUTHORIZED_CALLBACK"); ... cachedMsgSender = address(1); }
Consider also setting cachedPool to address(1) at the end of the functions tridentSwapCallback and tridentMintCallback
#0 - maxsam4
2021-09-22T08:36:47Z
Resetting cachedMsgSender
is a sufficient check. cachedPool
is not reset here for gas efficiency.
If you can come up with a scenario where this can be misused, I'll be happy to reconsider my stance.
#1 - alcueca
2021-10-24T05:42:10Z
Not resetting cachedPool
seems like an overzealous optimization. An inconsistent state is being allowed. A low risk issue refers to code quality and doesn't require a misuse scenario (that would warrant a severity of 2 or 3).