Platform: Code4rena
Start Date: 16/09/2021
Pot Size: $50,000 USDC
Total HM: 26
Participants: 30
Period: 7 days
Judge: GalloDaSballo
Total Solo HM: 17
Id: 36
League: ETH
Rank: 21/30
Findings: 3
Award: $359.37
๐ Selected for report: 2
๐ Solo Findings: 0
270.5216 USDC - $270.52
bw
Bounty is read into memory and then modified, which does not result in the modification being written to storage.
https://github.com/code-423n4/2021-09-defiProtocol/blob/main/contracts/contracts/Auction.sol#L143
--- a/contracts/contracts/Auction.sol +++ b/contracts/contracts/Auction.sol @@ -24,7 +24,7 @@ contract Auction is IAuction { IFactory public override factory; address public override auctionBonder; - Bounty[] private _bounties; + Bounty[] public _bounties; modifier onlyBasket() { require(msg.sender == address(basket), 'not basket'); diff --git a/contracts/test/Auction.test.js b/contracts/test/Auction.test.js index 5377bbc..9cbb126 100644 --- a/contracts/test/Auction.test.js +++ b/contracts/test/Auction.test.js @@ -142,7 +142,8 @@ describe("Auction", function () { await UNI.approve(auction.address, `100000000000000000000`); await COMP.approve(auction.address, `100000000000000000000`); await AAVE.approve(auction.address, `100000000000000000000`); - - await expect(auction.settleAuction([], [COMP.address], ["2999400000000000000"], [UNI.address, AAVE.address], ["200720000000000000", "200120000000000000"])).to.be.ok; + await auction.addBounty(UNI.address, `100000000000000000000`); + await expect(auction.settleAuction([0], [COMP.address], ["2999400000000000000"], [UNI.address, AAVE.address], ["200720000000000000", "200120000000000000"])).to.be.ok; + console.log(`bounty.active = ${await auction._bounties(0)}`); }); });
bounty = 0x0E801D84Fa97b50751Dbf25036d067dCf18858bF,100000000000000000000,true
Should have returned false
.
N/A
The memory
keyword should be replaced with storage
in order for bounty.active = false;
to be persisted.
diff --git a/contracts/contracts/Auction.sol b/contracts/contracts/Auction.sol index f07df8b..0ec5efe 100644 --- a/contracts/contracts/Auction.sol +++ b/contracts/contracts/Auction.sol @@ -140,7 +140,7 @@ contract Auction is IAuction { function withdrawBounty(uint256[] memory bountyIds) internal { // withdraw bounties for (uint256 i = 0; i < bountyIds.length; i++) { - Bounty memory bounty = _bounties[bountyIds[i]]; + Bounty storage bounty = _bounties[bountyIds[i]]; require(bounty.active); IERC20(bounty.token).transfer(msg.sender, bounty.amount);
#0 - frank-beard
2021-10-19T17:49:13Z
#1 - GalloDaSballo
2021-12-20T01:03:00Z
Finding is valid, in lack of any POC nor explanation for possible implications with the finding, I believe low severity to be correct
#2 - GalloDaSballo
2021-12-21T22:31:54Z
After re-reviewing, I've increased severity of a similar finding, and since this is a duplicate of it, am increasing the severity of this to medium as well.
Duplicate of #168
15.5766 USDC - $15.58
bw
The Factory.sol
contract made use of a number of public
variables that were set only in the constructor and would remain constant. These variables were consuming storage slots, which unnecessarily increased the deployment and runtime gas costs of the contract.
For more information regarding the immutable
keyword:
https://blog.soliditylang.org/2020/05/13/immutable-keyword/
diff --git a/contracts/contracts/Factory.sol b/contracts/contracts/Factory.sol index 271945d..3bbdd4f 100644 --- a/contracts/contracts/Factory.sol +++ b/contracts/contracts/Factory.sol @@ -23,8 +23,8 @@ contract Factory is IFactory, Ownable { Proposal[] private _proposals; - IAuction public override auctionImpl; - IBasket public override basketImpl; + IAuction public immutable override auctionImpl; + IBasket public immutable override basketImpl; uint256 public override minLicenseFee = 1e15; // 1e15 0.1% uint256 public override auctionDecrement = 10000;
diff --git a/base.gas b/factory-immutable.gas index 9d48ade..1447433 100644 --- a/base.gas +++ b/factory-immutable.gas @@ -23,9 +23,9 @@ ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท | ERC20Upgradeable ยท approve ยท - ยท - ยท 48900 ยท 3 ยท - โ ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท -| Factory ยท createBasket ยท 880031 ยท 908831 ยท 882911 ยท 10 ยท - โ +| Factory ยท createBasket ยท 875780 ยท 904580 ยท 878660 ยท 10 ยท - โ ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท -| Factory ยท proposeBasketLicense ยท 335488 ยท 335512 ยท 335505 ยท 12 ยท - โ +| Factory ยท proposeBasketLicense ยท 333388 ยท 333412 ยท 333405 ยท 12 ยท - โ ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท | Factory ยท setOwnerSplit ยท - ยท - ยท 46173 ยท 1 ยท - โ ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท @@ -39,7 +39,7 @@ ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท | Basket ยท - ยท - ยท 2390793 ยท 8 % ยท - โ ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท -| Factory ยท - ยท - ยท 1706801 ยท 5.7 % ยท - โ +| Factory ยท - ยท - ยท 1684215 ยท 5.6 % ยท - โ ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท | TestToken ยท 653145 ยท 653193 ยท 653163 ยท 2.2 % ยท - โ ยท---------------------------------------------|-------------|-------------|-----------|---------------|-------------ยท
By removing the public
keyword from all variables that are not required (which are only used in the unit tests), the deployment costs can be further reduced.
https://www.npmjs.com/package/hardhat-gas-reporter
Add the immutable key word to all variables that are only set during the constructor.
#0 - GalloDaSballo
2021-11-29T13:56:33Z
Finding is valid, great poc with details
15.5766 USDC - $15.58
bw
The handeFees()
function in Basket.sol
wastes gas if the function is triggered more than once per block. This is due to the timeDiff
being zero on subsequently calls and all resulting calculations subsequently also resulting in zero.
index 5fef21b..24e80e6 100644 --- a/contracts/contracts/Basket.sol +++ b/contracts/contracts/Basket.sol @@ -114,6 +114,7 @@ contract Basket is IBasket, ERC20Upgradeable { uint256 startSupply = totalSupply(); uint256 timeDiff = (block.timestamp - lastFee); + if (timeDiff == 0) return; uint256 feePct = timeDiff * licenseFee / ONE_YEAR; uint256 fee = startSupply * feePct / (BASE - feePct);
https://www.npmjs.com/package/hardhat-gas-reporter
Return early if handleFees
has already been called in the current block, prevent unnecessary calls to _mint and rewriting storage slots with the same value.
#0 - GalloDaSballo
2021-11-28T17:24:51Z
Duplicate of #53
๐ Selected for report: bw
57.691 USDC - $57.69
bw
A require statement in Factory.sol
could be performed prior to an expensive cross contract call, reducing the amount of gas wasted if the validation fails.
https://github.com/code-423n4/2021-09-defiProtocol/blob/main/contracts/contracts/Factory.sol#L74
N/A
Move the require statement before basketImpl.validateWeights(tokens, weights);
#0 - GalloDaSballo
2021-11-29T13:54:47Z
Agree with the finding, putting the require first saves gas in the worst case and has no impact in the best case