Platform: Code4rena
Start Date: 09/12/2022
Pot Size: $90,500 USDC
Total HM: 35
Participants: 84
Period: 7 days
Judge: GalloDaSballo
Total Solo HM: 12
Id: 192
League: ETH
Rank: 14/84
Findings: 1
Award: $1,588.98
🌟 Selected for report: 1
🚀 Solo Findings: 0
🌟 Selected for report: brgltd
Also found by: 0x4non, 0xNazgul, 0xSmartContract, Aymen0909, Deivitto, IllIllI, chrisdior4, hansfriese, joestakey, rbserver, unforgiven
1588.9763 USDC - $1,588.98
.call
instead of .transfer
to send ether.transfer
will relay 2300 gas and .call
will relay all the gas. If the receive/fallback function from the recipient proxy contract has complex logic, using .transfer
will fail, causing integration issues.
https://github.com/code-423n4/2022-12-tigris/blob/main/contracts/Trading.sol#L588
Replace .transfer
with .call
. Note that the result of .call
need to be checked.
New assets are pushed into the state variable assets
array, at the function BondNFT.addAsset()
.
https://github.com/code-423n4/2022-12-tigris/blob/main/contracts/BondNFT.sol#L352
Lock.claimGovFees()
will iterate all the assets.
https://github.com/code-423n4/2022-12-tigris/blob/main/contracts/Lock.sol#L110-L120
Currently, assets
can grow indefinitely. E.g. there's no maximum limit and there's no functionality to remove assets.
If the array grows too large, calling Lack.claimGovFeeds()
might run out of gas and revert. Claiming and distributing rewards will result in a DOS condition.
Add a functionality to delete assets or add a maximum size limit for assets.
ERC721.mint
.mint
won't check if the recipient is able to receive the NFT. If an incorrect address is passed, it will result in a silent failure and loss of asset.
OpenZeppelin recommendation is to use the safe variant of _mint
.
Replace _mint()
with _safeMint()
.
https://github.com/code-423n4/2022-12-tigris/blob/main/contracts/BondNFT.sol#L313
https://github.com/code-423n4/2022-12-tigris/blob/main/contracts/GovNFT.sol#L56
https://github.com/code-423n4/2022-12-tigris/blob/main/contracts/GovNFT.sol#L70
latestAnswer()
from chainlink is deprecated and can return stale data.
Use latestRoundData()
instead of latestAnswer()
. Also, adding checks for additional fields returned from latestRoundData()
is recommended. E.g.
(uint80 roundID, int256 price,,uint256 timestamp, uint80 answeredInRound) = chainlink.latestRoundData(); require(timestamp != 0, "round not complete"); require(answeredInRound >= roundID, "stale data"); require(price != 0, "chainlink error");
SafeERC20
for ERC20 transfers to ensure compatibility with non-standard tokensThe contracts are using IERC20 from OpenZeppelin. Consider using the SafeERC20. This will ensure compatibility with tokens that don't revert on failure (safemoon and it's forks), and tokens that don't return a boolean on success (USDT, BNB, OMG).
https://github.com/code-423n4/2022-12-tigris/blob/main/contracts/Trading.sol#L676
https://github.com/code-423n4/2022-12-tigris/blob/main/contracts/Lock.sol#L104
It's recommended to execute external calls after state changes, to prevent reetrancy bugs.
Consider moving the external calls after the state changes on the following instances:
https://github.com/code-423n4/2022-12-tigris/blob/main/contracts/Lock.sol#L72-L73
https://github.com/code-423n4/2022-12-tigris/blob/main/contracts/BondNFT.sol#L216-L226
Trading.sol
constructor for the variables _position
, _gov
and _pairsContract
If these variable get configured with address zero, failure to immediately reset the value can result in unexpected behavior for the project.
https://github.com/code-423n4/2022-12-tigris/blob/main/contracts/Trading.sol#L143-L152
Adding events for critical parameter changes will facilitate offchain monitoring and indexing.
https://github.com/code-423n4/2022-12-tigris/blob/main/contracts/Trading.sol#L898-L9051
https://github.com/code-423n4/2022-12-tigris/blob/main/contracts/Trading.sol#L912-L920
https://github.com/code-423n4/2022-12-tigris/blob/main/contracts/Trading.sol#L926-L933
https://github.com/code-423n4/2022-12-tigris/blob/main/contracts/Trading.sol#L939-L941
https://github.com/code-423n4/2022-12-tigris/blob/main/contracts/Trading.sol#L952-L969
https://github.com/code-423n4/2022-12-tigris/blob/main/contracts/Trading.sol#L975-L979
https://github.com/code-423n4/2022-12-tigris/blob/main/contracts/utils/MetaContext.sol#L9-L11
It is crucial to write tests with possibly 100% coverage for smart contracts.
The following functions are not covered:
https://github.com/code-423n4/2022-12-tigris/blob/main/contracts/GovNFT.sol#L206-L216
https://github.com/code-423n4/2022-12-tigris/blob/main/contracts/GovNFT.sol#L311-L313
It is recommended to write tests for all possible code flows.
All the contracts in scope are in scope are floating the pragma version.
Locking the pragma helps to ensure that contracts do not accidentally get deployed using an outdated compiler version.
Note that pragma statements can be allowed to float when a contract is intended for consumption by other developers, as in the case with contracts in a library or a package.
The solidity style guide recommends declaring state variables before all functions. Consider moving the state variables from the GovNFT instance highlighted bellow to the top of the contract.
https://github.com/code-423n4/2022-12-tigris/blob/main/contracts/GovNFT.sol#L263-L269
Another recommendation is to declare internal functions bellow external functions.
The instances bellow highlightes internal above external. If possible, consider adding internal functions bellow external functions for the contract layout.
https://github.com/code-423n4/2022-12-tigris/blob/main/contracts/Trading.sol#L884
https://github.com/code-423n4/2022-12-tigris/blob/main/contracts/Trading.sol#L898-L901
Furthermore, it's also recommended to declare pure and view functions at the end of a a grouping.
https://github.com/code-423n4/2022-12-tigris/blob/main/contracts/Trading.sol#L847
https://github.com/code-423n4/2022-12-tigris/blob/main/contracts/Trading.sol#L857
The value 1 days
can be used directly the the constant on L10 of BondNFT.sol
is not needed.
GovNFT.sol
Consider renaming the variable owner
on L77. Currently it's being shadowed by the library Ownable.owner
.
https://github.com/code-423n4/2022-12-tigris/blob/main/contracts/Trading.sol#L14-L77
https://github.com/code-423n4/2022-12-tigris/blob/main/contracts/StableVault.sol#L9-L13
https://github.com/code-423n4/2022-12-tigris/blob/main/contracts/StableVault.sol#L15-L25
https://github.com/code-423n4/2022-12-tigris/blob/main/contracts/Trading.sol#L96
private constant
consistentlyReplace constant private
with private constant
.
https://github.com/code-423n4/2022-12-tigris/blob/main/contracts/Trading.sol#L95
The solidity documentation recommends a maximum of 120 characters.
Consider adding a limit of 120 characters or less to prevent large lines.
https://github.com/code-423n4/2022-12-tigris/blob/main/contracts/Trading.sol#L178
return named variable
and returning a manual value for the same functionConsider refactoring the function MetaContext._msgSender
to use sender
on L25. E.g. sender = super._msgSender()
. This will make the function more consistent with the usage of the return named variable
declared in the function header.
https://github.com/code-423n4/2022-12-tigris/blob/main/contracts/Trading.sol#L863
Lack of two-step procedure for critical operations leaves them error-prone. Consider adding two step procedure on the critical functions.
Consider adding a two-steps pattern on critical changes to avoid mistakenly transferring ownership of roles or critial functionalities to the wrong address.
https://github.com/code-423n4/2022-12-tigris/blob/main/contracts/BondNFT.sol#L366-L370
Consider adding NATSPEC on all public/external functions to improve documentation.
https://github.com/code-423n4/2022-12-tigris/blob/main/contracts/TradingExtension.sol#L190
https://github.com/code-423n4/2022-12-tigris/blob/main/contracts/GovNFT.sol#L168
https://github.com/code-423n4/2022-12-tigris/blob/main/contracts/GovNFT.sol#L183
https://github.com/code-423n4/2022-12-tigris/blob/main/contracts/BondNFT.sol#L349
Optimizations are being actively developed and are not considered safe. Check the following audit recommending agaist deployments with the optimizer enabled (item 3 in the audit document).
If possible, consider measuring and documenting the tradeoffs when enabling the optimizer.
Consider using only one approach throughout the codebase, e.g. only uint or only uint256.
https://github.com/code-423n4/2022-12-tigris/blob/main/contracts/Trading.sol#L223-L224
https://github.com/code-423n4/2022-12-tigris/blob/main/contracts/Trading.sol#L316-L317
Consider moving the validation on L966 above the conditional on L955 for Trading.setFees()
.
Lock.sol
https://github.com/code-423n4/2022-12-tigris/blob/main/contracts/Lock.sol#L4
OpenZeppelin contracts may be considered draft contracts if they have not received adequate security auditing or are liable to change with future development.
https://github.com/code-423n4/2022-12-tigris/blob/main/contracts/StableToken.sol#L4
https://github.com/code-423n4/2022-12-tigris/blob/main/contracts/StableToken.sol#L7
Consider waiting until the contract is finalized. Otherwise, make sure that development team are aware of the risks of using a draft OpenZeppelin contract and accept the risk-benefit trade-off.
It's possible to name the imports to improve code readability. E.g. import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
can be rewritten as import {IERC20} from “import “@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol”;
https://github.com/code-423n4/2022-12-tigris/blob/main/contracts/Lock.sol#L6
Consider importing OZ first, then all interfaces, then all utils.
https://github.com/code-423n4/2022-12-tigris/blob/main/contracts/Trading.sol#L4-L12
https://github.com/code-423n4/2022-12-tigris/blob/main/contracts/TradingExtension.sol#L4-L8
Consider defining in only one contract so that values cannot become out of sync when only one location is updated.
A cheap way to store constants in a single location is to create an internal constant in a library. If the variable is a local cache of another contract’s value, consider making the cache variable internal or private, which will require external users to query the contract with the source of truth, so that callers don’t get out of sync.
https://github.com/code-423n4/2022-12-tigris/blob/main/contracts/Trading.sol#L95
https://github.com/code-423n4/2022-12-tigris/blob/main/contracts/TradingExtension.sol#L11
https://github.com/code-423n4/2022-12-tigris/blob/main/contracts/BondNFT.sol#L107
https://github.com/code-423n4/2022-12-tigris/blob/main/contracts/BondNFT.sol#L330
Using scientific notation for large multiples of ten will improve code readability.
https://github.com/code-423n4/2022-12-tigris/blob/main/contracts/TradingExtension.sol#L26
#0 - GalloDaSballo
2022-12-27T21:32:37Z
.call
instead of .transfer
to send etherL
L
ERC721.mint
L
L
SafeERC20
for ERC20 transfers to ensure compatibility with non-standard tokensOOS
L
Trading.sol
constructor for the variables _position
, _gov
and _pairsContract
L
NC
R
NC
NC
R
GovNFT.sol
Dispute as it's a function
R
R
private constant
consistentlyNC
NC
return named variable
and returning a manual value for the same functionR
NC
NC
NC
Disputed, optimizer good
NC
R
Lock.sol
NC
R
NC
NC
R
R
R
#1 - c4-sponsor
2023-01-02T17:52:49Z
GainsGoblin marked the issue as sponsor confirmed
#2 - GalloDaSballo
2023-01-22T19:38:08Z
6L 10R 12NC
#3 - c4-judge
2023-01-23T08:47:00Z
GalloDaSballo marked the issue as selected for report
#4 - c4-judge
2023-01-23T09:03:21Z
GalloDaSballo marked the issue as grade-a