Platform: Code4rena
Start Date: 05/01/2023
Pot Size: $90,500 USDC
Total HM: 55
Participants: 103
Period: 14 days
Judge: Picodes
Total Solo HM: 18
Id: 202
League: ETH
Rank: 53/103
Findings: 3
Award: $158.13
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: Lirios
Also found by: 0xcm, 0xsomeone, HE1M, Jeiwan, Koolex, bin2chen, c7e7eff, cergyk, dragotanqueray, evan, ladboy233, synackrst, unforgiven, wallstreetvilkas
33.2422 USDC - $33.24
ClearingHouses are deployed for each new loan and settle payments between Seaport auctions and Astaria Vaults if a liquidation occurs.
However, due to the lack of proper data validation in the current implementation, anyone can fake a token and transfer it to the ClearingHouse to settle the auction, which would undermine the clearing process and harm the entire system.
function safeTransferFrom( address from, // the from is the offerer address to, uint256 identifier, uint256 amount, bytes calldata data //empty from seaport ) public { //data is empty and useless _execute(from, to, identifier, amount); }
function _execute( address tokenContract, // collateral token sending the fake nft address to, // buyer uint256 encodedMetaData, //retrieve token address from the encoded data uint256 // space to encode whatever is needed, ) internal { IAstariaRouter ASTARIA_ROUTER = IAstariaRouter(_getArgAddress(0)); // get the router from the immutable arg ClearingHouseStorage storage s = _getStorage(); address paymentToken = bytes32(encodedMetaData).fromLast20Bytes(); uint256 currentOfferPrice = _locateCurrentAmount({ startAmount: s.auctionStack.startAmount, endAmount: s.auctionStack.endAmount, startTime: s.auctionStack.startTime, endTime: s.auctionStack.endTime, roundUp: true //we are a consideration we round up }); uint256 payment = ERC20(paymentToken).balanceOf(address(this)); require(payment >= currentOfferPrice, "not enough funds received"); uint256 collateralId = _getArgUint256(21); // pay liquidator fees here ILienToken.AuctionStack[] storage stack = s.auctionStack.stack; uint256 liquidatorPayment = ASTARIA_ROUTER.getLiquidatorFee(payment); ERC20(paymentToken).safeTransfer( s.auctionStack.liquidator, liquidatorPayment ); ERC20(paymentToken).safeApprove( address(ASTARIA_ROUTER.TRANSFER_PROXY()), payment - liquidatorPayment ); ASTARIA_ROUTER.LIEN_TOKEN().payDebtViaClearingHouse( paymentToken, collateralId, payment - liquidatorPayment, s.auctionStack.stack ); if (ERC20(paymentToken).balanceOf(address(this)) > 0) { ERC20(paymentToken).safeTransfer( ASTARIA_ROUTER.COLLATERAL_TOKEN().ownerOf(collateralId), ERC20(paymentToken).balanceOf(address(this)) ); } ASTARIA_ROUTER.COLLATERAL_TOKEN().settleAuction(collateralId); }
safeTransferFrom()
is a public function without msg.sender
access check, encodedMetaData
is user data, there no check make sure address paymentToken = bytes32(encodedMetaData).fromLast20Bytes()
is the settlementToken
.
so the paymentToken
can be a fake token worth nothing.
when an attacker call safeTransferFrom
before the real auction got settled, the real auction can not settle.
add check make sure paymentToken
= settlementToken
#0 - c4-judge
2023-01-24T07:45:29Z
Picodes marked the issue as duplicate of #564
#1 - c4-judge
2023-02-15T07:28:21Z
Picodes marked the issue as satisfactory
#2 - c4-judge
2023-02-23T21:03:28Z
Picodes changed the severity to QA (Quality Assurance)
#3 - c4-judge
2023-02-24T10:37:08Z
This previously downgraded issue has been upgraded by Picodes
#4 - c4-judge
2023-02-24T10:39:25Z
Picodes marked the issue as not a duplicate
#5 - c4-judge
2023-02-24T10:40:16Z
Picodes marked the issue as duplicate of #521
🌟 Selected for report: rbserver
Also found by: 0Kage, 0xcm, bin2chen, caventa, csanuragjain, synackrst, unforgiven
39.0944 USDC - $39.09
In the current implementation, PublicVault.sol#minDepositAmount()
is intended to prevent token deposits that are too small. However, in ERC4626-Cloned.sol#deposit()
, the minDepositAmount
is incorrectly used to compare with the number of shares obtained from this deposit to confirm compliance with the minimum deposit requirement, which does not match the return unit of PublicVault.sol#minDepositAmount()
.
Due to the features of PublicVault
, as profits increase, share prices will continue to rise. Under high share prices, the current implementation will continue to increase the minimum deposit amount, preventing more and more small investors
function minDepositAmount() public view virtual override(ERC4626Cloned) returns (uint256) { if (ERC20(asset()).decimals() == uint8(18)) { return 100 gwei; } else { return 10**(ERC20(asset()).decimals() - 1); } }
function deposit(uint256 assets, address receiver) public virtual returns (uint256 shares) { // Check for rounding error since we round down in previewDeposit. require((shares = previewDeposit(assets)) != 0, "ZERO_SHARES"); require(shares > minDepositAmount(), "VALUE_TOO_SMALL"); // Need to transfer before minting or ERC777s could reenter. ERC20(asset()).safeTransferFrom(msg.sender, address(this), assets); _mint(receiver, shares); emit Deposit(msg.sender, receiver, assets, shares); afterDeposit(assets, shares); }
Given:
asset
= USDCminDepositAmount
= 10**5 (0.1 USDC)Alice call minDepositAmount()
got 100,000
Alice call deposit()
try deposit 200,000
, tx revert with VALUE_TOO_SMALL
Consider Change to:
function deposit(uint256 assets, address receiver) public virtual returns (uint256 shares) { // Check for rounding error since we round down in previewDeposit. require((shares = previewDeposit(assets)) != 0, "ZERO_SHARES"); require(assets > minDepositAmount(), "VALUE_TOO_SMALL"); // Need to transfer before minting or ERC777s could reenter. ERC20(asset()).safeTransferFrom(msg.sender, address(this), assets); _mint(receiver, shares); emit Deposit(msg.sender, receiver, assets, shares); afterDeposit(assets, shares); }
#0 - c4-judge
2023-01-25T14:35:13Z
Picodes marked the issue as duplicate of #588
#1 - c4-judge
2023-01-25T15:28:49Z
Picodes marked the issue as not a duplicate
#2 - c4-judge
2023-01-25T15:29:59Z
Picodes marked the issue as duplicate of #486
#3 - c4-judge
2023-02-21T22:13:52Z
Picodes marked the issue as satisfactory
85.8039 USDC - $85.80
If the asset is WBTC, under the current design, the minDepositAmount will be 0.1 WBTC, valued more than 2000 US dollars, which is a excessively high minimum single investment amount for most investors, seriously affecting the efficiency of fundraising investment.
function minDepositAmount() public view virtual override(ERC4626Cloned) returns (uint256) { if (ERC20(asset()).decimals() == uint8(18)) { return 100 gwei; } else { return 10**(ERC20(asset()).decimals() - 1); } }
WBTC decimals is 8
, minDepositAmount()
for WBTC will be 10**7 wei
worth more than 2000 USD
consider add a storage minDepositAmount
in VIData
, and let owner set it
#0 - c4-judge
2023-01-25T15:02:41Z
Picodes marked the issue as duplicate of #367
#1 - c4-judge
2023-02-23T07:32:32Z
Picodes marked the issue as satisfactory