Platform: Code4rena
Start Date: 10/05/2022
Pot Size: $50,000 USDC
Total HM: 13
Participants: 100
Period: 5 days
Judge: HardlyDifficult
Total Solo HM: 1
Id: 122
League: ETH
Rank: 42/100
Findings: 1
Award: $89.40
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: IllIllI
Also found by: 0v3rf10w, 0x1f8b, 0x4non, 0xDjango, 0xNazgul, 0xf15ers, 0xkatana, 0xsanson, Bludya, BowTiedWardens, CertoraInc, Cityscape, DavidGialdi, FSchmoede, Fitraldys, Funen, Hawkeye, Kenshin, MadWookie, MaratCerby, MiloTruck, Picodes, RagePit, Tadashi, TerrierLover, TomFrenchBlockchain, VAD37, WatchPug, Waze, _Adam, antonttc, bobirichman, catchup, defsec, delfin454000, djxploit, ellahi, fatherOfBlocks, gzeon, hake, hansfriese, hickuphh3, horsefacts, ignacio, joestakey, jonatascm, mics, minhquanym, oyc_109, pmerkleplant, rfa, robee, rotcivegaf, samruna, shung, sikorico, simon135, z3s
89.4006 USDC - $89.40
discord Code4rena, Cally-may10 channel
Cally.sol: Use uint128 in Vault struct to save:
struct Vault { uint256 tokenIdOrAmount; address token; uint8 premiumIndex; uint8 durationDays; uint8 dutchAuctionStartingStrikeIndex; uint32 currentExpiration; bool isExercised; bool isWithdrawing; TokenType tokenType; uint128 currentStrike; // 16 bytes uint128 dutchAuctionReserveStrike; // 16 bytes }
The dutchAuctionReserveStrike
and currentStrike
should be lower than all elements of strikeOptions
array and the highest element its 6765 ether
, this enters in a uint80 and we have a uint128
currentStrike
look in getDutchAuctionStrike
functionSaves the gas(2209 according to my tests) of storage a bytes32 every time how creates a Vault
CallyNft.sol: For premiumOptions
and strikeOptions
use static storage array of uint256 and assign the values in the constructor
... contract Cally is CallyNft, ReentrancyGuard, Ownable { ... uint256[] public premiumOptions; uint256[] public strikeOptions; constructor () { premiumOptions[0] = 0.01 ether; premiumOptions[1] = 0.025 ether; premiumOptions[2] = 0.05 ether; premiumOptions[3] = 0.075 ether; premiumOptions[4] = 0.1 ether; premiumOptions[5] = 0.25 ether; premiumOptions[6] = 0.5 ether; premiumOptions[7] = 0.75 ether; premiumOptions[8] = 1.0 ether; premiumOptions[9] = 2.5 ether; premiumOptions[10] = 5.0 ether; premiumOptions[11] = 7.5 ether; premiumOptions[12] = 10 ether; premiumOptions[13] = 25 ether; premiumOptions[14] = 50 ether; premiumOptions[15] = 75 ether; premiumOptions[16] = 100 ether; strikeOptions[0] = 1 ether; strikeOptions[1] = 2 ether; strikeOptions[2] = 3 ether; strikeOptions[3] = 5 ether; strikeOptions[4] = 8 ether; strikeOptions[5] = 13 ether; strikeOptions[6] = 21 ether; strikeOptions[7] = 34 ether; strikeOptions[8] = 55 ether; strikeOptions[9] = 89 ether; strikeOptions[10] = 144 ether; strikeOptions[11] = 233 ether; strikeOptions[12] = 377 ether; strikeOptions[13] = 610 ether; strikeOptions[14] = 987 ether; strikeOptions[15] = 1597 ether; strikeOptions[16] = 2584 ether; strikeOptions[17] = 4181 ether; strikeOptions[18] = 6765 ether; } ...
This saves gas(55195 according to my tests) in the deploy of the contract Also saves 2100 gas for each .length consult and 2203 gas for each consult to the array
In solidity all variables initialize in 0, address(0), false, etc.
Cally.sol: Remove initialize in the uint256 public feeRate
and uint256 public protocolUnclaimedFees
variables
This save gas(2258 according to my tests) for each initialize in the deploy of the contract
CallyNft.sol:
Cally
contract call this functions and allways use msg.sender
as tovaultIndex
var in the Cally
contract, and vaultIndex
is only changed on the createVault
functionownerOf()
to _ownerOf
CallyNft.sol: In the lines 214, 263, 307, 323, 354 use directly _ownerOf(vaultId)
, ownerOf
function add an unnecessary require
Also in L382 because if the vaultId not exists the currentBeneficiary will be the address(0)
CallyNft.sol:
vaultIndex += 2;
vault.currentStrike = getDutchAuctionStrike( strikeOptions[vault.dutchAuctionStartingStrikeIndex], vault.currentExpiration + AUCTION_DURATION, vault.dutchAuctionReserveStrike );
vault.currentExpiration = uint32(block.timestamp) + (vault.durationDays * 1 days);
optionId = vaultId + 1;
ethBalance[beneficiary] += msg.value;
if (feeRate > 0) { fee = (msg.value * feeRate) / 1e18; protocolUnclaimedFees += fee; }
ethBalance[getVaultBeneficiary(vaultId)] += msg.value - fee;
getDutchAuctionStrike
functionunchecked { <LINE/BLOCK> }
These calculations cannot overflow
function harvest() public returns (uint256 amount) { amount = ethBalance[msg.sender]; if (amount > 0) { // reset premiums ethBalance[msg.sender] = 0; emit Harvested(msg.sender, amount); // transfer premiums to owner payable(msg.sender).safeTransferETH(amount); } }
Cally.sol, L170: require(durationDays > 0, "durationDays too small");
to require(durationDays != 0, "durationDays too small");
This save gas(6 according to my tests) for each require
#0 - outdoteth
2022-05-16T20:16:04Z
high quality report