Platform: Code4rena
Start Date: 18/05/2023
Pot Size: $24,500 USDC
Total HM: 3
Participants: 72
Period: 4 days
Judge: LSDan
Id: 237
League: ETH
Rank: 17/72
Findings: 1
Award: $321.72
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: minhquanym
Also found by: 0xStalin, BLACK-PANDA-REACH, Madalad, T1MOH, Udsen, adriro, max10afternoon, rbserver, sces60107
321.7244 USDC - $321.72
All the excess ETH send to make swaps on the JBXBuybackDelegate contract will be stuck forever inside the contract.
_amountToSend
calculated by the Uniswap pool will take a 100% of the sent ETH, which might not be always the case.Coded a PoC to demonstrate this issue
view
function on the JBXBuybackDelegate
contract, just to facilitate the monitoring of the ETH balance that the contract is holding, both, before and after doing a swap.JBXBuybackDelegate
contractfunction buyBackDelegateBalance() external view returns (uint256) { return address(this).balance; }
testDatasourceDelegateSwapIfPreferenceIsToClaimTokens()
in the DelegateUnit.t.sol
test file, basically, we need to call the buyBackDelegateBalance()
function at the beggining and at the end of the test.function testDatasourceDelegateSwapIfPreferenceIsToClaimTokens() public { + // Check the balanceOf the JBXBuybackDelegate.sol contract before the calls! + uint256 buyBackDelegateBalanceBefore = _delegate.buyBackDelegateBalance(); ... ... ... + // Check the balanceOf the JBXBuybackDelegate.sol contract after the calls! + uint256 buyBackDelegateBalanceAfter = _delegate.buyBackDelegateBalance(); }
JBETHPaymentTerminal::pay()
is left on the JBXBuybackDelegate
contract, the reason is because in this PoC there is no an actual payment of WETH tokens to the uni pool, but nevertheless, when the real swaps are executed, the ETH that will be left on the contract will be the difference between the msg.value
sent to JBETHPaymentTerminal::pay()
and the _amountToSend
calculated by Uniswap.Running 1 test for contracts/test/DelegateUnit.t.sol:TestUnitJBXBuybackDelegate [PASS] testDatasourceDelegateSwapIfPreferenceIsToClaimTokens() (gas: 267256) Traces: [267256] TestUnitJBXBuybackDelegate::testDatasourceDelegateSwapIfPreferenceIsToClaimTokens() ├─ [290] JBXBuybackDelegate::buyBackDelegateBalance() [staticcall] │ └─ ← 0 ├─ [0] VM::prank(projectOwner: [0x000000000000000000000000000000000000007B]) ... ... ... ├─ [290] JBXBuybackDelegate::buyBackDelegateBalance() [staticcall] │ └─ ← 1000000000000000000 └─ ← ()
Take as reference the logic on the _mint() function that succesfully returns back the received ETH back to the PaymentTerminal contract
Manual Audit
_amountToSend
), and deduct it from the total msg.value
that was send to jbETHPaymentTerminal().pay()
JBXBuybackDelegate
contract it will be stuck forever since there is no a function to withdraw it to another address.Other
#0 - c4-pre-sort
2023-05-24T16:17:47Z
dmvt marked the issue as duplicate of #42
#1 - c4-judge
2023-06-02T14:26:03Z
dmvt changed the severity to 2 (Med Risk)
#2 - c4-judge
2023-06-02T14:45:30Z
dmvt marked the issue as satisfactory