Platform: Code4rena
Start Date: 12/04/2023
Pot Size: $60,500 USDC
Total HM: 21
Participants: 199
Period: 7 days
Judge: hansfriese
Total Solo HM: 5
Id: 231
League: ETH
Rank: 116/199
Findings: 1
Award: $22.60
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: juancito
Also found by: 0xAgro, 0xNorman, 0xSmartContract, 0xStalin, 0xTheC0der, 0xWaitress, 0xhacksmithh, 0xnev, 3dgeville, 8olidity, Arz, Aymen0909, BGSecurity, BRONZEDISC, Bauchibred, Bauer, BenRai, ChainHunters, ChrisTina, CodeFoxInc, DedOhWale, DishWasher, EloiManuel, IceBear, Inspex, Jorgect, Kaysoft, LeoGold, LewisBroadhurst, Madalad, MiloTruck, MohammedRizwan, Nyx, Polaris_tow, RaymondFam, SaharDevep, SanketKogekar, Sathish9098, SolidityATL, Udsen, W0RR1O, aria, ayden, berlin-101, bin2chen, catellatech, codeslide, crc32, decade, descharre, evmboi32, eyexploit, fatherOfBlocks, georgits, giovannidisiena, joestakey, karanctf, kodyvim, ltyu, lukris02, m9800, matrix_0wl, mov, mrpathfindr, nadin, niser93, p0wd3r, parlayan_yildizlar_takimi, pavankv, pontifex, qpzm, ravikiranweb3, rbserver, santipu_, shealtielanz, slvDev, tnevler, wonjun, xmxanuel, yixxas
22.6007 USDC - $22.60
During the audit, 3 low and 7 non-critical issues were found.
â„– | Title | Risk Rating | Instance Count |
---|---|---|---|
L-1 | Function transferAndCall is not safe | Low | 1 |
L-2 | Use SafeCast Library | Low | 1 |
L-3 | Check that amount to mint > 0 | Low | 5 |
NC-1 | Order of Layout | Non-Critical | 7 |
NC-2 | Inconsistency when using the number 1000_000 | Non-Critical | 7 |
NC-3 | Inconsistency when using uint and uint256 | Non-Critical | 3 |
NC-4 | Prevent zero transfers | Non-Critical | 2 |
NC-5 | Natspec is incomplete | Non-Critical | 1 |
NC-6 | No space between the control structures | Non-Critical | 1 |
NC-7 | Missing leading underscore | Non-Critical | 33 |
The function transferAndCall
is vulnerable to reentrancy.
Avoid using it.
Downcasting from uint256/int256 in Solidity does not revert on overflow. This can easily result in undesired exploitation or bugs, since developers usually assume that overflows raise errors. SafeCast restores this intuition by reverting the transaction when such an operation overflows.
It is better to use safe casting library.
_mint(_target, usableMint);
_mint(address(reserve), _amount - usableMint); // rest goes to equity as reserves or as fees
_mint(_target, _amount);
_mint(msg.sender, _amount - reserveLeft);
mint(msg.sender, amount);
For example, add the check:
if (usableMint == 0) revert ZeroAmount(); _mint(_target, usableMint);
According to Order of Layout, inside each contract, library or interface, use the following order:
Place modifiers before constructor.
In some cases, 1000000 is used, and in some - 1000_000.
1000000:
return minterReserveE6 / 1000000;
uint256 theoreticalReserve = _reservePPM * mintedAmount / 1000000;
return 1000000 * amountExcludingReserve / (1000000 - adjustedReservePPM); // 41 / (1-18%) = 50
1000_000:
return totalMint * (1000_000 - reserveContribution - calculateCurrentFee()) / 1000_000;
return totalMint * (1000_000 - reserveContribution) / 1000_000;
uint256 reward = (volume * CHALLENGER_REWARD) / 1000_000;
uint256 usableMint = (_amount * (1000_000 - _feesPPM - _reservePPM)) / 1000_000; // rounding down is fine
Stick to one style.
Some variables is declared as uint
and some as uint256
.
There are 4 cases with uint when the rest are with uint256:
event Trade(address who, int amount, uint totPrice, uint newprice);
for (uint i=0; i<helpers.length; i++){
for (uint j=i+1; j<helpers.length; j++){
Stick to one style.
Check that amount to transfer > 0.
Parameter roundingLoss
is missing.
* @notice Decrease the total votes anchor when tokens lose their voting power due to being moved * @param from sender * @param amount amount to be sent */
Add the description for the roundingLoss
.
According to Style Guide, there should be a single space between the control structures if
, while
, and for
and the parenthetic block representing the conditional.
Change:
if(...) { ... }
to:
if (...) { ... }
Internal and private constants, immutables and functions should have a leading underscore.
function collateralBalance() internal view returns (uint256){
function mintInternal(address target, uint256 amount, uint256 collateral_) internal {
function restrictMinting(uint256 period) internal {
function repayInternal(uint256 burnable) internal {
function notifyRepaidInternal(uint256 amount) internal {
function internalWithdrawCollateral(address target, uint256 amount) internal returns (uint256) {
function checkCollateral(uint256 collateralReserve, uint256 atPrice) internal view {
function emitUpdate() internal {
IPositionFactory private immutable POSITION_FACTORY; // position contract to clone
function minBid(Challenge storage challenge) internal view returns (uint256) {
function returnCollateral(Challenge storage challenge, bool postpone) internal {
uint256 private constant MINIMUM_EQUITY = 1000 * ONE_DEC18;
uint32 private constant QUORUM = 300;
uint8 private constant BLOCK_TIME_RESOLUTION_BITS = 24;
uint192 private totalVotesAtAnchor; // Total number of votes at the anchor time, see comment on the um
uint64 private totalVotesAnchorTime; // 40 Bit for the block number, 24 Bit sub-block time resolution
mapping (address => uint64) private voteAnchor; // 40 Bit for the block number, 24 Bit sub-block time resolution
function adjustTotalVotes(address from, uint256 amount, uint256 roundingLoss) internal {
function adjustRecipientVoteAnchor(address to, uint256 amount) internal returns (uint256){
function anchorTime() internal view returns (uint64){
function canVoteFor(address delegate, address owner) internal view returns (bool) {
function calculateSharesInternal(uint256 capitalBefore, uint256 investment) internal view returns (uint256) {
uint256 private minterReserveE6;
function allowanceInternal(address owner, address spender) internal view override returns (uint256) {
uint256 internal constant INFINITY = (1 << 255);
function allowanceInternal(address owner, address spender) internal view virtual returns (uint256) {
function mintInternal(address target, uint256 amount) internal {
function burnInternal(address zchfHolder, address target, uint256 amount) internal {
function createClone(address target) internal returns (address result) {
uint256 internal constant ONE_DEC18 = 10**18;
uint256 internal constant THRESH_DEC18 = 10000000000000000;//0.01
function setOwner(address newOwner) internal {
function requireOwner(address sender) internal view {
Add leading underscores where needed.
#0 - 0xA5DF
2023-04-27T10:52:00Z
L2 is dupe of #393 L1 auotmated
#1 - c4-judge
2023-05-17T03:50:03Z
hansfriese marked the issue as grade-b