VirtuSwap Disclosed Report

Bug bounty report VirtuSwap Smart Contract

Stealing funds using virtual pools with multicall

Company
Created date
Jan 20 2023

Target

https://github.com/Virtuswap/v1-core/tree/main/contracts

Vulnerability Details

The function _update in vPair.sol only sets _lastPairBalance0 and _lastPairBalance1 once per block, although it is possible to execute many swaps in one block (even easier with multicall). These balances are then used in the method getLastBalances() in vPair, which is used by getVirtualPoolBase in vSwapLibrary.sol, which leads to wrong balances in the returned vPool. This results in the calculation of wrong swap rates. An attacker can call swapReserveExactOutput in vRouter.sol multiple times. In the swapping process A -> C using the pairs AB and BC, the balances in pair AB will only get updated once per block, while BC will use the correct balances. This can be exploited by an attacker in the following way:

Use multicall to make these swaps in a single transaction: -> Swap B -> A (lastBalance will not change anymore in the AB-pair) -> Swap C -> B (last Balance will not change anymore in the BC-pair) -> Perform as often as possible (A->C using B as a common token, A->B using C as a common token)

After the transaction, the attacker will have more tokens then before, having stolen the funds from the DEX.

The bug can be easily fixed by using vPair.getBalances() instead of vPair.getLastBalances() in getVirtualPoolBase().

Validation steps

Simple rename the provided script to '7_exploit.test.ts' and put it in the test-directory and run the test. It uses the deployPools-fixture from the GitHub-repository and performs the exploit using the tokens A, B and C.

Attachments

hidden
CommentsReport History
Comments on this report are hidden
Details
Statedisclosed
Severity
Critical
Bounty$5,000
Visibilitypartially
VulnerabilityBlockchain
Participants (6)
company admin
triage team
manager
manager
author