Moonwell - RED-LOTUS-REACH's results

An open lending and borrowing DeFi protocol.

General Information

Platform: Code4rena

Start Date: 24/07/2023

Pot Size: $100,000 USDC

Total HM: 18

Participants: 73

Period: 7 days

Judge: alcueca

Total Solo HM: 8

Id: 267

League: ETH

Moonwell

Findings Distribution

Researcher Performance

Rank: 42/73

Findings: 1

Award: $86.74

🌟 Selected for report: 0

🚀 Solo Findings: 0

Findings Information

🌟 Selected for report: hals

Also found by: 0x70C9, 0xComfyCat, 0xl51, Kaysoft, RED-LOTUS-REACH, T1MOH, Tendency, Vagner, bin2chen, immeas, kodyvim, sces60107

Labels

bug
2 (Med Risk)
satisfactory
duplicate-268

Awards

86.7417 USDC - $86.74

External Links

Lines of code

https://github.com/code-423n4/2023-07-moonwell/blob/main/src/core/Governance/TemporalGovernor.sol#L237

Vulnerability details

Impact

Summary

TemporalGovernor.sol is missing the ability to transfer any native token while executing proposals.
In the original Compound sources, there is the payable specifier on both the governance and timelock contracts to allow for native tokens to be sent with calls to execute() [1][2].

As a result, if a governance proposal requires native tokens to be transferred while executing proposals this will not be possible, rendering necessary functionality of an effective governance system unavailable. There could be significant financial impact on the protocol if native tokens cannot be transferred within execution of crucial proposals.

Please see (https://www.comp.xyz/t/enable-transfer-eth-from-timelock/2689) for an example of a Compound proposal requiring native token trasnfer.

For example, Compound:

// Compound, GovernorAlpha.sol, line 193 function execute(uint proposalId) public payable { // ...payable... timelock.executeTransaction{value: proposal.values[i]}(...) // ... } // Compound Timelock.sol, line 81 function executeTransaction(...) public payable returns (bytes memory) { //...payable... (bool success, bytes memory returnData) = target.call{value: value}(callData); //... }

In contrast, TemporalGovernor.sol:

// line 237, no payable function executeProposal(bytes memory VAA) public whenNotPaused { _executeProposal(VAA, false); }

The TemporalGovernor.sol also lacks a receive or fallback function to possibly send actual native token for proposals to be executed.

Links:

Proof of Concept

pragma solidity 0.8.17; import "forge-std/Test.sol"; import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol"; import {MockWormholeCore} from "@test/mock/MockWormholeCore.sol"; import {ITemporalGovernor, TemporalGovernor} from "@protocol/core/Governance/TemporalGovernor.sol"; contract TemporalGovernorNoValue is Test { TemporalGovernor governor; MockWormholeCore mockCore; address public wormholeCore; uint16 chainId = 42; function setUp() public { mockCore = new MockWormholeCore(); wormholeCore = address(mockCore); TemporalGovernor.TrustedSender[] memory trustedSenders = new TemporalGovernor.TrustedSender[](1); trustedSenders[0] = ITemporalGovernor.TrustedSender({ chainId: chainId, addr: address(this) }); governor = new TemporalGovernor(wormholeCore, 0 days, 0 days, trustedSenders); ///////////////////////////////////// // Build the payload, set up Wormhole ///////////////////////////////////// address[] memory targets = new address[](1); targets[0] = address(0x0); uint256[] memory values = new uint256[](1); values[0] = 0; // no values to send bytes[] memory payloads = new bytes[](1); payloads[0] = abi.encodeWithSignature( "_setPriceOracle(address)", address(0x0) ); bytes memory payload = abi.encode( address(governor), // intended recipient targets, values, payloads ); mockCore.setStorage( true, // valid chainId, // _emitterChainId governor.addressToBytes(address(this)), // _emitterAddress "UNUSED", // reason payload // payload ); } function test_fallbackOrReceieve() public { governor.queueProposal(""); vm.expectRevert(); address(governor).call{value: 1 ether}(""); } function test_payable() public { // THIS WILL NOT COMPILE // uncomment to see // governor.executeProposal{value: 1 ether}(""); } }

Tools Used

Manual Review Foundry

Add a receive or fallback function to the TemporalGovernor.sol contract or make the execute function payable.

Assessed type

Other

#0 - c4-pre-sort

2023-08-03T13:21:43Z

0xSorryNotSorry marked the issue as duplicate of #268

#1 - c4-judge

2023-08-12T20:37:44Z

alcueca marked the issue as satisfactory

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax © 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter