RageTrade/Core

QuantstampFiles named in the report

Quantstamp reviewed RageTradeCore (RageTrade/Core) on 15 Jun 2022: 15 findings, 0 critical; 13 marked fixed, 2 open.

No open critical findings
Open the reportOpen RageTradeCore’s security record

Report hosted on certificate.quantstamp.com.

Trustblock does not review code.

Findings15

Statuses are the security firm’s own, from its report.

SeverityOpenAcknowledgedFixed
Critical000
High002
Medium002
Low209
HighFunds Drainable to `teamMultisig()`Fixed

Function `ClearingHouse.withdrawProtocolFee()` accepts an arbitrary list of addresses, on which it calls `collectAccruedProtocolFee()` to retrieve amounts to be withdrawn and then subsequently transfers the accumulated amounts of `protocol.settlementToken` from that contract to `teamMultisig()`. As this function is publicly callable and the provided addresses are not checked in any way (i.e. whitelisted) an attacker could deploy a smart contract implementing a function `collectAccruedProtocolFee()` that returns an arbitrary amount and subsequently drain the `ClearingHouse.sol` contract of funds, transferring them to `teamMultisig()`.

HighNo Guarantee that the Global Funding State for All Pools Will Be Updated on `pause()`/`unpause()`Fixed

The protocol can be paused/unpaused by the governance or the team multisig by calling `ClearingHouse.pause()` and `ClearingHouse.unpause()` respectively. During the pause/unpause operation, the global funding state must be updated for all the pools to prevent funding payments from accumulating while the protocol is paused. However, the list of pools whose global funding state will be updated on pause/unpause must be supplied as an argument `uint32[] calldata allPoolIds` to each of these functions. This introduces a manual error risk in which some pools' global funding state is not updated on the pause/unpause operation.

Medium`fixFee` Not Reflected in Liquidation Related OperationsFixed

Liquidation related mechanisms in the protocol can have an additional fee called `fixFee` that are paid to keepers, in addition to the keeper fee. However, the internal functions that handle the liquidation mechanisms (`ClearingHouse._removeLimitOrder()`, `ClearingHouse._liquidateLiquidityPositions()`, and `ClearingHouse._liquidateTokenPosition()`) all pass `0` as the `fixFee` argument, instead of referencing the `_getFixFee()` function (this function currently returns zero but it can be overriden in specific chain implementations).

MediumMulticall Cannot Be Used by Keepers to LiquidateFixed

When users call liquidation related functions in `ClearingHouse.multicallWithSingleMarginCheck()`, the `accountId` variable is always passed as the liquidation target. However, `ClearingHouse.multicallWithSingleMarginCheck()` always enforces the check `ClearingHouse._getAccountAndCheckOwner()` to ensure that `msg.sender` and the variable `accountId` are the same, meaning that the keeper cannot liquidate another account.

Low`VToken.setVPoolWrapper()` Can Be Called by AnyoneFixed

The `VToken` contract has a function `VToken.setVPoolWrapper()` that is used to authorize the `VPoolWrapper.sol` contract so that only it can mint the virtual token. However, this is an external function without permission check, so there is a possibility of the function getting called by another entity after deployment. As of now, this is not an issue since `VToken.setVPoolWrapper()` is called in the same function as the `VToken` deployment (in `RageTradeFactory.initializePool()`). Nevertheless, it is a good security practice to add permission checks on important functions like this.

LowGovernance and Team Multisig Address Transfer Is Finalized Without Requiring Confirmation from the New Governance/Multisig AddressFixed

The governance or team multisig privileges can be transferred to another address simply by calling `Governable.transferGovernance()` or `Governanble.transferTeamMultisig()` functions respectively. These two functions immediately transfer a high level of privileges to new addresses in a single transaction, which can be risky from a security perspective. <br/><br/> A more common pattern for governance or team multisig privilege transfers is to require the new pending addresses to issue an `acceptAdmin()` function call before finalizing the transfer. Note that this pattern is common even with the use of timelocks, such as the [Compound Timelock](https://github.com/compound-finance/compound-protocol/blob/master/contracts/Timelock.sol) contract.

LowInverted Sign in the Funding Rate CalculationFixed

The funding rate calculation in `FundingPayment.getFundingRate()` has an inverted sign because the funding rate is computed with the numerator `int256(realPriceX128) - int256(virtualPriceX128)`, as opposed to the usual formula `int256(virtualPriceX128) - int256(realPriceX128)`. While this inverted sign is corrected by further inverting in `LiquiditionPosition.unrealizedFundingPayment()` and `VTokenPosition.unrealizeFundingPaymment()`, this could lead to other errors in funding rate calculation in future development.

LowLack of Input ValidationsFixed

There are no checks on whether the values being supplied on collateral, pool, or protocol parameter changes are reasonable or not (`ClearingHouse.updateCollateralSettings()`, `ClearingHouse.updatePoolSettings()`, `ClearingHouse.updateProtocolSettings()`). Given the importance of these parameters, it is important to be able to reject unreasonable values. For example, parameter `_removeLimitOrderFee` in `ClearingHouse.updateProtocolSettings()` is unconstrained, leaving users vulnerable to potentially unexpected very high fees.

LowRemoved `LiquidityPosition` Is Still Calculated in `longSideRisk`Fixed

`LiquidityPositionSet.longSideRisk` does not stop even when encountering a removed/uninitialized `LiquidityPosition`.

LowRemoved `LiquidityPosition` Is Still Calculated in `maxNetPosition`Fixed

`LiquidityPositionSet.maxNetPosition` does not stop even when encountering a removed/uninitialized `LiquidityPosition`.

Show 3 more
LowSettlement Token Oracle Always Returning `1`Fixed

The settlement token oracle function `SettlementTokenOracle.getTwapPriceX128()` always returns `1 (X128)`, as a healthy stablecoin value is assumed.

LowToken 1 Is Cast to the `IVToken` InterfaceFixed

On `L323` in `VPoolWrapper.uniswapV3SwapCallback()`, `token1` is cast to `IVToken(vPool.token1())` even though `token1` in the Uniswap V3 pool is always the `VQuoteToken`. It should be `IVQuote(vPool.token1())`. While the two interfaces are currently identical, it may lead to other errors in future development.

LowUse of Unsafe CastsFixed

In L118 of `Protocol.sol` primitive cast operations (`int256(...)`) are used, which are prone for over-/underflows.

Contracts in scope

No deployed address is recorded for this audit.

The report names a repository or files. Open the report to see its scope.

Repository and files the report names (103)

  • contracts/protocol/tokens/VTokenDeployer.sol
  • contracts/libraries/Protocol.sol
  • contracts/test/Uint32L8ArrayTest.sol
  • contracts/test/mocks/UniswapV3PoolMock.sol
  • contracts/lens/SwapSimulator.sol
  • contracts/protocol/tokens/VQuote.sol
  • contracts/test/mocks/ArbSysMock.sol
  • contracts/libraries/SwapMath.sol
  • contracts/test/ClearingHouseTest.sol
  • contracts/test/mocks/ClearingHouseDummy.sol
  • contracts/libraries/SafeCast.sol
  • contracts/libraries/Bisection.sol
  • contracts/libraries/CollateralDeposit.sol
  • contracts/libraries/SignedMath.sol
  • contracts/libraries/GoodAddressDeployer.sol
  • contracts/libraries/TickExtended.sol
  • contracts/libraries/VTokenPositionSet.sol
  • contracts/libraries/Uint48.sol
  • contracts/protocol/clearinghouse/ClearingHouse.sol
  • contracts/libraries/Block.sol
  • contracts/test/ClearingHouseExtsloadTest.sol
  • contracts/test/AccountTest.sol
  • contracts/libraries/Account.sol
  • contracts/libraries/SignedFullMath.sol
  • contracts/extsloads/ClearingHouseExtsload.sol
  • contracts/interfaces/clearinghouse/IClearingHouseActions.sol
  • contracts/test/mocks/OracleMock.sol
  • contracts/test/VTokenPositionSetTest.sol
  • contracts/test/mocks/VPoolWrapperMock2.sol
  • contracts/protocol/wrapper/VPoolWrapper.sol
  • contracts/libraries/WordHelper.sol
  • contracts/test/BisectionTest.sol
  • contracts/interfaces/IInsuranceFund.sol
  • contracts/test/mocks/AccountProtocolInfoMock.sol
  • contracts/test/LiquidityPositionTest.sol
  • contracts/interfaces/IGovernable.sol
  • contracts/interfaces/IVQuote.sol
  • contracts/test/mocks/RealTokenMock.sol
  • contracts/test/BatchedLoopTest.sol
  • contracts/test/FundingPaymentTest.sol
  • contracts/test/ExtsloadTest.sol
  • contracts/test/VTokenPositionSetTest2.sol
  • contracts/utils/TimelockControllerWithMinDelayOverride.sol
  • contracts/interfaces/IVToken.sol
  • contracts/libraries/Uint48L5Array.sol
  • contracts/test/CollateralDepositSetTest.sol
  • contracts/interfaces/clearinghouse/IClearingHouseSystemActions.sol
  • contracts/libraries/UniswapV3PoolHelper.sol
  • contracts/libraries/LiquidityPositionSet.sol
  • contracts/test/LiquidityPositionSetTest.sol
  • contracts/oracles/ChainlinkOracle.sol
  • contracts/utils/Multicall.sol
  • contracts/utils/constants.sol
  • contracts/test/WordHelperTest.sol
  • contracts/interfaces/IVPoolWrapper.sol
  • contracts/test/mocks/VPoolWrapperMock.sol
  • contracts/libraries/LiquidityPosition.sol
  • contracts/test/Uint48L5ArrayTest.sol
  • contracts/protocol/insurancefund/InsuranceFundDeployer.sol
  • contracts/test/mocks/MockAggregatorV2.sol
  • contracts/libraries/SimulateSwap.sol
  • contracts/libraries/VTokenPosition.sol
  • contracts/utils/Extsload.sol
  • contracts/test/Governable.sol
  • contracts/protocol/insurancefund/InsuranceFund.sol
  • contracts/test/SimulateSwapTest.sol
  • contracts/interfaces/clearinghouse/IClearingHouseStructures.sol
  • contracts/protocol/clearinghouse/ClearingHouseStorage.sol
  • contracts/lens/ClearingHouseLens.sol
  • contracts/interfaces/clearinghouse/IClearingHouseCustomErrors.sol
  • contracts/test/TickExtendedTest.sol
  • contracts/protocol/wrapper/VPoolWrapperDeployer.sol
  • contracts/interfaces/IOracle.sol
  • contracts/test/TimelockControllerWithMinDelayOverrideTest.sol
  • contracts/interfaces/clearinghouse/IClearingHouseView.sol
  • contracts/libraries/TickBitmapExtended.sol
  • contracts/libraries/FundingPayment.sol
  • contracts/protocol/RageTradeFactory.sol
  • contracts/interfaces/IExtsload.sol
  • contracts/libraries/Uint32L8Array.sol
  • contracts/libraries/AddressHelper.sol
  • contracts/protocol/tokens/VToken.sol
  • contracts/interfaces/IClearingHouse.sol
  • contracts/test/mocks/VPoolWrapperMockRealistic.sol
  • contracts/utils/Governable.sol
  • contracts/test/Uint48Test.sol
  • contracts/oracles/SettlementTokenOracle.sol
  • contracts/test/PriceMathTest.sol
  • contracts/protocol/clearinghouse/ClearingHouseDeployer.sol
  • contracts/test/SignedMathTest.sol
  • contracts/libraries/PriceMath.sol
  • contracts/utils/ProxyAdminDeployer.sol
  • contracts/protocol/clearinghouse/ClearingHouseView.sol
  • contracts/interfaces/clearinghouse/IClearingHouseEnums.sol
  • contracts/libraries/BatchedLoop.sol
  • contracts/test/GoodAddressDeployerTest.sol
  • contracts/protocol/tokens/VQuoteDeployer.sol
  • contracts/test/mocks/RealTokenMock1.sol
  • contracts/test/SignedFullMathTest.sol
  • contracts/test/VTokenPositionTest.sol
  • contracts/test/mocks/SettlementTokenMock.sol
  • contracts/interfaces/clearinghouse/IClearingHouseEvents.sol
  • contracts/interfaces/clearinghouse/IClearingHouseOwnerActions.sol

Part of RageTradeCore’s security record

RageTradeCore
Audits1 audit by 1 firmLast audit Jun 2022, by Quantstamp.
Critical findingsNo open critical findingsIn 1 report.
Open RageTradeCore’s security record

Security firm

Quantstamp

236 projects reviewed · 332 reports · latest Oct 2026

See Quantstamp’s audits

Something wrong on this page? A missing report, a wrong date, a finding that was fixed since. Tell us and we check it against its source.

Tell us