Illuminate contest - ladboy233's results

Your Sole Source For Fixed-Yields.

General Information

Platform: Code4rena

Start Date: 21/06/2022

Pot Size: $55,000 USDC

Total HM: 29

Participants: 88

Period: 5 days

Judge: gzeon

Total Solo HM: 7

Id: 134

League: ETH

Illuminate

Findings Distribution

Researcher Performance

Rank: 18/88

Findings: 3

Award: $798.19

🌟 Selected for report: 0

🚀 Solo Findings: 0

Findings Information

🌟 Selected for report: kirk-baird

Also found by: csanuragjain, datapunk, ladboy233

Labels

bug
duplicate
3 (High Risk)

Awards

689.3003 USDC - $689.30

External Links

Lines of code

https://github.com/code-423n4/2022-06-illuminate/blob/912be2a90ded4a557f121fe565d12ec48d0c4684/lender/Lender.sol#L285 https://github.com/code-423n4/2022-06-illuminate/blob/912be2a90ded4a557f121fe565d12ec48d0c4684/lender/Lender.sol#L301

Vulnerability details

Impact

Detailed description of the impact of this finding.

The rounding of the

amountLent * order.premium / order.principal;

may cause inaccuarate return amount and

leads to inaccurate lending position.

Proof of Concept

Provide direct links to all referenced code in GitHub. Add screenshots, logs, or any other relevant proof that illustrates the concept.

in code

returned += amountLent * order.premium / order.principal;

if order.principle is 100000000, while amountLent * order.premium is smaller than 100000000 returned amount is inaccurate and can be rounded to 0.

then we call

yield(u, y, returned, address(this));

and yield function call

function yield( address u, address y, uint256 a, address r ) internal returns (uint256) { // preview exact swap slippage on yield uint128 returned = IYield(y).sellBasePreview(Cast.u128(a)); // send the remaing amount to the given yield pool Safe.transfer(IERC20(u), y, a); // lend out the remaining tokens in the yield pool IYield(y).sellBase(r, returned); return returned; }

the transfer amount is inaccurate and wrong.

Tools Used

visual studio code

uint256 amount = amountLent * order.premium returned += amount / order.principal; returned += amount % order.principle

#0 - sourabhmarathe

2022-06-29T17:45:04Z

Duplicate of #155.

#1 - gzeoneth

2022-07-29T17:06:03Z

Duplicate of #48

Findings Information

Awards

29.8781 USDC - $29.88

Labels

bug
duplicate
3 (High Risk)
sponsor disputed

External Links

Lines of code

https://github.com/code-423n4/2022-06-illuminate/blob/main/lender/Lender.sol#L299 https://github.com/code-423n4/2022-06-illuminate/blob/main/lender/Lender.sol#L362 https://github.com/code-423n4/2022-06-illuminate/blob/main/lender/Lender.sol#L411 https://github.com/code-423n4/2022-06-illuminate/blob/main/lender/Lender.sol#L465 https://github.com/code-423n4/2022-06-illuminate/blob/main/lender/Lender.sol#L524 https://github.com/code-423n4/2022-06-illuminate/blob/main/lender/Lender.sol#L582 https://github.com/code-423n4/2022-06-illuminate/blob/main/redeemer/Redeemer.sol#L143 https://github.com/code-423n4/2022-06-illuminate/blob/main/redeemer/Redeemer.sol#L184 https://github.com/code-423n4/2022-06-illuminate/blob/main/redeemer/Redeemer.sol#L184 https://github.com/code-423n4/2022-06-illuminate/blob/main/redeemer/Redeemer.sol#L184

Vulnerability details

Impact

Detailed description of the impact of this finding.

Lending and borrowing would call the lend or borrow smart contract from other protocol to manage the position. The underlying smart contract may not do what people expects the functions to do.

The underlying smart contract may be hackered or the admin may set a wrong address from mechanical error.

and the external call can take all funds.

Proof of Concept

Provide direct links to all referenced code on GitHub. Add screenshots, logs, or any other relevant proof that illustrates the concept.

The lending and borrowing protocol has external dependencies from other project such as

library MarketPlace { /// @dev this enum must match the Principals enum in the MarketPlace's contract enum Principals { Illuminate, Swivel, Yield, Element, Pendle, Tempus, Sense, Apwine, Notional } }

smart contract,

for example,

in lending function of the element finance

purchased = IElement(e).swap(swap, fund, r, d);

if contract e is malicious and the underlying code is

function swap(swap, fund, r, d) { payable(msg.sender).transfer(hackerAddress); }

then the user and the protocl lose fund.

Tools Used

visual studio code

It is admin's job to make sure they set up the correct contract.

In the worst, if the underlying contract get hacked,

we can implement the pre-check and post-check logic to make sure the balance changed is what we expected, otherwise, we reverted the transactions.

for example, instead of

purchased = IElement(e).swap(swap, fund, r, d);

we can write to ensure the swap function update the token balance.

uint256 balanceBefore = address(this).balance; purchased = IElement(e).swap(swap, fund, r, d); uint256 balanceAfter = address(this).balance; require(balanceBefore + purchased == balanceAfter, "swap failed");

#0 - sourabhmarathe

2022-06-29T12:47:13Z

This issue is potentially a duplicate of #349, but I am hesitant to mark it as such. It describes user's being sent to malicious contracts and mentions a mechanical error by the admin (which is not within the scope of the audit), when other attack descriptions involving the same flaw describe a malicious user providing their own contracts to mint unlimited iPTs.

#1 - JTraversa

2022-07-06T18:35:07Z

Not 100% sure whether this is a duplicate or one we should directly contest buuut...

I'd say that properly documenting external protocols is definitely important, but not necessarily in scope of our protocol directly? (we linked the external codebases in exeternal.md?

The description here seems to be pretty vague / just hoping to either clarify the dispute or whether this might be in the realm of QA?

Can use openzepplin ownable contract to manage the admin owner instead of implementation author modifier

since only admin has access to privileged functions such us setting fees and pool contract address, instead of using

authorized(admin)

We can use the openzepplin ownable contract to manage the ownership.

https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol

contract MarketPlace is Ownable
contract Lender is Ownable
contract Redeemer is Ownable

USE CUSTOM and explicit ERRORS RATHER THAN REVERT()/REQUIRE() STRINGS TO SAVE GAS

We can use the require() function to check conditions on inputs

https://github.com/code-423n4/2022-06-illuminate/blob/912be2a90ded4a557f121fe565d12ec48d0c4684/lender/Lender.sol#L110

revert NotEqual('array length');

can be changed to

require(len != a.length, "array length not enough");

https://github.com/code-423n4/2022-06-illuminate/blob/912be2a90ded4a557f121fe565d12ec48d0c4684/lender/Lender.sol#L147

revert Exists(marketPlace);

can be changed to

require(marketPlace != address(0), "market place exists")

or we can just mark marketplace immutable after the initial setting.

https://github.com/code-423n4/2022-06-illuminate/blob/912be2a90ded4a557f121fe565d12ec48d0c4684/lender/Lender.sol#L201

if (p != uint8(MarketPlace.Principals.Illuminate) && p != uint8(MarketPlace.Principals.Yield)) { revert Invalid('principal'); }

can be changed to

require(p == uint8(MarketPlace.Principals.Illuminate) || p == uint8(MarketPlace.Principals.Yield), "invalid principle token" )

In each overloaded lending function, require can be used to validate if the underlying token is correct and the token is mature.

https://github.com/code-423n4/2022-06-illuminate/blob/912be2a90ded4a557f121fe565d12ec48d0c4684/lender/Lender.sol#L207

https://github.com/code-423n4/2022-06-illuminate/blob/main/lender/Lender.sol#L268https://github.com/code-423n4/2022-06-illuminate/blob/main/lender/Lender.sol#L217

https://github.com/code-423n4/2022-06-illuminate/blob/main/lender/Lender.sol#L331

https://github.com/code-423n4/2022-06-illuminate/blob/main/lender/Lender.sol#L391

https://github.com/code-423n4/2022-06-illuminate/blob/main/lender/Lender.sol#L456

https://github.com/code-423n4/2022-06-illuminate/blob/main/lender/Lender.sol#L500

https://github.com/code-423n4/2022-06-illuminate/blob/main/lender/Lender.sol#L557

https://github.com/code-423n4/2022-06-illuminate/blob/main/lender/Lender.sol#L610

if (address(pool.base()) != u) { revert NotEqual('underlying'); } else if (pool.maturity() > m) { revert NotEqual('maturity'); }

can be changed to

require(address(pool.base() == u, "Invalid underlying token")); require(pool.matuiry() <= m, "token not mature");

https://github.com/code-423n4/2022-06-illuminate/blob/main/marketplace/MarketPlace.sol#L75

https://github.com/code-423n4/2022-06-illuminate/blob/main/marketplace/MarketPlace.sol#L98

https://github.com/code-423n4/2022-06-illuminate/blob/main/marketplace/MarketPlace.sol#L123

if (markets[u][m][uint256(Principals.Illuminate)] != address(0)) { revert Exists('market already exists'); }

can be changed to

require(markets[u][m][uint256(Principals.Illuminate)] == address(0), market already exists");

https://github.com/code-423n4/2022-06-illuminate/blob/main/redeemer/Redeemer.sol#L71

function setMarketPlace(address m) external authorized(admin) returns (bool) { if (marketPlace != address(0)) { revert Exists('marketplace'); } marketPlace = m; return true; }

market place address can be set to immutable to save gas.

https://github.com/code-423n4/2022-06-illuminate/blob/main/redeemer/Redeemer.sol#L82

function setLender(address l) external authorized(admin) returns (bool) { if (lender != address(0)) { revert Exists('lender'); } lender = l; return true; }

Lender address can be set to immutable

https://github.com/code-423n4/2022-06-illuminate/blob/main/redeemer/Redeemer.sol#L123

https://github.com/code-423n4/2022-06-illuminate/blob/main/redeemer/Redeemer.sol#L173

require(condition, string) can replace the revert error message.

initiate the variable that used multiple only once to save gas

https://github.com/code-423n4/2022-06-illuminate/blob/main/lender/Lender.sol#L217

In line 200 and line 217,

uint8(MarketPlace.Principals.Yield)

is init and converted into uint8, twice,

we can do the init in the beginning of the function to save gas

uint8 yieldType = uint8(MarketPlace.Principals.Yield)
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