Platform: Code4rena
Start Date: 20/01/2023
Pot Size: $90,500 USDC
Total HM: 10
Participants: 59
Period: 7 days
Judge: Picodes
Total Solo HM: 4
Id: 206
League: ETH
Rank: 47/59
Findings: 1
Award: $65.35
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: rbserver
Also found by: 0x1f8b, 0xAgro, 0xGusMcCrae, 0xSmartContract, Awesome, Breeje, DadeKuma, Diana, IllIllI, Josiah, Moksha, RaymondFam, Rolezn, SaeedAlipoor01988, Udsen, Viktor_Cortess, brgltd, btk, chaduke, cryptonue, ddimitrov22, delfin454000, descharre, fatherOfBlocks, georgits, hansfriese, lukris02, luxartvinsec, martin, matrix_0wl, mookimgo, oberon, popular00, shark, tnevler
65.3481 USDC - $65.35
The codebase is very solid and doesn't present any particular security risks. Tests are a bit lacking and incomplete, but they are a work in progress. It does not pose any concerning centralization risks.
numberOfPairs
is not implemented and always returns 0In TimeswapV2OptionFactory.sol
getByIndex
is never assigned, so numberOfPairs
has always zero length.
Code: https://github.com/code-423n4/2023-01-timeswap/blob/main/packages/v2-pool/src/TimeswapV2PoolFactory.sol#L52-L54 https://github.com/code-423n4/2023-01-timeswap/blob/main/packages/v2-pool/src/TimeswapV2PoolFactory.sol#L33
In TimeswapV2OptionFactory.sol
there isn't a check for creating a pool with a strike of zero. This is low risk because everywhere else (mint, burn, leverage) there is a check, so these transactions will fail.
If mint, burn, leverage, or deleverage are called with a durationForward
, the isQuote
parameter will always be true, thus reverting the transaction. These functions will never go through, so it would make sense to remove them entirely.
Example with mint:
function mint( TimeswapV2PoolMintParam calldata param, uint96 durationForward ) external override returns (uint160 liquidityAmount, uint256 long0Amount, uint256 long1Amount, uint256 shortAmount, bytes memory data) { return mint(param, true, durationForward); } function mint( TimeswapV2PoolMintParam calldata param, bool isQuote, uint96 durationForward ) private noDelegateCall returns (uint160 liquidityAmount, uint256 long0Amount, uint256 long1Amount, uint256 shortAmount, bytes memory data) { ... if (isQuote) revert Quote(); ... }
Code: https://github.com/code-423n4/2023-01-timeswap/blob/main/packages/v2-pool/src/TimeswapV2Pool.sol#L245-L250 https://github.com/code-423n4/2023-01-timeswap/blob/main/packages/v2-pool/src/TimeswapV2Pool.sol#L310-L315 https://github.com/code-423n4/2023-01-timeswap/blob/main/packages/v2-pool/src/TimeswapV2Pool.sol#L370-L375 https://github.com/code-423n4/2023-01-timeswap/blob/main/packages/v2-pool/src/TimeswapV2Pool.sol#L426-L428
notZeroAddress
The second zeroAddress
revert is a bit misleading in this case because the transaction will fail if the address is not the zero address. This is confusing because before that it was used in the opposite way:
if (optionPair == address(0)) Error.zeroAddress(); pair = pairs[optionPair]; if (pair != address(0)) Error.zeroAddress();
/// @dev mapping of all option state for all strikes and maturies.
Code: https://github.com/code-423n4/2023-01-timeswap/blob/main/packages/v2-option/src/TimeswapV2Option.sol#L31 https://github.com/code-423n4/2023-01-timeswap/blob/main/packages/v2-option/src/TimeswapV2Option.sol#L47
/// @dev Reverts when an option of given strike and maturity is still inactive. /// @param strike The chosen strike. function inactiveOptionChoice(uint256 strike, uint256 maturity) external pure { return Error.inactiveOptionChoice(strike, maturity); }
#0 - c4-judge
2023-02-02T11:29:12Z
Picodes marked the issue as grade-b