Swivel v3 contest - ElKu's results

The Capital-Efficient Protocol For Fixed-Rate Lending.

General Information

Platform: Code4rena

Start Date: 12/07/2022

Pot Size: $35,000 USDC

Total HM: 13

Participants: 78

Period: 3 days

Judge: 0xean

Total Solo HM: 6

Id: 135

League: ETH

Swivel

Findings Distribution

Researcher Performance

Rank: 47/78

Findings: 2

Award: $70.44

🌟 Selected for report: 0

🚀 Solo Findings: 0

1) Missing natspec comment.

  1. ZcToken.sol 1. There is no natspec comment for parameter holder in withdraw function. 2. There is no natspec comment for parameter holder in redeem function.

2) Declare magic numbers as constants in VaultTracker.sol

Magic number 1e26 used in 6 functions: addNotional, removeNotional, redeemInterest, transferNotionalFrom, transferNotionalFee and removeNotional.

Awards

26.1808 USDC - $26.18

Labels

bug
G (Gas Optimization)
resolved

External Links

1) State variables which are read more than once should be cached to save gas.

  1. ZcToken.sol 1. protocol, redeemer and maturity state variables in convertToUnderlying function. 2. protocol, redeemer and maturity state variables in convertToPrincipal function.

2) Remove Identical functions in ZcToken.sol.

  1. convertToUnderlying and previewRedeem functions are identical.
  2. convertToPrincipal and previewWithdraw functions are identical.

3) Convert frequenctly used revert checks into a modifier.

ZcToken.sol has the following revert check which repeats twice.

if (block.timestamp < maturity) { revert Maturity(maturity); }

4) Simplify formula for better readability and gas saving.

There are 6 functions in VaultTracker.sol ( addNotional, removeNotional, redeemInterest, transferNotionalFrom, transferNotionalFee and removeNotional ) which calculate interest in the following way:

if (maturityRate > 0) { // calculate marginal interest yield = ((maturityRate * 1e26) / sVault.exchangeRate) - 1e26; } else { yield = ((exchangeRate * 1e26) / sVault.exchangeRate) - 1e26; } uint256 interest = (yield * sVault.notional) / 1e26;

These can be re-written as below:

if (maturityRate > 0) { // calculate marginal interest interest = ((maturityRate * sVault.notional - sVault.notional) / sVault.exchangeRate); } else { interest = ((exchangeRate * sVault.notional - sVault.notional) / sVault.exchangeRate); }

5) Use already cached variable instead of indexing again.

There are two instances of this:

  1. The value of o[i] is already cached into memory variable order. So use it inside the following if-else statements instead of freshly indexing again.
  2. The same is happening in the exit function.

#0 - robrobbins

2022-08-31T19:39:53Z

  1. good point, but the implementation used is the inverse of the suggestion here. to be consistent with other tickets pointing out reading from calldata here is better than memory it is more in pattern to remove the memory order and simply use o[i] throughout. this applies to every function called by these as well as changing the call to them with a memory order would require changing those signatures as well

that being said, marking this as resolved because pointing out order vs o[i] here is worth recognizing

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