DeFiHardhatOracleProxyUpdates
100,000 USDC
View results
Submission Details
Severity: low
Invalid

Reentrancy vulnerabilities (events)

Summary

Possible Reentrancy vulnerabilities leading to out-of-order Events, making difficult for off chain tools to monitor the state of protocol.

Vulnerability Details

File: contracts/beanstalk/sun/SeasonFacet/SeasonFacet.sol
/// @audit ******************* Issue Detail *******************
Reentrancy (events) in SeasonFacet.gm(address,LibTransfer.To) (contracts/beanstalk/sun/SeasonFacet/SeasonFacet.sol#44-57):
External calls:
- caseId = calcCaseIdandUpdate(deltaB) (contracts/beanstalk/sun/SeasonFacet/SeasonFacet.sol#51)
- C.bean().mint(address(this),newHarvestable.add(sopBeans)) (contracts/beanstalk/sun/SeasonFacet/Weather.sol#196)
- C.bean().mint(address(this),sopBeans) (contracts/beanstalk/sun/SeasonFacet/Weather.sol#198)
- C.bean().approve(sopWell,sopBeans) (contracts/beanstalk/sun/SeasonFacet/Weather.sol#202)
- amountOut = IWell(sopWell).swapFrom(C.bean(),sopToken,sopBeans,0,address(this),type()(uint256).max) (contracts/beanstalk/sun/SeasonFacet/Weather.sol#203-210)
- stepSun(deltaB,caseId) (contracts/beanstalk/sun/SeasonFacet/SeasonFacet.sol#54)
- C.bean().mint(address(this),newSupply) (contracts/beanstalk/sun/SeasonFacet/Sun.sol#86)
- incentivize(account,initialGasLeft,mode) (contracts/beanstalk/sun/SeasonFacet/SeasonFacet.sol#56)
- returndata = address(token).functionCall(data,SafeERC20: low-level call failed) (node_modules/@openzeppelin/contracts/token/ERC20/SafeERC20.sol#69)
- token.mint(recipient,amount) (contracts/libraries/Token/LibTransfer.sol#110)
- token.mint(address(this),amount) (contracts/libraries/Token/LibTransfer.sol#112)
- (success,returndata) = target.call{value: value}(data) (node_modules/@openzeppelin/contracts/utils/Address.sol#119)
- token.safeTransfer(recipient,amount) (contracts/libraries/Token/LibTransfer.sol#82)
- LibTransfer.mintToken(C.bean(),incentiveAmount,account,mode) (contracts/beanstalk/sun/SeasonFacet/SeasonFacet.sol#116)
External calls sending eth:
- incentivize(account,initialGasLeft,mode) (contracts/beanstalk/sun/SeasonFacet/SeasonFacet.sol#56)
- (success,returndata) = target.call{value: value}(data) (node_modules/@openzeppelin/contracts/utils/Address.sol#119)
Event emitted after the call(s):
- LibIncentive.Incentivization(account,incentiveAmount) (contracts/beanstalk/sun/SeasonFacet/SeasonFacet.sol#118)
- incentivize(account,initialGasLeft,mode) (contracts/beanstalk/sun/SeasonFacet/SeasonFacet.sol#56)
- InternalBalanceChanged(account,token,delta) (contracts/libraries/Token/LibBalance.sol#102)
- incentivize(account,initialGasLeft,mode) (contracts/beanstalk/sun/SeasonFacet/SeasonFacet.sol#56)
/// @audit ************** Possible Issue Line(s) **************
L#51, L#54, L#56, L#116, L#118,
/// @audit ****************** Affected Code *******************
44: function gm(address account, LibTransfer.To mode) public payable returns (uint256) {
45: uint256 initialGasLeft = gasleft();
46:
47: require(!s.paused, "Season: Paused.");
48: require(seasonTime() > s.season.current, "Season: Still current Season.");
49: uint32 season = stepSeason();
50: int256 deltaB = stepOracle();
51: uint256 caseId = calcCaseIdandUpdate(deltaB);
52: LibGerminate.endTotalGermination(season, LibWhitelistedTokens.getWhitelistedTokens());
53: LibGauge.stepGauge();
54: stepSun(deltaB, caseId);
55:
56: return incentivize(account, initialGasLeft, mode);
57: }
116: LibTransfer.mintToken(C.bean(), incentiveAmount, account, mode);
118: emit LibIncentive.Incentivization(account, incentiveAmount);

GitHub : 44-57

File: contracts/beanstalk/sun/SeasonFacet/Sun.sol
/// @audit ******************* Issue Detail *******************
Reentrancy (events) in Sun.stepSun(int256,uint256) (contracts/beanstalk/sun/SeasonFacet/Sun.sol#63-76):
External calls:
- newHarvestable = rewardBeans(uint256(deltaB)) (contracts/beanstalk/sun/SeasonFacet/Sun.sol#66)
- C.bean().mint(address(this),newSupply) (contracts/beanstalk/sun/SeasonFacet/Sun.sol#86)
Event emitted after the call(s):
- Soil(s.season.current,amount.toUint128()) (contracts/beanstalk/sun/SeasonFacet/Sun.sol#229)
- setSoilAbovePeg(newHarvestable,caseId) (contracts/beanstalk/sun/SeasonFacet/Sun.sol#67)
/// @audit ************** Possible Issue Line(s) **************
L#66, L#86, L#229, L#67,
/// @audit ****************** Affected Code *******************
63: function stepSun(int256 deltaB, uint256 caseId) internal {
64: // Above peg
65: if (deltaB > 0) {
66: uint256 newHarvestable = rewardBeans(uint256(deltaB));
67: setSoilAbovePeg(newHarvestable, caseId);
68: s.season.abovePeg = true;
69: }
70:
71: // Below peg
72: else {
73: setSoil(uint256(-deltaB));
74: s.season.abovePeg = false;
75: }
76: }
86: C.bean().mint(address(this), newSupply);
229: emit Soil(s.season.current, amount.toUint128());

GitHub : 63-76

File: contracts/libraries/LibFertilizer.sol
/// @audit ******************* Issue Detail *******************
Reentrancy (events) in LibFertilizer.addFertilizer(uint128,uint256,uint256) (contracts/libraries/LibFertilizer.sol#37-63):
External calls:
- addUnderlying(fertilizerAmount.mul(DECIMALS),minLP) (contracts/libraries/LibFertilizer.sol#57)
- C.bean().mint(address(this),newDepositedBeans) (contracts/libraries/LibFertilizer.sol#103-106)
- C.bean().mint(address(C.BEAN_ETH_WELL),newDepositedLPBeans) (contracts/libraries/LibFertilizer.sol#109-112)
- newLP = IWell(C.BEAN_ETH_WELL).sync(address(this),minAmountOut) (contracts/libraries/LibFertilizer.sol#114-117)
Event emitted after the call(s):
- SetFertilizer(id,bpf) (contracts/libraries/LibFertilizer.sol#62)
/// @audit ************** Possible Issue Line(s) **************
L#57, L#103-106, L#109-112, L#114-117, L#62,
/// @audit ****************** Affected Code *******************
57: addUnderlying(fertilizerAmount.mul(DECIMALS), minLP);
62: emit SetFertilizer(id, bpf);
103: C.bean().mint(
104: address(this),
105: newDepositedBeans
106: );
109: C.bean().mint(
110: address(C.BEAN_ETH_WELL),
111: newDepositedLPBeans
112: );
114: uint256 newLP = IWell(C.BEAN_ETH_WELL).sync(
115: address(this),
116: minAmountOut
117: );

GitHub : 37-63

File: contracts/beanstalk/sun/SeasonFacet/Weather.sol
/// @audit ******************* Issue Detail *******************
Reentrancy (events) in Weather.sop() (contracts/beanstalk/sun/SeasonFacet/Weather.sol#181-213):
External calls:
- C.bean().mint(address(this),newHarvestable.add(sopBeans)) (contracts/beanstalk/sun/SeasonFacet/Weather.sol#196)
- C.bean().mint(address(this),sopBeans) (contracts/beanstalk/sun/SeasonFacet/Weather.sol#198)
- C.bean().approve(sopWell,sopBeans) (contracts/beanstalk/sun/SeasonFacet/Weather.sol#202)
- amountOut = IWell(sopWell).swapFrom(C.bean(),sopToken,sopBeans,0,address(this),type()(uint256).max) (contracts/beanstalk/sun/SeasonFacet/Weather.sol#203-210)
Event emitted after the call(s):
- SeasonOfPlenty(s.season.current,sopWell,address(sopToken),amountOut,newHarvestable) (contracts/beanstalk/sun/SeasonFacet/Weather.sol#212)
/// @audit ************** Possible Issue Line(s) **************
L#196, L#198, L#202, L#203-210, L#212,
/// @audit ****************** Affected Code *******************
196: C.bean().mint(address(this), newHarvestable.add(sopBeans));
198: C.bean().mint(address(this), sopBeans);
202: C.bean().approve(sopWell, sopBeans);
203: uint256 amountOut = IWell(sopWell).swapFrom(
204: C.bean(),
205: sopToken,
206: sopBeans,
207: 0,
208: address(this),
209: type(uint256).max
210: );
212: emit SeasonOfPlenty(s.season.current, sopWell, address(sopToken), amountOut, newHarvestable);

GitHub : 181-213

File: contracts/beanstalk/sun/SeasonFacet/SeasonFacet.sol
/// @audit ******************* Issue Detail *******************
Reentrancy (events) in SeasonFacet.incentivize(address,uint256,LibTransfer.To) (contracts/beanstalk/sun/SeasonFacet/SeasonFacet.sol#88-120):
External calls:
- LibTransfer.mintToken(C.bean(),incentiveAmount,account,mode) (contracts/beanstalk/sun/SeasonFacet/SeasonFacet.sol#116)
Event emitted after the call(s):
- LibIncentive.Incentivization(account,incentiveAmount) (contracts/beanstalk/sun/SeasonFacet/SeasonFacet.sol#118)
/// @audit ************** Possible Issue Line(s) **************
L#116, L#118,
/// @audit ****************** Affected Code *******************
116: LibTransfer.mintToken(C.bean(), incentiveAmount, account, mode);
118: emit LibIncentive.Incentivization(account, incentiveAmount);

GitHub : 88-120

File: contracts/beanstalk/silo/SiloFacet/Silo.sol
/// @audit ******************* Issue Detail *******************
Reentrancy (events) in Silo._claimPlenty(address) (contracts/beanstalk/silo/SiloFacet/Silo.sol#154-164):
External calls:
- sopToken.safeTransfer(account,plenty) (contracts/beanstalk/silo/SiloFacet/Silo.sol#160)
Event emitted after the call(s):
- ClaimPlenty(account,address(sopToken),plenty) (contracts/beanstalk/silo/SiloFacet/Silo.sol#163)
/// @audit ************** Possible Issue Line(s) **************
L#160, L#163,
/// @audit ****************** Affected Code *******************
154: function _claimPlenty(address account) internal {
155: // Plenty is earned in the form of the sop token.
156: uint256 plenty = s.a[account].sop.plenty;
157: IWell well = IWell(s.sopWell);
158: IERC20[] memory tokens = well.tokens();
159: IERC20 sopToken = tokens[0] != C.bean() ? tokens[0] : tokens[1];
160: sopToken.safeTransfer(account, plenty);
161: delete s.a[account].sop.plenty;
162:
163: emit ClaimPlenty(account, address(sopToken), plenty);
164: }

GitHub : 154-164

File: contracts/beanstalk/sun/SeasonFacet/Sun.sol
/// @audit ******************* Issue Detail *******************
Reentrancy (events) in Sun.rewardBeans(uint256) (contracts/beanstalk/sun/SeasonFacet/Sun.sol#83-104):
External calls:
- C.bean().mint(address(this),newSupply) (contracts/beanstalk/sun/SeasonFacet/Sun.sol#86)
Event emitted after the call(s):
- Reward(s.season.current,newHarvestable,newSupply,newFertilized) (contracts/beanstalk/sun/SeasonFacet/Sun.sol#103)
/// @audit ************** Possible Issue Line(s) **************
L#86, L#103,
/// @audit ****************** Affected Code *******************
83: function rewardBeans(uint256 newSupply) internal returns (uint256 newHarvestable) {
84: uint256 newFertilized;
85:
86: C.bean().mint(address(this), newSupply);
87:
88: // Distribute first to Fertilizer if some Fertilizer are active
89: if (s.season.fertilizing) {
90: newFertilized = rewardToFertilizer(newSupply);
91: newSupply = newSupply.sub(newFertilized);
92: }
93:
94: // Distribute next to the Field if some Pods are still outstanding
95: if (s.f.harvestable < s.f.pods) {
96: newHarvestable = rewardToHarvestable(newSupply);
97: newSupply = newSupply.sub(newHarvestable);
98: }
99:
100: // Distribute remainder to the Silo
101: rewardToSilo(newSupply);
102:
103: emit Reward(s.season.current, newHarvestable, newSupply, newFertilized);
104: }

GitHub : 83-104

File: contracts/beanstalk/sun/SeasonFacet/SeasonFacet.sol
/// @audit ******************* Issue Detail *******************
Reentrancy (events) in SeasonFacet.gm(address,LibTransfer.To) (contracts/beanstalk/sun/SeasonFacet/SeasonFacet.sol#44-57):
External calls:
- caseId = calcCaseIdandUpdate(deltaB) (contracts/beanstalk/sun/SeasonFacet/SeasonFacet.sol#51)
- C.bean().mint(address(this),newHarvestable.add(sopBeans)) (contracts/beanstalk/sun/SeasonFacet/Weather.sol#196)
- C.bean().mint(address(this),sopBeans) (contracts/beanstalk/sun/SeasonFacet/Weather.sol#198)
- C.bean().approve(sopWell,sopBeans) (contracts/beanstalk/sun/SeasonFacet/Weather.sol#202)
- amountOut = IWell(sopWell).swapFrom(C.bean(),sopToken,sopBeans,0,address(this),type()(uint256).max) (contracts/beanstalk/sun/SeasonFacet/Weather.sol#203-210)
- stepSun(deltaB,caseId) (contracts/beanstalk/sun/SeasonFacet/SeasonFacet.sol#54)
- C.bean().mint(address(this),newSupply) (contracts/beanstalk/sun/SeasonFacet/Sun.sol#86)
Event emitted after the call(s):
- Reward(s.season.current,newHarvestable,newSupply,newFertilized) (contracts/beanstalk/sun/SeasonFacet/Sun.sol#103)
- stepSun(deltaB,caseId) (contracts/beanstalk/sun/SeasonFacet/SeasonFacet.sol#54)
- Soil(s.season.current,amount.toUint128()) (contracts/beanstalk/sun/SeasonFacet/Sun.sol#229)
- stepSun(deltaB,caseId) (contracts/beanstalk/sun/SeasonFacet/SeasonFacet.sol#54)
/// @audit ************** Possible Issue Line(s) **************
L#51, L#54,
/// @audit ****************** Affected Code *******************
44: function gm(address account, LibTransfer.To mode) public payable returns (uint256) {
45: uint256 initialGasLeft = gasleft();
46:
47: require(!s.paused, "Season: Paused.");
48: require(seasonTime() > s.season.current, "Season: Still current Season.");
49: uint32 season = stepSeason();
50: int256 deltaB = stepOracle();
51: uint256 caseId = calcCaseIdandUpdate(deltaB);
52: LibGerminate.endTotalGermination(season, LibWhitelistedTokens.getWhitelistedTokens());
53: LibGauge.stepGauge();
54: stepSun(deltaB, caseId);
55:
56: return incentivize(account, initialGasLeft, mode);
57: }

GitHub : 44-57

Impact

Offline apps or tools will not able to check and report latest correct state of the protocol due to out of order events.

Tools Used

Manual Review

Recommendations

Ensure that events follow the best practice of check-effects-interaction, and are emitted before external calls

Updates

Lead Judging Commences

giovannidisiena Lead Judge over 1 year ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
Assigned finding tags:

Informational/Invalid

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.