The purpose of the BuybackDelegate contract is to ensure that a user receives the maximum amount of JBX tokens in exchange for their ETH. The contract compares uniswap quote with a built-in issuance rate and depending on which one is bigger either swaps ETH received from a user on uniswap or mints JBX internally.
The problem is that we receive our quotes offchain from Uniswap SDK and if our pay transaction is left pending for too long the quote may change from least favorable (amount received from the swap < minted amount) therefore user will receive lesser JBX tokens than if the contract would choose the swap path.
Proof of Concept
Let's say Alice pays 1 ETH to the terminal, payParams function is called in which token amount calculated with internal weight and compared to token amount received from the swap
for example weight is 100 -> _tokenCount = 100 JBX, quote = 95 JBX, slippage - 5
100 > 90 - contract chooses to mint tokens
we send the transaction and it stays pending long enough that quote became - 110
when the transaction is finally executed we use old quote - 95 to decide the path and choose the less profitable one - minting instead of swapping.
Tools Used
Manual review
Recommended Mitigation Steps
Add deadline to the metadata
// Unpack the quote from the pool, given by the frontend
(,, uint256 _quote, uint256 _slippage, uint256 deadline) = abi.decode(_data.metadata, (bytes32, bytes32, uint256, uint256, uint256));
if (block.timestamp > deadline) revert deadlineExpired();
Lines of code
https://github.com/code-423n4/2023-05-juicebox/blob/main/juice-buyback/contracts/JBXBuybackDelegate.sol#L155-L170
Vulnerability details
Impact
The purpose of the
BuybackDelegate
contract is to ensure that a user receives the maximum amount of JBX tokens in exchange for their ETH. The contract compares uniswap quote with a built-in issuance rate and depending on which one is bigger either swaps ETH received from a user on uniswap or mints JBX internally. The problem is that we receive our quotes offchain from Uniswap SDK and if ourpay
transaction is left pending for too long the quote may change from least favorable (amount received from the swap < minted amount) therefore user will receive lesser JBX tokens than if the contract would choose the swap path.Proof of Concept
payParams
function is called in which token amount calculated with internalweight
and compared to token amount received from the swaphttps://github.com/code-423n4/2023-05-juicebox/blob/main/juice-buyback/contracts/JBXBuybackDelegate.sol#L156
Tools Used
Manual review
Recommended Mitigation Steps
Add deadline to the metadata
Assessed type
Timing