Platform: Code4rena
Start Date: 14/06/2022
Pot Size: $100,000 USDC
Total HM: 26
Participants: 59
Period: 7 days
Judge: GalloDaSballo
Total Solo HM: 9
Id: 133
League: ETH
Rank: 4/59
Findings: 12
Award: $5,261.39
🌟 Selected for report: 3
🚀 Solo Findings: 0
9086.4148 CANTO - $1,467.46
1467.456 USDC - $1,467.46
It's not possible to initialize the accountant because of a mistake in the function's require statement.
I rate it as MED since a key part of the protocol wouldn't be available until the contract is modified and redeployed.
The issue is the following require()
statement: https://github.com/Plex-Engineer/lending-market/blob/main/contracts/Accountant/AccountantDelegate.sol#L29
There, the function checks whether the accountant has received the correct amount of tokens. But, it compares the accountant's balance with the _initialSupply
. That value is always 0. So the require statement will always fail
When the Note contract is initialized, _initialSupply
is set to 0:
After _mint_to_Accountant()
mints type(uint).max
tokens to the accountant: https://github.com/Plex-Engineer/lending-market/blob/main/contracts/Note.sol#L18
That increases the totalSupply
but not the _initialSupply
: https://github.com/Plex-Engineer/lending-market/blob/main/contracts/ERC20.sol#L242
The _initialSupply
value is only modified by the ERC20 contract's constructor.
none
Change the require statement to
require(note.balanceOf(msg.sender) == note.totalSupply(), "AccountantDelegate::initiatlize: Accountant has not received payment");
#0 - GalloDaSballo
2022-08-07T23:00:27Z
The warden has shown how, due to an incorrect assumption, AccountantDelegate.initialize
cannot work, meaning part of the protocol will never work without fixing this issue.
While the change should be fairly trivial, the impact is pretty high, for those reasons am going to raise severity to High
🌟 Selected for report: Soosh
Also found by: 0x1f8b, Ruhum, TerrierLover, WatchPug, cccz, csanuragjain, hake, p4st13r4, zzzitron
782.2807 CANTO - $126.34
126.3383 USDC - $126.34
https://github.com/Plex-Engineer/manifest/blob/main/contracts/Proposal-Store.sol#L46-L50
The ProposalStore contract's AddProposal()
function is callable by anyone and allows the caller to overwrite an existing proposal.
This can be abused to block proposals from being queued and executed properly.
The governance process goes through three steps:
ProposalStore.AddProposal()
GovernorBravoDelegate.queue()
GovernorBravoDelegate.execute()
The attacker is able to overwrite existing proposals in the ProposalStore contract. They simply call AddProposal()
with propId
being the proposal they want to overwrite. The function doesn't check whether a proposal with that ID already exists or not. It simply overwrites it in the proposals
map.
So the attacker simply watches the mempool for any transaction where GovernorBravoDelegate.queue()
is executed and front runs it with a transaction where that specific proposal is modified. The user then queues a malicious proposal which will be canceled before the execution delay is over.
The proposer is able to bypass this issue by creating and queuing a proposal within the same transaction. Or they submit both transactions to a miner directly instead of going through the public mempool. Because of that, I'd rate it as a MED issue.
none
Don't allow existing proposals from being overwritten.
#0 - nivasan1
2022-06-23T02:23:14Z
duplicate of #26
🌟 Selected for report: p4st13r4
Also found by: Ruhum, TerrierLover, WatchPug, hansfriese, zzzitron
320.9326 USDC - $320.93
1987.1989 CANTO - $320.93
Judge has assessed an item in Issue #54 as High risk. The relevant finding follows:
#0 - GalloDaSballo
2022-08-13T00:07:18Z
02: WETH.totalSupply() provides the incorrect value The WETH contract returns its own token balance instead of the total supply of tokens in circulation.
Instead of _balanceOf[address(this)]; it should be this.balance.
Since the function isn't used anywhere it's a spec issue. So I rate it as LOW. Could cause issues in the future if someone depends on the total supply.
#1 - GalloDaSballo
2022-08-13T00:07:31Z
Dup of #191
1987.1989 CANTO - $320.93
320.9326 USDC - $320.93
The Comptroller contract uses a hardcoded address for the WETH contract which is not the correct one. Because of that, it will be impossible to claim COMP rewards. That results in a loss of funds so I rate it as HIGH.
The Comptroller's getWETHAddress()
function: https://github.com/Plex-Engineer/lending-market/blob/755424c1f9ab3f9f0408443e6606f94e4f08a990/contracts/Comptroller.sol#L1469
It's a left-over from the original compound repo: https://github.com/compound-finance/compound-protocol/blob/master/contracts/Comptroller.sol#L1469
It's used by the grantCompInternal()
function: https://github.com/Plex-Engineer/lending-market/blob/755424c1f9ab3f9f0408443e6606f94e4f08a990/contracts/Comptroller.sol#L1377
That function is called by claimComp()
: https://github.com/Plex-Engineer/lending-market/blob/755424c1f9ab3f9f0408443e6606f94e4f08a990/contracts/Comptroller.sol#L1365
If there is a contract stored in that address and it doesn't adhere to the interface (doesn't have a balanceOf()
and transfer()
function), the transaction will revert. If there is no contract, the call will succeed without having any effect. In both cases, the user doesn't get their COMP rewards.
none
The WETH contract's address should be parsed to the Comptroller through the constructor or another function instead of being hardcoded.
#0 - GalloDaSballo
2022-08-10T22:37:27Z
The warden has shown how the address for WETH / comp is hardcoded and the address is pointing to Mainnet's COMP.
This misconfiguration will guarantee that any function calling grantCompInternal
as well as claimComp
will revert.
Because the functionality is hampered, I agree with High Severity
247.5766 USDC - $247.58
1532.982 CANTO - $247.58
https://github.com/Plex-Engineer/lending-market/blob/main/contracts/Governance/GovernorBravoDelegate.sol#L63 https://github.com/Plex-Engineer/lending-market/blob/main/contracts/Governance/GovernorBravoDelegate.sol#L87
It's not possible to execute a proposal through the GovernorBravoDelegate contract because the executed
property of it is set to true
when it's queued up.
Since this means that the governance contract is unusable, it might result in locked-up funds if those were transferred to the contract before the issue comes up. Because of that I'd rate it as HIGH.
executed
is set to true
: https://github.com/Plex-Engineer/lending-market/blob/main/contracts/Governance/GovernorBravoDelegate.sol#L63
Here, the execute()
function checks whether the proposal's state is Queued
: https://github.com/Plex-Engineer/lending-market/blob/main/contracts/Governance/GovernorBravoDelegate.sol#L87
But, since the execute
property is true
, the state()
function will return Executed
: https://github.com/Plex-Engineer/lending-market/blob/main/contracts/Governance/GovernorBravoDelegate.sol#L117
In the original compound repo, executed
is false
when the proposal is queued up: https://github.com/compound-finance/compound-protocol/blob/master/contracts/Governance/GovernorBravoDelegate.sol#L111
none
Just delete the line where executed
is set to true
. Since the zero-value is false
anyway, you'll save gas as well.
#0 - GalloDaSballo
2022-08-10T23:43:23Z
The warden has shown how, due to a coding decision, no transaction can be executed from the Governor Contract.
Because the functionality is broken, I agree with High Severity
🌟 Selected for report: joestakey
Also found by: 0x1f8b, 0x29A, 0x52, 0xDjango, 0xNazgul, 0xf15ers, 0xmint, Bronicle, Dravee, Funen, JMukesh, Limbooo, MadWookie, Picodes, Ruhum, TerrierLover, TomJ, Tutturu, WatchPug, Waze, _Adam, asutorufos, c3phas, catchup, cccz, codexploder, cryptphi, csanuragjain, defsec, fatherOfBlocks, gzeon, hake, hansfriese, hyh, ignacio, k, nxrblsrpr, oyc_109, robee, sach1r0, saian, simon135, technicallyty, zzzitron
79.9481 USDC - $79.95
687.9945 CANTO - $111.11
uint
is >= 0
is unnecessary since it's always trueWETH.totalSupply()
provides the incorrect valueNote._mint_to_accountant()
uint
is >= 0
is unnecessary since it's always trueRelevant code:
WETH.totalSupply()
provides the incorrect valueThe WETH contract returns its own token balance instead of the total supply of tokens in circulation.
Instead of _balanceOf[address(this)];
it should be this.balance
.
Since the function isn't used anywhere it's a spec issue. So I rate it as LOW. Could cause issues in the future if someone depends on the total supply.
Note._mint_to_accountant()
By calling the _mint_to_accountant()
function first, they mint the tokens to themselve and set their address as both the accountant and admin. The contract would have to be redeployed.
Relevant code:
#0 - GalloDaSballo
2022-08-03T23:30:24Z
Valid Refactoring
Bumped up to High
Valid L
1L 2R
🌟 Selected for report: _Adam
Also found by: 0v3rf10w, 0x1f8b, 0x29A, 0xKitsune, 0xNazgul, 0xf15ers, 0xkatana, 0xmint, Chom, Dravee, Fitraldys, Funen, JC, Limbooo, MadWookie, Picodes, Ruhum, TerrierLover, TomJ, Tomio, Waze, ak1, c3phas, catchup, defsec, fatherOfBlocks, gzeon, hake, hansfriese, joestakey, k, oyc_109, rfa, robee, sach1r0, saian, simon135, ynnad
39.7504 USDC - $39.75
396.9199 CANTO - $64.10
The struct has the property's zero-value by default. Assigning it explicitly is just wasting gas.
Relevant code:
Solidity comes with built-in safe math after v0.8.0. Having your own functions is just a waste of gas since it will check for overflows twice.
Relevant code:
Since under- & overflow protection is built-in since Solidity v0.8.0 it's unnecessary to check for that. It's a waste of gas.
Relevant code:
There are probably a lot more places where this is relevant. Those are just some that caught my eye.
#0 - GalloDaSballo
2022-08-04T00:38:29Z
Less than 200 gas