Golom contest - gogo's results

An NFT marketplace that offers the lowest industry fee, a publicly available order-book along with analytical tools.

General Information

Platform: Code4rena

Start Date: 26/07/2022

Pot Size: $75,000 USDC

Total HM: 29

Participants: 179

Period: 6 days

Judge: LSDan

Total Solo HM: 6

Id: 148

League: ETH

Golom

Findings Distribution

Researcher Performance

Rank: 88/179

Findings: 1

Award: $94.66

🌟 Selected for report: 0

🚀 Solo Findings: 0

2022-07-golom

Gas Optimizations Report

FUNCTIONS GUARANTEED TO REVERT WHEN CALLED BY NORMAL USERS CAN BE MARKED PAYABLE

If a function modifier such as onlyOwner is used, the function will revert if a normal user tries to pay the function. Marking the function as payable will lower the gas cost for legitimate callers because the compiler will not include checks for whether a payment was provided. The extra opcodes avoided are CALLVALUE(2),DUP1(3),ISZERO(3),PUSH2(3),JUMPI(10),PUSH1(3),DUP1(3),REVERT(0),JUMPDEST(1),POP(2), which costs an average of about 21 gas per call to the function, in addition to the extra deployment cost

There are 2 instances of this issue:

File: /contracts/governance/GolomToken.sol

36:   function mint(address _account, uint256 _amount) external onlyMinter {

https://github.com/code-423n4/2022-07-golom/blob/main/contracts/governance/GolomToken.sol#L36

File: /contracts/rewards/RewardDistributor.sol

98:   function addFee(address[2] memory addr, uint256 fee) public onlyTrader {

https://github.com/code-423n4/2022-07-golom/blob/main/contracts/rewards/RewardDistributor.sol#L98

PUBLIC FUNCTIONS NOT CALLED BY THE CONTRACT SHOULD BE DECLARED EXTERNAL INSTEAD

For all the public functions, the input parameters are copied to memory automatically, and it costs gas. If your function is only called externally, then you should explicitly mark it as external. External function’s parameters are not copied into memory but are read from calldata directly. This small optimization in your solidity code can save you a lot of gas when the function input parameters are huge.

There are 12 instances of this issue:

File: /contracts/rewards/RewardDistributor.sol

98:   function addFee(address[2] memory addr, uint256 fee) public onlyTrader {

141:  function traderClaim(address addr, uint256[] memory epochs) public {

155:  function exchangeClaim(address addr, uint256[] memory epochs) public {

172:  function multiStakerClaim(uint256[] memory tokenids, uint256[] memory epochs) public {

215:  function stakerRewards(uint256 tokenid) public view returns (

254:  function traderRewards(address addr) public view returns (

269:  function exchangeRewards(address addr) public view returns ( 

https://github.com/code-423n4/2022-07-golom/blob/main/contracts/rewards/RewardDistributor.sol#L98

File: /contracts/core/GolomTrader.sol

203:  function fillAsk(

279:  function fillBid(

312:  function cancelOrder(Order calldata o) public nonReentrant {

334:  function fillCriteriaBid(

https://github.com/code-423n4/2022-07-golom/blob/main/contracts/core/GolomTrader.sol#L203

File: /contracts/vote-escrow/VoteEscrowDelegation.sol

185:  function getPriorVotes(uint256 tokenId, uint256 blockNumber) public view returns (uint256) { 

https://github.com/code-423n4/2022-07-golom/blob/main/contracts/vote-escrow/VoteEscrowDelegation.sol#L185

STATE VARIABLES SHOULD BE CACHED IN STACK VARIABLES RATHER THAN RE-READING THEM FROM STORAGE

One of most the expensive opcodes is SLOAD. In order to save gas from checking the value of storage-located variable they can be cached in memory. That way the MLOAD opcode is used each time we want to access the variable which is much cheaper than SLOAD.

There are 8 instances of this issue:

File: /contracts/core/GolomTrader.sol

189:  if (filled[hashStruct] >= o.tokenAmt) {
      ...
193:  return (3, hashStruct, o.tokenAmt - filled[hashStruct]);

Cache filled[hashStruct]
https://github.com/code-423n4/2022-07-golom/blob/main/contracts/core/GolomTrader.sol#L189-L193

File: /contracts/core/GolomTrader.sol

382:  WETH.transferFrom(o.signer, address(this), o.totalAmt * amount);
383:  WETH.withdraw(o.totalAmt * amount);

Cache WETH
https://github.com/code-423n4/2022-07-golom/blob/main/contracts/core/GolomTrader.sol#L382-L383

File: /contracts/rewards/RewardDistributor.sol

100:  if (rewardToken.totalSupply() > 1000000000 * 10**18) {
      ...
112:  uint256 tokenToEmit = (dailyEmission * (rewardToken.totalSupply() - rewardToken.balanceOf(address(ve)))) /
113:      rewardToken.totalSupply();
114:  uint256 stakerReward = (tokenToEmit * rewardToken.balanceOf(address(ve))) / rewardToken.totalSupply();

Cache rewardToken.totalSupply() and rewardToken.balanceOf(address(ve))
https://github.com/code-423n4/2022-07-golom/blob/main/contracts/rewards/RewardDistributor.sol#L100

File: /contracts/rewards/RewardDistributor.sol

173:  require(address(ve) != address(0), ' VE not added yet');

177:  address tokenowner = ve.ownerOf(tokenids[0]);

181:  require(tokenowner == ve.ownerOf(tokenids[tindex]), 'Can only claim for a single Address together');

191:      ve.balanceOfAtNFT(tokenids[tindex], epochBeginTime[1])) /
192:  ve.totalSupplyAt(epochBeginTime[1]);

198:  ve.totalSupplyAt(epochBeginTime[epochs[index]]);

203:  ve.totalSupplyAt(epochBeginTime[epochs[index]]);

220:  require(address(ve) != address(0), ' VE not added yet');

233:      ve.balanceOfAtNFT(tokenid, epochBeginTime[1])) /
234:  ve.totalSupplyAt(epochBeginTime[1]);

239:  (rewardStaker[index] * ve.balanceOfAtNFT(tokenid, epochBeginTime[index])) /
240:  ve.totalSupplyAt(epochBeginTime[index]);

244:      ve.balanceOfAtNFT(tokenid, epochBeginTime[index])) /
245:  ve.totalSupplyAt(epochBeginTime[index]);

Cache ve, ve.totalSupplyAt(epochBeginTime[epochs[index]]) and ve.balanceOfAtNFT(tokenid, epochBeginTime[index])) / ve.totalSupplyAt(epochBeginTime[index])
https://github.com/code-423n4/2022-07-golom/blob/main/contracts/rewards/RewardDistributor.sol#L173

File: /contracts/vote-escrow/VoteEscrowCore.sol

650:  bool senderIsOwner = (idToOwner[_tokenId] == msg.sender);

Use owner instead of idToOwner[_tokenId]
https://github.com/code-423n4/2022-07-golom/blob/main/contracts/vote-escrow/VoteEscrowCore.sol#L650

INTERNAL and PRIVATE FUNCTIONS ONLY CALLED ONCE CAN BE INLINED TO SAVE GAS

Not inlining costs 20 to 40 gas because of two extra JUMP instructions and additional stack operations needed for function calls.

There are 2 instances of this issue:

File: /contracts/core/GolomTrader.sol

123:  function _hashOrder(Order calldata o) private pure returns (bytes32) {

127:  function _hashOrderinternal(Order calldata o, uint256[2] memory extra) private pure returns (bytes32) {

https://github.com/code-423n4/2022-07-golom/blob/main/contracts/core/GolomTrader.sol#L123

USING > 0 COSTS LESS GAS THAN != 0 WHEN USED ON A UINT

This change saves 3 gas per instance

There are 7 instances of this issue:

File: /contracts/vote-escrow/VoteEscrowCore.sol

701:  if (_tokenId != 0) {

717:  if (new_locked.end != 0) {

781:  if (_tokenId != 0) {

797:  if (_tokenId != 0) {

848:  if (unlock_time != 0) {

860:  if (_value != 0 && deposit_type != DepositType.MERGE_TYPE) {

1144: if (d_block != 0) {

https://github.com/code-423n4/2022-07-golom/blob/main/contracts/vote-escrow/VoteEscrowCore.sol#L701

DEFAULT VALUE INITIALIZATION

If a variable is not set/initialized, it is assumed to have the default value (0, false, 0x0 etc depending on the data type). Explicitly initializing it with its default value is an anti-pattern and wastes gas.

There are 37 instances of this issue:

File: /contracts/core/GolomTrader.sol

415:  for (uint256 i = 0; i < proof.length; i++) {

https://github.com/code-423n4/2022-07-golom/blob/main/contracts/core/GolomTrader.sol#L415

File: /contracts/rewards/RewardDistributor.sol

45:   uint256 public epoch = 0;

142:  uint256 reward = 0;

143:  for (uint256 index = 0; index < epochs.length; index++) {

156:  uint256 reward = 0;

157:  for (uint256 index = 0; index < epochs.length; index++) {

175:  uint256 reward = 0;

176:  uint256 rewardEth = 0;

180:  for (uint256 tindex = 0; tindex < tokenids.length; tindex++) {

183:  for (uint256 index = 0; index < epochs.length; index++) {

222:  uint256 reward = 0;

223:  uint256 rewardEth = 0;

226:  for (uint256 index = 0; index < epoch; index++) {

257:  uint256 reward = 0;

258:  for (uint256 index = 0; index < epoch; index++) {

272:  uint256 reward = 0;

273:  for (uint256 index = 0; index < epoch; index++) {

https://github.com/code-423n4/2022-07-golom/blob/main/contracts/rewards/RewardDistributor.sol#L45

File: /contracts/vote-escrow/VoteEscrowCore.sol

697:  int128 old_dslope = 0;

698:  int128 new_dslope = 0;

735:  uint256 block_slope = 0;

745:  for (uint256 i = 0; i < 255; ++i) {

749:  int128 d_slope = 0;

1042: uint256 _min = 0;

1044: for (uint256 i = 0; i < 128; ++i) {

1113: uint256 _min = 0;

1115: for (uint256 i = 0; i < 128; ++i) {

1133: uint256 d_block = 0;

1134: uint256 d_t = 0;

1167: for (uint256 i = 0; i < 255; ++i) {

1169: int128 d_slope = 0;

1211: uint256 dt = 0;

https://github.com/code-423n4/2022-07-golom/blob/main/contracts/vote-escrow/VoteEscrowCore.sol#L697

File: /contracts/vote-escrow/VoteEscrowDelegation.sol

50:   uint256 public MIN_VOTING_POWER_REQUIRED = 0;

147:  uint256 lower = 0;

170:  uint256 votes = 0;

171:  for (uint256 index = 0; index < delegated.length; index++) {

188:  uint256 votes = 0;

189:  for (uint256 index = 0; index < delegatednft.length; index++) {

https://github.com/code-423n4/2022-07-golom/blob/main/contracts/vote-escrow/VoteEscrowDelegation.sol#L50

USING PRIVATE RATHER THAN PUBLIC FOR CONSTANTS, SAVES GAS

If needed, the value can be read from the verified contract source code. Savings are due to the compiler not having to create non-payable getter functions for deployment calldata, and not adding another entry to the method ID table

There are 4 instances of this issue:

File: /contracts/vote-escrow/VoteEscrowCore.sol

317:  string public constant name = 'veNFT';

318:  string public constant symbol = 'veNFT';

319:  string public constant version = '1.0.0';

320:  uint8 public constant decimals = 18;

https://github.com/code-423n4/2022-07-golom/blob/main/contracts/vote-escrow/VoteEscrowCore.sol#L317-L320

PREFIX INCREMENTS ARE CHEAPER THAN POSTFIX INCREMENTS

++I costs less gas than I++, especially when it's used in for-loops (--I/I-- too). Saves 6 gas per instance

There are 11 instances of this issue:

File: /contracts/vote-escrow/VoteEscrowDelegation.sol

171:  for (uint256 index = 0; index < delegated.length; index++) {

189:  for (uint256 index = 0; index < delegatednft.length; index++) {

199:  for (uint256 i; i < _array.length; i++) {

https://github.com/code-423n4/2022-07-golom/blob/main/contracts/vote-escrow/VoteEscrowDelegation.sol#L171

File: /contracts/core/GolomTrader.sol

415:  for (uint256 i = 0; i < proof.length; i++) {

https://github.com/code-423n4/2022-07-golom/blob/main/contracts/core/GolomTrader.sol#L415

File: /contracts/rewards/RewardDistributor.sol

143:  for (uint256 index = 0; index < epochs.length; index++) {

157:  for (uint256 index = 0; index < epochs.length; index++) {

180:  for (uint256 tindex = 0; tindex < tokenids.length; tindex++) { 

183:  for (uint256 index = 0; index < epochs.length; index++) {

226:  for (uint256 index = 0; index < epoch; index++) { 

258:  for (uint256 index = 0; index < epoch; index++) {

273:  for (uint256 index = 0; index < epoch; index++) {

https://github.com/code-423n4/2022-07-golom/blob/main/contracts/rewards/RewardDistributor.sol#L143

<ARRAY>.LENGTH SHOULD NOT BE LOOKED UP IN EVERY LOOP OF A FOR-LOOP

The overheads outlined below are PER LOOP, excluding the first loop

  • storage arrays incur a Gwarmaccess (100 gas)
  • memory arrays use MLOAD (3 gas)
  • calldata arrays use CALLDATALOAD (3 gas) \

There are 11 instances of this issue:

File: /contracts/vote-escrow/VoteEscrowDelegation.sol

171:  for (uint256 index = 0; index < delegated.length; index++) {

189:  for (uint256 index = 0; index < delegatednft.length; index++) {

199:  for (uint256 i; i < _array.length; i++) {

https://github.com/code-423n4/2022-07-golom/blob/main/contracts/vote-escrow/VoteEscrowDelegation.sol#L171

File: /contracts/core/GolomTrader.sol

415:  for (uint256 i = 0; i < proof.length; i++) {

https://github.com/code-423n4/2022-07-golom/blob/main/contracts/core/GolomTrader.sol#L415

File: /contracts/rewards/RewardDistributor.sol

143:  for (uint256 index = 0; index < epochs.length; index++) {

157:  for (uint256 index = 0; index < epochs.length; index++) {

180:  for (uint256 tindex = 0; tindex < tokenids.length; tindex++) { 

183:  for (uint256 index = 0; index < epochs.length; index++) {

https://github.com/code-423n4/2022-07-golom/blob/main/contracts/rewards/RewardDistributor.sol#L143

++I/I++ SHOULD BE UNCHECKED{++I}/UNCHECKED{I++} WHEN IT IS NOT POSSIBLE FOR THEM TO OVERFLOW, AS IS THE CASE WHEN USED IN FOR- AND WHILE-LOOPS

The unchecked keyword is new in solidity version 0.8.0, so this only applies to that version or higher, which these instances are. This saves 30-40 gas per loop

There are 15 instances of this issue:

File: /contracts/core/GolomTrader.sol

415:  for (uint256 i = 0; i < proof.length; i++) {

https://github.com/code-423n4/2022-07-golom/blob/main/contracts/core/GolomTrader.sol#L415

File: /contracts/rewards/RewardDistributor.sol

143:  for (uint256 index = 0; index < epochs.length; index++) {

157:  for (uint256 index = 0; index < epochs.length; index++) {

180:  for (uint256 tindex = 0; tindex < tokenids.length; tindex++) {

183:  for (uint256 index = 0; index < epochs.length; index++) {

226:  for (uint256 index = 0; index < epoch; index++) {

258:  for (uint256 index = 0; index < epoch; index++) {

273:  for (uint256 index = 0; index < epoch; index++) {

https://github.com/code-423n4/2022-07-golom/blob/main/contracts/rewards/RewardDistributor.sol#L143

File: /contracts/vote-escrow/VoteEscrowCore.sol

745:  for (uint256 i = 0; i < 255; ++i) {

1044: for (uint256 i = 0; i < 128; ++i) {

1115: for (uint256 i = 0; i < 128; ++i) {

1167: for (uint256 i = 0; i < 255; ++i) {

https://github.com/code-423n4/2022-07-golom/blob/main/contracts/vote-escrow/VoteEscrowCore.sol#L745

File: /contracts/vote-escrow/VoteEscrowDelegation.sol

171:  for (uint256 index = 0; index < delegated.length; index++) {

189:  for (uint256 index = 0; index < delegatednft.length; index++) {

199:  for (uint256 i; i < _array.length; i++) {

https://github.com/code-423n4/2022-07-golom/blob/main/contracts/vote-escrow/VoteEscrowDelegation.sol#L171

X += Y COSTS MORE GAS THAN X = X + Y FOR STATE VARIABLES (SAME FOR X -= Y)

There are 2 instances of this issue:

File: /contracts/vote-escrow/VoteEscrowCore.sol

499:  ownerToNFTokenCount[_to] += 1;

512:  ownerToNFTokenCount[_from] -= 1;

https://github.com/code-423n4/2022-07-golom/blob/main/contracts/vote-escrow/VoteEscrowCore.sol#L499

USAGE OF UINTS/INTS SMALLER THAN 32 BYTES (256 BITS) INCURS OVERHEAD

"When using elements that are smaller than 32 bytes, your contract’s gas usage may be higher. This is because the EVM operates on 32 bytes at a time. Therefore, if the element is smaller than that, the EVM must use more operations in order to reduce the size of the element from 32 bytes to the desired size."

https://docs.soliditylang.org/en/v0.8.15/internals/layout_in_storage.html
Use a larger size then downcast where needed

There are 9 instances of this issue:

File: /contracts/vote-escrow/VoteEscrowCore.sol

261:  int128 bias;

262:  int128 slope;

271:  int128 amount;

297:  int128 internal constant iMAXTIME = 4 * 365 * 86400;

311:  mapping(uint256 => int128) public slope_changes; 

697:  int128 old_dslope = 0;

698:  int128 new_dslope = 0;

749:  int128 d_slope = 0;

1169: int128 d_slope = 0;

https://github.com/code-423n4/2022-07-golom/blob/main/contracts/vote-escrow/VoteEscrowCore.sol#L261

Replace x <= y with x < y + 1, and x >= y with x > y - 1.

In the EVM, there is no opcode for >= or <=. When using greater than or equal, two operations are performed: > and =. Using strict comparison operators hence saves gas

There are 19 instances of this issue:

File: /contracts/core/GolomTrader.sol

189:  if (filled[hashStruct] >= o.tokenAmt) {

212:  o.totalAmt >= o.exchange.paymentAmt + o.prePayment.paymentAmt + o.refererrAmt + (o.totalAmt * 50) / 10000,

217:  require(msg.value >= o.totalAmt * amount + p.paymentAmt, 'mgmtm');

227:  require(amountRemaining >= amount, 'order already filled');

296:  require(amountRemaining >= amount);

342:  require(o.totalAmt >= o.exchange.paymentAmt + o.prePayment.paymentAmt + o.refererrAmt);

350:  require(amountRemaining >= amount);

417:  if (computedHash <= proofElement) {

455:  require(distributorEnableDate <= block.timestamp, 'not allowed');

https://github.com/code-423n4/2022-07-golom/blob/main/contracts/core/GolomTrader.sol#L189

File: /contracts/governance/GolomToken.sol

69:   require(minterEnableDate <= block.timestamp, 'GolomToken: wait for timelock');

https://github.com/code-423n4/2022-07-golom/blob/main/contracts/governance/GolomToken.sol#L69

File: /contracts/rewards/RewardDistributor.sol

292:  require(traderEnableDate <= block.timestamp, 'RewardDistributor: time not over yet');

309:  require(voteEscrowEnableDate <= block.timestamp, 'RewardDistributor: time not over yet');

https://github.com/code-423n4/2022-07-golom/blob/main/contracts/rewards/RewardDistributor.sol#L292

File: /contracts/vote-escrow/VoteEscrowCore.sol

902:  uint256 end = _locked0.end >= _locked1.end ? _locked0.end : _locked1.end;

946:  require(unlock_time <= block.timestamp + MAXTIME, 'Voting lock can be 4 years max'); 

999:  require(unlock_time <= block.timestamp + MAXTIME, 'Voting lock can be 4 years max');

1011: require(block.timestamp >= _locked.end, "The lock didn't expire");

1046: if (_min >= _max) {

1050: if (point_history[_mid].blk <= _block) {

1110: assert(_block <= block.number);

1117: if (_min >= _max) {

1121: if (user_point_history[_tokenId][_mid].blk <= _block) {

1149: if (upoint.bias >= 0) {

1206: assert(_block <= block.number);

https://github.com/code-423n4/2022-07-golom/blob/main/contracts/vote-escrow/VoteEscrowCore.sol#L901

File: /contracts/vote-escrow/VoteEscrowDelegation.sol

73:   require(this.balanceOfNFT(tokenId) >= MIN_VOTING_POWER_REQUIRED, 'VEDelegation: Need more voting power');

138:  if (checkpoints[nftId][nCheckpoints - 1].fromBlock <= blockNumber) {

https://github.com/code-423n4/2022-07-golom/blob/main/contracts/vote-escrow/VoteEscrowDelegation.sol#L73

USE CUSTOM ERRORS RATHER THAN REVERT()/REQUIRE() STRINGS

Custom errors from Solidity 0.8.4 are cheaper than revert strings (cheaper deployment cost and runtime cost when the revert condition is met) while providing the same amount of information. In order to get rid of the multiple custom errors, a single universal custom error Exception(uint c) can be used. It would accept a single parameter that represents an error code used to make a reference to an off-chain dictionary of the errors' descriptions.

There are 46 instances of this issue:

File: /contracts/governance/GolomToken.sol

24:   require(msg.sender == minter, 'GolomToken: only reward distributor can enable');

43:   require(!isAirdropMinted, 'already minted');

51:   require(!isGenesisRewardMinted, 'already minted');

69:   require(minterEnableDate <= block.timestamp, 'GolomToken: wait for timelock');

https://github.com/code-423n4/2022-07-golom/blob/main/contracts/governance/GolomToken.sol#L24

File: /contracts/vote-escrow/VoteEscrowDelegation.sol

72:   require(ownerOf(tokenId) == msg.sender, 'VEDelegation: Not allowed');

73:   require(this.balanceOfNFT(tokenId) >= MIN_VOTING_POWER_REQUIRED, 'VEDelegation: Need more voting power');

99:   require(_delegatedTokenIds.length < 500, 'VVDelegation: Cannot stake more');

130:  require(blockNumber < block.number, 'VEDelegation: not yet determined');

186:  require(blockNumber < block.number, 'VEDelegation: not yet determined');

211:  require(ownerOf(tokenId) == msg.sender, 'VEDelegation: Not allowed');

239:  require(attachments[_tokenId] == 0 && !voted[_tokenId], 'attached');

https://github.com/code-423n4/2022-07-golom/blob/main/contracts/vote-escrow/VoteEscrowDelegation.sol#L72

File: /contracts/rewards/RewardDistributor.sol

173:  require(address(ve) != address(0), ' VE not added yet');

181:  require(tokenowner == ve.ownerOf(tokenids[tindex]), 'Can only claim for a single Address together');

184:  require(epochs[index] < epoch, 'cant claim for future epochs');

185:  require(claimed[tokenids[tindex]][epochs[index]] == 0, 'cant claim if already claimed');

220:  require(address(ve) != address(0), ' VE not added yet');

292:  require(traderEnableDate <= block.timestamp, 'RewardDistributor: time not over yet');

309:  require(voteEscrowEnableDate <= block.timestamp, 'RewardDistributor: time not over yet');

https://github.com/code-423n4/2022-07-golom/blob/main/contracts/rewards/RewardDistributor.sol#L173

File: /contracts/core/GolomTrader.sol

177:  require(signaturesigner == o.signer, 'invalid signature');

211:  require(
212:      o.totalAmt >= o.exchange.paymentAmt + o.prePayment.paymentAmt + o.refererrAmt + (o.totalAmt * 50) / 10000, //19
213:      'amt not matching' //17
214:  );

217:  require(msg.value >= o.totalAmt * amount + p.paymentAmt, 'mgmtm');

222:  require(o.orderType == 0, 'invalid orderType');

226:  require(status == 3, 'order not valid');

227:  require(amountRemaining >= amount, 'order already filled');

235:  require(amount == 1, 'only 1 erc721 at 1 time');

299:  require(amount == 1, 'only 1 erc721 at 1 time');

359:  require(amount == 1, 'only 1 erc721 at 1 time');

426:  revert('invalid proof');

455:  require(distributorEnableDate <= block.timestamp, 'not allowed');

https://github.com/code-423n4/2022-07-golom/blob/main/contracts/core/GolomTrader.sol#L177

File: /contracts/vote-escrow/VoteEscrowCore.sol

538:  require(attachments[_tokenId] == 0 && !voted[_tokenId], 'attached');

608:  revert('ERC721: transfer to non ERC721Receiver implementer');

894:  require(attachments[_from] == 0 && !voted[_from], 'attached');

928:  require(_locked.amount > 0, 'No existing lock found');

929:  require(_locked.end > block.timestamp, 'Cannot add to expired lock. Withdraw');

945:  require(unlock_time > block.timestamp, 'Can only lock until time in the future');

946:  require(unlock_time <= block.timestamp + MAXTIME, 'Voting lock can be 4 years max');

982:  require(_locked.amount > 0, 'No existing lock found');

983:  require(_locked.end > block.timestamp, 'Cannot add to expired lock. Withdraw');

996:  require(_locked.end > block.timestamp, 'Lock expired');

997:  require(_locked.amount > 0, 'Nothing is locked');

998:  require(unlock_time > _locked.end, 'Can only increase lock duration');

999:  require(unlock_time <= block.timestamp + MAXTIME, 'Voting lock can be 4 years max');

1008: require(attachments[_tokenId] == 0 && !voted[_tokenId], 'attached');

1011: require(block.timestamp >= _locked.end, "The lock didn't expire");

1082: require(idToOwner[_tokenId] != address(0), 'Query for nonexistent token'); 

1227: require(_isApprovedOrOwner(msg.sender, _tokenId), 'caller is not owner nor approved');

https://github.com/code-423n4/2022-07-golom/blob/main/contracts/vote-escrow/VoteEscrowCore.sol#L538

Duplicate code

Remove duplicate code in order to reduce contract's size and deployment cost

There is 1 instances of this issue:

File: /contracts/vote-escrow/VoteEscrowCore.sol

467:  if (current_count == current_index) {
468:      // update ownerToNFTokenIdList
469:      ownerToNFTokenIdList[_from][current_count] = 0;
470:      // update tokenToOwnerIndex
471:      tokenToOwnerIndex[_tokenId] = 0;
472:  } else {
473:      uint256 lastTokenId = ownerToNFTokenIdList[_from][current_count];
474:
475:      // Add
476:      // update ownerToNFTokenIdList
477:      ownerToNFTokenIdList[_from][current_index] = lastTokenId;
478:      // update tokenToOwnerIndex
479:      tokenToOwnerIndex[lastTokenId] = current_index;
480:
481:      // Delete //bonus изнеси извън тва to reduce deployment
482:      // update ownerToNFTokenIdList
483:      ownerToNFTokenIdList[_from][current_count] = 0;
484:      // update tokenToOwnerIndex
485:      tokenToOwnerIndex[_tokenId] = 0;
486:  }

^ Remove the first check and move lines 468-471 and 482-485 outside the if check' parentheses

Result:

File: /contracts/vote-escrow/VoteEscrowCore.sol

467:  if (current_count != current_index) {
468:      uint256 lastTokenId = ownerToNFTokenIdList[_from][current_count];
469:
470:      // Add
471:      // update ownerToNFTokenIdList
472:      ownerToNFTokenIdList[_from][current_index] = lastTokenId;
473:      // update tokenToOwnerIndex
474:      tokenToOwnerIndex[lastTokenId] = current_index;
475:  }
476
477:  // update ownerToNFTokenIdList
478:  ownerToNFTokenIdList[_from][current_count] = 0;
479:  // update tokenToOwnerIndex
480:  tokenToOwnerIndex[_tokenId] = 0;

https://github.com/code-423n4/2022-07-golom/blob/main/contracts/vote-escrow/VoteEscrowCore.sol#L467-L486

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