Platform: Code4rena
Start Date: 16/12/2021
Pot Size: $100,000 USDC
Total HM: 21
Participants: 25
Period: 7 days
Judge: alcueca
Total Solo HM: 12
Id: 66
League: ETH
Rank: 7/25
Findings: 3
Award: $4,034.67
π Selected for report: 8
π Solo Findings: 0
pauliax
function wrap can be called by anyone. It accepts arbitrary _from and _to, and transfers 'from', and mints 'to'. A malicious actor can transfer from other users that have approved the contract before, e.g. an EOA user will need to execute 2 txs: first, approve and then wrap, so an attacker can monitor the mempool and backrun the approval tx. Also, a common practice is to approve more (or even unlimited) amounts, so such users will also lose their tokens.
A simple solution would be to remove _from parameter and use msg.sender instead.
#0 - kingyetifinance
2022-01-07T06:46:55Z
Duplicate #58
#1 - alcueca
2022-01-15T06:41:41Z
Duplicate #208
π Selected for report: pauliax
531.2947 USDC - $531.29
pauliax
Deleting a struct that contains a mapping will not delete the mapping contents:
delete frontEndSnapshots[_frontEnd];
So when a mapping is re-initialized, it will have old values of this mapping.
Here is a simplified smart contract that demonstrates this issue in practice: https://gist.github.com/pauliax/67bc74982a78d28e94a175cf692830fb
#0 - kingyetifinance
2022-01-05T17:51:07Z
@LilYeti: We are not intending to use the frontends feature of this contract, and thus it is out of scope. Since we didn't really mention this anywhere, if it is accepted anyway it would be severity 1 since the realistic loss of funds is not well defined.
#1 - alcueca
2022-01-16T06:43:15Z
Agree with the sponsor.
143.4496 USDC - $143.45
pauliax
contract ERC20_8 does not update _totalSupply on _mint/_burn, so it always remains 0.
Increase total supply on mint and decrease on burn.
#0 - kingyetifinance
2022-01-05T17:38:48Z
Duplicate #128
#1 - alcueca
2022-01-14T21:48:53Z
Duplicate of #259
#2 - alcueca
2022-01-15T15:36:39Z
Assets are not a risk, code is incorrect as to spec. Low severity.
π Selected for report: pauliax
531.2947 USDC - $531.29
pauliax
modifier exists(address _collateral) { if (validCollateral.length != 0 && validCollateral[0] != _collateral) { require(collateralParams[_collateral].index != 0, "collateral does not exists"); } _; }
if validCollateral.length == 0, then the execution will continue as if the _collateral exists.
The sponsor confirmed that this behavior is not expected, although there should never be a situation where validCollateral.length is 0.
#0 - 0xtruco
2022-01-11T11:48:50Z
Changing to level 0 bug and acknowledged, since this function doesn't mean anything if no collateral is in the whitelist anyway. Saved some gas by doing this as well since this function is actually run quite often.
#1 - alcueca
2022-01-15T16:31:13Z
Function incorrect as to spec, so low severity is warranted.
π Selected for report: pauliax
pauliax
There are functions that declare to return named variables but actually do not return anything. function _userUpdate declares to return pendingJoeSent, but actually does not return anything, so it always gets a default value of 0. function _sendCollateral should return a boolean value but does not return anything, so it also gets assigned a default value of false.
#0 - kingyetifinance
2022-01-06T07:07:22Z
@LilYeti: This is actually the same issue as #1 where the value it would return should be the transfer success or not. Recommend that these are lumped together.
#1 - kingyetifinance
2022-01-06T07:11:14Z
However it should be fixed. The actual exploit part of it should be lumped with #1 and related but by itself it could be seen as a level 0 bug.
#2 - kingyetifinance
2022-01-10T06:29:28Z
Fixed
#3 - alcueca
2022-01-15T07:28:17Z
Same kind of error as in #94, but not the same issue. Not a duplicate.
π Selected for report: pauliax
531.2947 USDC - $531.29
pauliax
function setAddresses in contract Whitelist is intended to be invoked only once (confirmed with the sponsor) but currently, it has no prevention from being called multiple times.
Maybe this should also be prevented in sYETIToken's setAddresses and ThreePieceWiseLinearPriceCurve's setAddresses.
Prevent repeated access of setAddresses in Whitelist and potentially in sYETIToken and ThreePieceWiseLinearPriceCurve.
#0 - kingyetifinance
2022-01-05T17:45:36Z
@LilYeti: This would be a nice extra check, but is a weird edge case. If owner wallet compromised worse things will happen. Extra checks are useful though, but since this is unlikely and worse things can happen set to 0 severity.
#1 - 0xtruco
2022-01-11T11:58:33Z
#2 - alcueca
2022-01-15T16:39:41Z
Function incorrect as to spec, low severity.
pauliax
There are many error messages that are quite long, e.g.:
"YUSD: Cannot transfer tokens directly to the StabilityPool, TroveManager or BorrowerOps"
Shortening revert strings to fit in 32 bytes will decrease deployment time gas and will decrease runtime gas when the revert condition has been met.
#0 - kingyetifinance
2022-01-06T09:18:33Z
Duplicate #66
43.9157 USDC - $43.92
pauliax
Assigned operations to constant variables are re-evaluated every time:
bytes32 private constant _PERMIT_TYPEHASH = keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); bytes32 private constant _TYPE_HASH = keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"); uint constant public BORROWING_FEE_FLOOR = DECIMAL_PRECISION / 1000 * 5; // 0.5% uint constant public REDEMPTION_FEE_FLOOR = DECIMAL_PRECISION / 1000 * 5; // 0.5% uint constant public MAX_BORROWING_FEE = DECIMAL_PRECISION / 100 * 5; // 5% bytes32 private constant DOMAIN_SEPARATOR_SIGNATURE_HASH = keccak256("EIP712Domain(uint256 chainId,address verifyingContract)");
See https://github.com/ethereum/solidity/issues/9232
Change from 'constant' to 'immutable'.
#0 - kingyetifinance
2022-01-06T09:39:35Z
@LilYeti : Duplicate #175 but unique for BORROWING FEE FLOOR etc.
pauliax
Some contracts, e.g. ERC20_8, WJLP. are compiled with Solidity version >0.8, but still use SafeMath library. It is not necessary, as with this new version safe operations are handled by default.
#0 - kingyetifinance
2022-01-06T09:16:54Z
Duplicate #53
#1 - alcueca
2022-01-15T06:55:42Z
Taking as main
π Selected for report: pauliax
97.5905 USDC - $97.59
pauliax
In function _transfer, shares.to128(); can be cached to skip the same calculation again:
users[from].balance = fromUser.balance - shares.to128(); users[to].balance = toUser.balance + shares.to128();
Same here, the result can be extracted to a constant as it never changes:
(DECIMAL_PRECISION / 2)
π Selected for report: pauliax
97.5905 USDC - $97.59
pauliax
_isBeforeFeeBootstrapPeriod() is re-evaluated again and again inside the loop, although its value could be cached outside the loop and re-used to reduce gas costs.
#0 - kingyetifinance
2022-01-06T09:41:30Z
@LilYeti : In _getTotalVariableDepositFee bops
π Selected for report: pauliax
531.2947 USDC - $531.29
pauliax
condition should be inclusive >= :
if (available > totalClaimed.add(_amount))
#0 - kingyetifinance
2022-01-06T07:05:16Z
@LilYeti: Miniscule edge case that could cause loss of 1 wei of YETI for owners.
#1 - kingyetifinance
2022-01-06T07:05:27Z
Recommend downgrade to severity 0
#2 - alcueca
2022-01-15T16:30:19Z
Function incorrect as to spec, otherwise it would be medium severity.