Platform: Code4rena
Start Date: 07/07/2023
Pot Size: $121,650 USDC
Total HM: 36
Participants: 111
Period: 7 days
Judge: Picodes
Total Solo HM: 13
Id: 258
League: ETH
Rank: 34/111
Findings: 2
Award: $504.75
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: 0xkasper
Also found by: 0xStalin, 0xbepresent, 3docSec, Aymen0909, Co0nan, GREY-HAWK-REACH, Jeiwan, minhtrng, qpzm
163.3108 USDC - $163.31
https://github.com/GenerationSoftware/pt-v5-vault/blob/55dcd65de4436d50967819c2ac313c3910b6f5f3/src/Vault.sol#L480-L482 https://github.com/generationsoftware/pt-v5-twab-controller/blob/1cdf78e87a3d9127f85a3755024f143664643c5e/src/TwabController.sol#L500-L502 https://github.com/generationsoftware/pt-v5-twab-controller/blob/1cdf78e87a3d9127f85a3755024f143664643c5e/src/TwabController.sol#L656-L661 https://github.com/generationsoftware/pt-v5-twab-controller/blob/1cdf78e87a3d9127f85a3755024f143664643c5e/src/TwabController.sol#L24
TwabController.delegateBalance
is related to the probability to get the prize, and Vault.sponsor
can make the others' delegateBalance to 0.
A malicious user can send a small amount of assets to every depositor and be the only prize taker.
Paste this test in VaultDepositTest
below this line.
https://github.com/GenerationSoftware/pt-v5-vault/blob/55dcd65de4436d50967819c2ac313c3910b6f5f3/test/unit/Vault/Deposit.t.sol#L401
I commented the purpose of the code.
function testSponsor_AliceTakesAwayPrizeChanceFromBob() external { // @audit bob deposits $5000 vm.startPrank(bob); uint256 _amount1 = 5000e18; underlyingAsset.mint(bob, _amount1); underlyingAsset.approve(address(vault), type(uint256).max); vault.deposit(_amount1, bob); assertEq(vault.balanceOf(bob), _amount1); assertEq(twabController.delegateBalanceOf(address(vault), bob), _amount1); vm.stopPrank(); // @audit alice sponsors bob with little assets vm.startPrank(alice); uint256 _amount2 = 1; underlyingAsset.mint(alice, _amount2); underlyingAsset.approve(address(vault), type(uint256).max); vault.sponsor(_amount2, bob); vm.stopPrank(); // @audit bob has no chance to get the prize. This should not pass. assertEq(twabController.delegateBalanceOf(address(vault), bob), 0); }
Then run these commands.
cd vault forge test --match-test testSponsor_AliceTakesAwayPrizeChanceFromBob
This changes the probability of getting the prize, because TwabLib.AccountDetails.delegateBalance
is the actual balance recorded in the TwabLib.Account.observations
mapping.
https://github.com/GenerationSoftware/pt-v5-twab-controller/blob/1cdf78e87a3d9127f85a3755024f143664643c5e/src/libraries/TwabLib.sol#L203
https://github.com/GenerationSoftware/pt-v5-twab-controller/blob/1cdf78e87a3d9127f85a3755024f143664643c5e/src/libraries/TwabLib.sol#L119
The observations mapping is used in PrizePool._isWinner
to calculate the winning zone based on _userTwab
.
https://github.com/GenerationSoftware/pt-v5-prize-pool/blob/4bc8a12b857856828c018510b5500d722b79ca3a/src/PrizePool.sol#L864
https://github.com/GenerationSoftware/pt-v5-prize-pool/blob/4bc8a12b857856828c018510b5500d722b79ca3a/src/PrizePool.sol#L928
https://github.com/GenerationSoftware/pt-v5-prize-pool/blob/4bc8a12b857856828c018510b5500d722b79ca3a/src/libraries/TierCalculationLib.sol#L93
Manual review
TwabController.sponsor
had better take an additional input argument uint256 amount
to indicate the amount to sponsor.
Other
#0 - c4-judge
2023-07-14T23:04:53Z
Picodes marked the issue as duplicate of #393
#1 - c4-judge
2023-08-06T10:29:14Z
Picodes marked the issue as satisfactory
#2 - c4-judge
2023-08-06T10:29:29Z
Picodes marked the issue as selected for report
#3 - c4-judge
2023-08-06T10:29:51Z
Picodes marked issue #351 as primary and marked this issue as a duplicate of 351
341.4422 USDC - $341.44
https://github.com/GenerationSoftware/pt-v5-vault/blob/b1deb5d494c25f885c34c83f014c8a855c5e2749/src/Vault.sol#L518 https://github.com/GenerationSoftware/pt-v5-vault/blob/b1deb5d494c25f885c34c83f014c8a855c5e2749/src/Vault.sol#L532
On every withdraw/redeem, assets in the vault will decrease faster than expected and finally, the vault will drain.
Vault._withdraw
assumes _yieldVault.withdraw(_assets, address(this), address(this));
will return the same amount of tokens as _assets
but this is not the case if _yieldVault
is a fee-on-transfer token.
https://github.com/GenerationSoftware/pt-v5-vault/blob/b1deb5d494c25f885c34c83f014c8a855c5e2749/src/Vault.sol#L1026-L1027
Manual review
Calculate the difference of the asset and transfer the amount to the receiver.
+ uint256 assetBefore = IERC20(asset()).balanceOf(address(this)); _yieldVault.withdraw(_assets, address(this), address(this)); + uint256 assetAfter = IERC20(asset()).balanceOf(address(this)); SafeERC20.safeTransfer(IERC20(asset()), _receiver, assetAfter - assetBefore);
Token-Transfer
#0 - c4-judge
2023-07-16T22:12:50Z
Picodes marked the issue as duplicate of #470
#1 - c4-judge
2023-08-07T15:12:08Z
Picodes marked the issue as satisfactory
#2 - c4-judge
2023-08-08T10:10:48Z
Picodes marked the issue as unsatisfactory: Out of scope
#3 - c4-judge
2023-08-12T16:00:29Z
Picodes marked the issue as satisfactory