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: 32/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
Issue | Description | Instances |
---|---|---|
1 | Duplicate file names could be problematic | 5 |
Total | 5 |
Issue | Description | Instances |
---|---|---|
1 | Event is missing indexed fields | 3 |
2 | Long single-line comments | 51 |
3 | Typos | 97 |
4 | pragma solidity version should be upgraded to latest version before finalization | 3 |
5-1 | Natspec completely or mostly missing for function | 8 |
5-2 | @param missing for function | 3 |
5-3 | @return missing for function | 30 |
5-4 | Natspec is missing for event | 1 |
Total | 196 |
No. | Explanation + cases |
---|---|
1 | Duplicate file names could be problematic |
The in-scope contacts include multiple instances of duplicate file names, as shown below | |
The existence of two or more files with in same name within the packages folder could cause errors and confusion, and could also cause compilation problems under some circumstances |
CallbackParam.sol
NoDelegateCall.sol
https://github.com/code-423n4/2023-01-timeswap/blob/main/packages/v2-pool/src/NoDelegateCall.sol
https://github.com/code-423n4/2023-01-timeswap/blob/main/packages/v2-option/src/NoDelegateCall.sol
Param.sol
https://github.com/code-423n4/2023-01-timeswap/blob/main/packages/v2-pool/src/structs/Param.sol
https://github.com/code-423n4/2023-01-timeswap/blob/main/packages/v2-option/src/structs/Param.sol
Position.sol
https://github.com/code-423n4/2023-01-timeswap/blob/main/packages/v2-token/src/structs/Position.sol
https://github.com/code-423n4/2023-01-timeswap/blob/main/packages/v2-option/src/enums/Position.sol
Transaction.sol
https://github.com/code-423n4/2023-01-timeswap/blob/main/packages/v2-pool/src/enums/Transaction.sol
No. | Description |
---|---|
1 | Event is missing indexed fields |
Each event should use three indexed fields if there are three or more fields; if fewer, all should be indexed, assuming gas cost is not too expensive |
/// @dev Emits when the pending owner is chosen. /// @param pendingOwner The new pending owner. event SetOwner(address pendingOwner);
/// @dev Emits when the pending owner accepted and become the new owner. /// @param owner The new owner. event AcceptOwner(address owner);
ITimeswapV2LiquidityToken.sol: L13
event TransferFees(address from, address to, TimeswapV2LiquidityTokenPosition position, uint256 long0Fees, uint256 long1Fees, uint256 shortFees);
No. | Explanation + cases |
---|---|
2 | Long single-line comments |
In theory, comments over 80 characters should wrap using multi-line comment syntax. Even if longer comments (up to 120 characters) are becoming acceptable and a scroll bar is provided, very long comments can interfere with readability | |
Below are five instances of extra-long comments (over 120 characters) whose readability could be improved by wrapping, as shown. Note that a small indentation is used in each continuation line (which flags for the reader that the comment is ongoing), along with a period at the close (to signal the end of the comment) |
v2-option/src/structs/Param.sol: L62
/// @param amount If isLong0ToLong1 and transaction is GivenToken0AndLong0, this is the amount of token0 withdrawn, and the amount of long0 position burnt.
Suggestion:
/// @param amount If isLong0ToLong1 and transaction is GivenToken0AndLong0, this is the /// amount of token0 withdrawn, and the amount of long0 position burnt.
v2-option/src/structs/Param.sol: L63
/// If isLong1ToLong0 and transaction is GivenToken0AndLong0, this is the amount of token0 to be deposited, and the amount of long0 position minted.
Suggestion:
/// If isLong1ToLong0 and transaction is GivenToken0AndLong0, this is the amount of /// token0 to be deposited, and the amount of long0 position minted.
/// @dev Calculate the amount of liquidity positions and amount of short positions from given long positions in base denomination.
Suggestion:
/// @dev Calculate the amount of liquidity positions and amount of long positions /// in base denomination or short position whichever is larger or smaller.
/// @dev Move short positions to short fee growth due to duration of the pool decreasing as time moves forward.
Suggestion:
/// @dev Move short positions to short fee growth due to duration of the /// pool decreasing as time moves forward.
v2-pool/src/structs/Param.sol: L76
/// If transaction is GivenSum, the sum amount of long position in base denomination to be deposited, and short position to be withdrawn.
Suggestion:
/// If transaction is GivenSum, the sum amount of long position in base /// denomination to be deposited, and short position to be withdrawn.
Similarly for the following extra-long (over 120 characters) comments:
StrikeConversion.sol
ITimeswapV2Pool.sol
L170, L256, L265, L299, L300, L312
ITimeswapV2PoolBurnCallback.sol
ITimeswapV2PoolLeverageCallback.sol
ITimeswapV2PoolMintCallback.sol
ITimeswapV2PoolDeleverageCallback.sol
v2-pool/src/structs/Param.sol
Pool.sol
ConstantProduct.sol
DurationCalculation.sol
ITimeswapV2Option.sol
ITimeswapV2OptionSwapCallback.sol
ITimeswapV2OptionMintCallback.sol
ITimeswapV2OptionCollectCallback.sol
ITimeswapV2OptionBurnCallback.sol
Option.sol
v2-option/src/structs/Param.sol
No. | Description |
---|---|
3 | Typos |
/// @param addendA0 The least signficant part of addendA.
Change signficant
to significant
// correct result modulo 2**256. Since the precoditions guarantee
Change precoditions
to preconditions
The same typo (have
) occurs in both lines below:
/// @dev Reverts when a pool already have liquidity.
Change have
to has
in both cases
/// @param amount The amount ot be converted. Token0 amount when zeroToOne. Token1 amount when oneToZero.
Change ot
to to
The same typo (overidden
) occurs in all six lines below:
// Can be overidden for testing purposes.
Change overidden
to overridden
in all cases
v2-token/src/structs/CallbackParam.sol: L32
/// @param data Arbitrary data passed to the callback, initalize as empty if not required.
Change initalize
to initialize
The same typo (receipients
) occurs in all seven lines below:
ITimeswapV2OptionMintCallback.sol: L12
ITimeswapV2OptionCollectCallback.sol: L12
ITimeswapV2OptionBurnCallback.sol: L12
/// @dev Transfer long0 positions, long1 positions, and/or short positions to the receipients.
Change receipients
to recipients
in all cases
The same typo (receipient
) occurs in all 54 lines below:
TimeswapV2Pool.sol
IL121, IL122, IL132, IL234, IL242
ITimeswapV2PoolRebalanceCallback.sol
ITimeswapV2PoolMintCallback.sol
ITimeswapV2PoolDeleverageCallback.sol
v2-pool/src/structs/Param.sol
Pool.sol
ITimeswapV2Option
v2-option/src/structs/Param.sol
/// @param long0To The receipient of long0 positions.
Change receipient
to recipient
in all cases
The same typo (receipeint
) occurs in all three lines below:
/// @param to The receipeint of liquidity position.
Change receipeint
to recipient
in each case
/// @param to If isLong0ToLong1 then receipient of long0 positions, ekse recipient of long1 positions.
Change ekse
to else
The same typo (receipients
) occurs in all six lines below:
ITimeswapV2Pool.sol
Pool.sol
/// @dev Transfer long0 positions, long1 positions, and/or short positions to the receipients.
Change receipients
to recipients
in all cases
ITimeswapV2PoolMintCallback.sol: L10
/// @dev The liquidity positionss will already be minted to the receipient.
Change positionss
to positions
/// @return sqrtDiscriminant The square root disriminant calculated.
Change disriminant
to discriminant
The same typo (retreived
) occurs in all four lines below:
PoolFactory.sol
/// @return optionPair The retreived option pair address. Zero address if not deployed.
Change retreived
to retrieved
in all cases
/// @dev Checks if the pool doesn not exist.
Change doesn
to does
The same typo (postion
) occurs in both lines below:
/// @dev mints TimeswapV2Token as per postion and amount
Change postion
to position
in both cases
The same typo (liqudityAmount
) occurs in both lines below:
ITimeswapV2LiquidityToken.sol: L44
ITimeswapV2LiquidityToken.sol: L49
/// @dev mints TimeswapV2LiquidityToken as per the liqudityAmount
Change liqudityAmount
to liquidityAmount
in both cases
/// @dev Processing information required for interacting multple options in a single contract.
Change multple
to multiple
The same typo (calback
) occurs in both lines below:
v2-option/src/structs/Param.sol: L43
v2-option/src/structs/Param.sol: L88
/// @notice If data length is zero, skips the calback.
Change calback
to callback
in both cases
The same typo (maturies
) occurs in both lines below:
/// @notice Holds the option of all strikes and maturies.
Change maturies
to maturities
in both cases
No. | Description |
---|---|
4 | pragma solidity version should be upgraded to latest version before finalization |
The solidity version used in the in-scope contracts is either pragma solidity ^0.8.0 , pragma solidity ^0.8.8 or pragma solidity =0.8.8 compared to the latest version of 0.8.17 . | |
There are specific upgrades that have been applied since 0.8.8 . For example, a version of at least 0.8.10 is required to have external calls skip contract existence checks if the external call has a return value, 0.8.12 is necessary for string.concat to be used instead of abi.encodePacked , and 0.8.13 or later is needed for the ability to use using for with a list of free functions. In addition, only the latest version receives security fixes. |
No. | Description |
---|---|
5-1 | Natspec completely or mostly missing for function |
While the majority of functions in the in-scope contracts are preceded by complete Natspec, it is missing or mostly missing for the functions below | |
Note that NatSpec is required for public or external functions but not for private or internal ones |
TimeswapV2PoolFactory.sol: L52-54
function numberOfPairs() external view override returns (uint256) { return getByIndex.length; }
ITimeswapV2PoolFactory.sol: L31
function getByIndex(uint256 id) external view returns (address optionPair);
ITimeswapV2PoolFactory.sol: L33
function numberOfPairs() external view returns (uint256);
IERC1155Enumerable.sol: L14-16
/// @dev Returns a token ID owned by `owner` at a given `index` of its token list. /// Use along with {balanceOf} to enumerate all of ``owner``'s tokens. function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256);
Missing: @param
and @return
statements
IERC1155Enumerable.sol: L18-20
/// @dev Returns a token ID at a given `index` of all the tokens stored by the contract. /// Use along with {totalSupply} to enumerate all tokens. function tokenByIndex(uint256 index) external view returns (uint256);
Missing: @param
and @return
statements
function getByIndex(uint256 id) external view override returns (StrikeAndMaturity memory) { return listOfOptions[id];
function numberOfOptions() external view override returns (uint256) { return listOfOptions.length;
function collect(TimeswapV2OptionCollectParam calldata param) external override noDelegateCall returns (uint256 token0Amount, uint256 token1Amount, uint256 shortAmount, bytes memory data) {
No. | Description |
---|---|
5-2 | @param missing for function |
One or more @param statements is missing for the following functions : |
/// @dev Returns the amount of sum of long0 and long1 converted to base denomination in the pool. /// @dev Returns the amount of short positions in the pool. /// @param pool The state of the pool. /// @return longAmount The amount of sum of long0 and long1 converted to base denomination in the pool. /// @return shortAmount The amount of short in the pool. function totalPositions(Pool storage pool, uint256 maturity, uint96 blockTimestamp) external view returns (uint256 longAmount, uint256 shortAmount) { longAmount = ConstantProduct.getLong(pool.liquidity, pool.sqrtInterestRate, false); shortAmount = ConstantProduct.getShort(pool.liquidity, pool.sqrtInterestRate, DurationCalculation.unsafeDurationFromNowToMaturity(maturity, blockTimestamp), false); }
Missing: @param maturity
and @param blockTimestamp
/// @dev Transfer fees earned of the sender to another address. /// @notice Does not transfer the liquidity positions of the sender. /// @param pool The state of the pool. /// @param to The receipient of the transaction fees. /// @param long0Fees The amount of long0 position fees transferrred. /// @param long1Fees The amount of long1 position fees transferrred. /// @param shortFees The amount of short position fees transferrred. /// @param blockTimestamp The current block timestamp. function transferFees(Pool storage pool, uint256 maturity, address to, uint256 long0Fees, uint256 long1Fees, uint256 shortFees, uint96 blockTimestamp) external {
Missing: @param maturity
/// @dev Collects the transaction fees of the pool. /// @dev only liquidity provider can call this function. /// @dev if the owner enters an amount which is greater than the fee amount they have earned, withdraw only the amount they have. /// @param pool The state of the pool. /// @param blockTimestamp The current block timestamp. /// @param long0Requested The maximum amount of long0 positions wanted. /// @param long1Requested The maximum amount of long1 positions wanted. /// @param shortRequested The maximum amount of short positions wanted. /// @return long0Amount The amount of long0 collected. /// @return long1Amount The amount of long1 collected. /// @return shortAmount The amount of short collected. function collectTransactionFees( Pool storage pool, uint256 maturity, uint256 long0Requested, uint256 long1Requested, uint256 shortRequested, uint96 blockTimestamp ) external returns (uint256 long0Amount, uint256 long1Amount, uint256 shortAmount) {
Missing: @param maturity
No. | Description |
---|---|
5-3 | @return missing for function |
The following functions have complete Natspec, with the exception of missing @return statements: |
/// @dev Returns the factory address that deployed this contract. function poolFactory() external view returns (address);
/// @dev Returns the Timeswap V2 Option of the pair. function optionPair() external view returns (address);
/// @dev Returns the transaction fee earned by the liquidity providers. function transactionFee() external view returns (uint256);
/// @dev Returns the protocol fee earned by the protocol. function protocolFee() external view returns (uint256);
/// @dev Get the strike and maturity of the pool in the pool enumeration list. /// @param id The chosen index. function getByIndex(uint256 id) external view returns (StrikeAndMaturity memory);
/// @dev Get the number of pools being interacted. function numberOfPools() external view returns (uint256);
ITimeswapV2PoolFactory.sol: L19-20
/// @dev Returns the fixed transaction fee used by all created Timeswap V2 Pool contract. function transactionFee() external view returns (uint256);
ITimeswapV2PoolFactory.sol: L22-23
/// @dev Returns the fixed protocol fee used by all created Timeswap V2 Pool contract. function protocolFee() external view returns (uint256);
ITimeswapV2PoolFactory.sol: L37-41
/// @dev Creates a Timeswap V2 Pool based on option parameter. /// @dev Cannot create a duplicate Timeswap V2 Pool with the same option parameter. /// @param option The address of the option contract used by the pool. /// @param poolPair The address of the Timeswap V2 Pool contract created. function create(address option) external returns (address poolPair);
ITimeswapV2PoolRebalanceCallback.sol: L8-12
/// @dev When Long0ToLong1, require the transfer of long0 position into the pool. /// @dev When Long1ToLong0, require the transfer of long1 position into the pool. /// @dev The long0 positions or long1 positions will already be minted to the receipient. /// @param data The bytes of data to be sent to msg.sender. function timeswapV2PoolRebalanceCallback(TimeswapV2PoolRebalanceCallbackParam calldata param) external returns (bytes memory data);
ITimeswapV2PoolLeverageCallback.sol: L16-18
/// @dev Require the transfer of short position into the pool. /// @param data The bytes of data to be sent to msg.sender. function timeswapV2PoolLeverageCallback(TimeswapV2PoolLeverageCallbackParam calldata param) external returns (bytes memory data);
ITimeswapV2PoolMintCallback.sol: L16-18
/// @dev Require the transfer of long0 position, long1 position, and short position into the pool. /// @param data The bytes of data to be sent to msg.sender. function timeswapV2PoolMintCallback(TimeswapV2PoolMintCallbackParam calldata param) external returns (bytes memory data);
ITimeswapV2PoolDeleverageCallback.sol: L16-18
/// @dev Require the transfer of long0 position and long1 position into the pool. /// @param data The bytes of data to be sent to msg.sender. function timeswapV2PoolDeleverageCallback(TimeswapV2PoolDeleverageCallbackParam calldata param) external returns (bytes memory data);
/// @title An interface for TS-V2 token system /// @notice This interface is used to interact with TS-V2 positions interface ITimeswapV2Token is IERC1155 { /// @dev Returns the factory address that deployed this contract. function optionFactory() external view returns (address);
/// @dev Returns the position Balance of the owner /// @param owner The owner of the token /// @param position type of option position (long0, long1, short) function positionOf(address owner, TimeswapV2TokenPosition calldata position) external view returns (uint256 amount);
/// @dev burns TimeswapV2Token as per postion and amount /// @param param The TimeswapV2TokenBurnParam function burn(TimeswapV2TokenBurnParam calldata param) external returns (bytes memory data);
ITimeswapV2LiquidityToken.sol: L23-26
/// @dev Returns the position Balance of the owner /// @param owner The owner of the token /// @param position The liquidity position function positionOf(address owner, TimeswapV2LiquidityTokenPosition calldata position) external view returns (uint256 amount);
ITimeswapV2LiquidityToken.sol: L54-59
/// @dev collects fees as per the fees desired /// @param param The TimeswapV2LiquidityTokenBurnParam /// @return long0Fees Fees for long0 /// @return long1Fees Fees for long1 /// @return shortFees Fees for short function collect(TimeswapV2LiquidityTokenCollectParam calldata param) external returns (uint256 long0Fees, uint256 long1Fees, uint256 shortFees, bytes memory data);
Missing: @return data
/// @title ERC-1155 Token Standard, optional enumeration extension /// @dev See https://eips.ethereum.org/EIPS/eip-721 interface IERC1155Enumerable is IERC1155 { /// @dev Returns the total amount of tokens stored by the contract. function totalSupply() external view returns (uint256);
ITimeswapV2Option.sol: L109-110
/// @dev Returns the factory address that deployed this contract. function optionFactory() external view returns (address);
ITimeswapV2Option.sol: L112-113
/// @dev Returns the first ERC20 token address of the pair. function token0() external view returns (address);
ITimeswapV2Option.sol: L115-116
/// @dev Returns the second ERC20 token address of the pair. function token1() external view returns (address);
ITimeswapV2Option.sol: L118-120
/// @dev Get the strike and maturity of the option in the option enumeration list. /// @param id The chosen index. function getByIndex(uint256 id) external view returns (StrikeAndMaturity memory);
ITimeswapV2Option.sol: L122-123
/// @dev Number of options being interacted. function numberOfOptions() external view returns (uint256);
ITimeswapV2Option.sol: L161-169
/// @dev Burn short position. /// Withdraw token0, when long token0 is burnt. /// Withdraw token1, when long token1 is burnt. /// @dev Can only be called before the maturity of the pool. /// @param param The parameters for the burn function. /// @return token0AndLong0Amount The amount of token0 withdrawn and long0 burnt. /// @return token1AndLong1Amount The amount of token1 withdrawn and long1 burnt. /// @return shortAmount The amount of short burnt. function burn(TimeswapV2OptionBurnParam calldata param) external returns (uint256 token0AndLong0Amount, uint256 token1AndLong1Amount, uint256 shortAmount, bytes memory data);
Missing: @return data
ITimeswapV2Option.sol: L184-190
/// @dev Burn short position, withdraw token0 and token1. /// @dev Can only be called after the maturity of the pool. /// @param param The parameters for the collect function. /// @return token0Amount The amount of token0 withdrawn. /// @return token1Amount The amount of token1 withdrawn. /// @return shortAmount The amount of short burnt. function collect(TimeswapV2OptionCollectParam calldata param) external returns (uint256 token0Amount, uint256 token1Amount, uint256 shortAmount, bytes memory data);
Missing: @return data
ITimeswapV2OptionDeployer.sol: L11-16
/// @notice Get the parameters to be used in constructing the pair, set transiently during pair creation. /// @dev Called by the pair constructor to fetch the parameters of the pair. /// @return optionFactory The factory address. /// @param token0 The first ERC20 token address of the pair. /// @param token1 The second ERC20 token address of the pair. function parameter() external view returns (address optionFactory, address token0, address token1);
Notice: @param
statements should be @return
statements
ITimeswapV2OptionFactory.sol: L26-28
/// @dev Get the address of the option pair in the option pair enumeration list. /// @param id The chosen index. function getByIndex(uint256 id) external view returns (address optionPair);
ITimeswapV2OptionFactory.sol: L30-31
/// @dev The number of option pairs deployed. function numberOfPairs() external view returns (uint256);
ITimeswapV2OptionFactory.sol: L35-41
/// @dev Creates a Timeswap V2 Option based on pair parameters. /// @dev Cannot create a duplicate Timeswap V2 Option with the same pair parameters. /// @notice The token0 address must be smaller than token1 address. /// @param token0 The first ERC20 token address of the pair. /// @param token1 The second ERC20 token address of the pair. /// @param optionPair The address of the Timeswap V2 Option contract created. function create(address token0, address token1) external returns (address optionPair);
Notice: @param optionPair
should be @return optionPair
No. | Description |
---|---|
5-4 | Natspec is missing for event |
While the majority of events in the in-scope contracts are preceded by complete Natspec, it is missing for the following event : |
ITimeswapV2LiquidityToken.sol: L13
event TransferFees(address from, address to, TimeswapV2LiquidityTokenPosition position, uint256 long0Fees, uint256 long1Fees, uint256 shortFees);
#0 - c4-judge
2023-02-01T23:06:06Z
Picodes marked the issue as grade-b