Platform: Code4rena
Start Date: 06/01/2022
Pot Size: $60,000 USDC
Total HM: 20
Participants: 33
Period: 7 days
Judge: LSDan
Total Solo HM: 9
Id: 67
League: ETH
Rank: 23/33
Findings: 3
Award: $195.56
π Selected for report: 0
π Solo Findings: 0
cccz
There is no slippage control on _swapUstToUnderlying of NonUSTStrategy.sol, which expose strategy to sandwich attack.
And since finishRedeemStable lacks access control, anyone can do a sandwich attack by calling the _swapUstToUnderlying function.
function finishRedeemStable(uint256 idx) public override(BaseStrategy) { super.finishRedeemStable(idx); _swapUstToUnderlying(); } ... function _swapUstToUnderlying() internal { uint256 ustBalance = _getUstBalance(); if (ustBalance > 0) { // slither-disable-next-line unused-return curvePool.exchange_underlying(ustI, underlyingI, ustBalance, 0); } }
Manual analysis
Replace 0 in the parameter of exchange_underlying with minout
#0 - naps62
2022-01-11T18:38:41Z
duplicate of #8
#1 - dmvt
2022-01-27T11:42:04Z
duplicate of #7
90.0579 USDC - $90.06
cccz
The mint function of the Depositors contract uses the _safeMint function of the ERC721 contract. And there is a reentrancy vulnerability in the _safeMint function
function _safeMint( address to, uint256 tokenId, bytes memory _data ) internal virtual { _mint(to, tokenId); require( _checkOnERC721Received(address(0), to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer" ); } ... function _checkOnERC721Received( address from, address to, uint256 tokenId, bytes memory _data ) private returns (bool) { if (to.isContract()) { try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, _data) returns (bytes4 retval) { return retval == IERC721Receiver.onERC721Received.selector;
The deposit function of the Vault contract will call the _createDeposit and _createClaim functions, and the mint function of the Depositors contract will be called in the _createClaim function. Because the _transferAndCheckUnderlying function will be called after the mint function to increase the underlying tokens in the contract. The user can reenter the deposit function in the mint function. In the _createDeposit function, since the underlying tokens are less than normal, the localTotalUnderlying variable will be smaller. Later, when the mint function of the Claimers contract is called in the _createClaim function, the user will get more share tokens.
function deposit(DepositParams calldata _params) external { _createDeposit(_params.amount, _params.lockedUntil, _params.claims); _transferAndCheckUnderlying(_msgSender(), _params.amount); } ... function _createDeposit( uint256 _amount, uint256 _lockedUntil, ClaimParams[] calldata claims ) internal { if (_lockedUntil == 0) _lockedUntil = block.timestamp + minLockPeriod; else require( _lockedUntil >= block.timestamp + minLockPeriod, "Vault: lock time is too small" ); uint256 localTotalShares = totalShares(); uint256 localTotalUnderlying = totalUnderlyingMinusSponsored(); uint256 pct = 0; for (uint256 i = 0; i < claims.length; ++i) { ClaimParams memory data = claims[i]; _createClaim( _depositGroupIds.current(), _amount, _lockedUntil, data, localTotalShares, localTotalUnderlying ); pct += data.pct; } ... function _createClaim( uint256 _depositGroupId, uint256 _amount, uint256 _lockedUntil, ClaimParams memory _claim, uint256 _localTotalShares, uint256 _localTotalPrincipal ) internal { uint256 amount = _amount.percOf(_claim.pct); uint256 newShares = _computeShares( amount, _localTotalShares, _localTotalPrincipal ); uint256 claimerId = claimers.mint( _claim.beneficiary, amount, newShares ); uint256 tokenId = depositors.mint(
https://github.com/code-423n4/2022-01-sandclock/blob/main/sandclock/contracts/vault/Depositors.sol#L53 https://github.com/code-423n4/2022-01-sandclock/blob/main/sandclock/contracts/Vault.sol#L160-L163 https://github.com/code-423n4/2022-01-sandclock/blob/main/sandclock/contracts/Vault.sol#L438 https://github.com/code-423n4/2022-01-sandclock/blob/main/sandclock/contracts/Vault.sol#L476
Manual analysis
Use the _mint function of the ERC721 contract in the mint function of the Depositors contract.
#0 - r2moon
2022-01-07T15:46:06Z
15.442 USDC - $15.44
cccz
Open TODOs can point to architecture or programming issues that still need to be resolved.
https://github.com/code-423n4/2022-01-sandclock/blob/main/sandclock/contracts/Vault.sol#L291
https://github.com/code-423n4/2022-01-sandclock/blob/main/sandclock/contracts/Vault.sol#L637
https://github.com/code-423n4/2022-01-sandclock/blob/main/sandclock/contracts/vault/Claimers.sol#L32
Manual analysis
Consider resolving the TODOs before deploying.
#0 - r2moon
2022-01-11T16:06:13Z
#1 - dmvt
2022-01-28T14:42:24Z
duplicate of #96