Centralization risk
Description and impact
The design of the contract heavily relies on an off-chain backend component, and it trusts a single centralized owner account. There are multiple implications, which we describe in the following paragraphs.
Lack of privilege separation
Only a single owner authority is defined; this implies that the off-chain backend has access to a private key that can perform routine operations (signing data to authorize a position to be opened or closed), as well as critical operations, such as updating the interest rate or even upgrading the contract. This design increases the impact of a backend compromise to a critical level by default. If the backend private key was compromised, there would be a multitude of ways the contracts could be drained of all their assets, including upgrading the contract, deploying malicious vaults, changing the address of the address provider by invoking setAddressProvider
.
Basic operation requires centralized signature
Basic operation of the contract, including opening and closing a position, requires parameters signed from the backend. As such, any backend availability issue (for example, due to a software bug, a hardware or connectivity issue, or a denial-of-service attack) would impact the user's ability to use basic functionality, potentially causing a substantial individual and/or collective loss.
Centralized liquidation
Liquidating a position is an action reserved to the owner of the contract. Liquidity providers cannot trigger liquidation of an undercollateralized position and therefore depend on the reliability of the off-chain backend to act in a timely manner.
Ineffective liquidation-threshold checks
The smart contracts attempt to protect their users against a malicious or compromised backend from liquidating a position unfairly. The safety check is implemented by checking that the payout received by the user is less than 5% the amount the user has committed as down payment in case of a short position, or less than 5% of the principal in the case of long positions.
However, since the route used to perform the swap(s) needed to close the position is generated and signed by the backend, a compromised or malicious backend could generate a route that results in a loss for the user, for example by requesting a swap to an entirely different token and/or recipient. Additionally, since the check is based on the spot price, it is likely possible to manipulate the price to liquidate any position without risk, by means of a sandwich attack. Therefore, the on-chain check trying to prevent unfair liquidations is ineffective against a compromised backend.
Antislippage checks
When opening a position, the pools effectively perform an antislippage check after a swap is performed. This check is performed by asserting that the received amount is greater than a minimum amount provided as part of the signed data describing the position being opened. We note that no such check is performed when closing the position. This potentially enables MEV sandwiching attacks when closing or liquidating a position. However, it is assumed that the backend correctly populates the minAmountOut
field (or alternative equivalent if a market with an API different than Uniswap is used), for all swaps being performed both when opening and when closing a position. At the time of the start of this review, the backend did set antislippage parameters, but there was no option to configure the amount of slippage the user is willing to accept.
Reliance on off-chain--sourced data
The contract performs only limited on-chain enforcement of some security relevant invariants. Some checks are only effective if the signed data describing the position originated by the off-chain backend is correct and was not manipulated by an attacker. For instance, when opening a position, the backend is responsible to provide all the parameters that describe the position being opened, including antislippage parameters, fees, and down payment amount. The parameters are provided as a signed binary string, which is difficult to inspect for correctness.
When opening and closing a position, the data provided by the backend also contains the path to be used to perform the required swaps (collateral for principal or vice versa). However, this functionality is implemented in the most generic way possible, allowing the backend to provide a list of arbitrary addresses that will be called with arbitrary calldata and arbitrary ETH value. While this design choice allows for great flexibility, it also greatly increases the potential attack surface and makes a security analysis much harder.
Recommendations
Implement separate roles for separate operations to limit the impact of a backend compromise. Reduce the dependency on the off-chain backend and add more verification logic on the contracts.
Remediation
Lack of privilege separation
This issue has been acknowledged by Wasabi, and a fix was implemented in commit 73faeca1↗.
Wasabi implemented separate roles for the pools, by introducing a new PerpManager contract which tracks the following user roles:
LIQUIDATOR_ROLE
is required to liquidate ordersORDER_SIGNER_ROLE
is required to submit new ordersADMIN_ROLE
is required to perform other administrative actions (upgrading contracts, adding vaults)
The team communicated they intend to implement the following key and role management plan.
Only one account will be assigned the admin role; the account will be a Gnosis safe multisig, associated to three or more private keys controlled by members of the development team. The wallet will be configured to require approval from the majority of the controlling private keys to be operated.
The order signer role will be assigned to a separate keypair that will be available to Wasabi backend. No ETH need to be owned by this address. The keypair will be rotated weekly by using the admin keys.
The liquidator role will be assigned to another separate keypair that will be available to a separate internal liquidation server. This server will be separate from the backend and not exposed to the internet. The private key will be rotated bi-monthly.
Basic operation requires centralized signature
Wasabi added a claimPosition
function to both the long and short pool contracts in commit . The function allows to close an existing position without involving the backend. The user is responsible for obtaining the liquidity required to pay back the principal plus interests (and fees, in case of long positions), and for authorizing Wasabi to use transferFrom
to be able to transfer them from the user balance. The claimPosition
function pulls the owed amount of principal from the user, and returns the collateral (minus closing fees in the case of short positions) to the user.
Centralized liquidation
Wasabi acknowledged the considerations and risks posed by centralized liquidation. For the time being, liquidation will remain centralized.
Ineffective liquidation threshold checks
Wasabi acknowledged the risks of this design decision; fully mitigating this issue would require a more decentralized design, including use of an independent on-chain price oracle, and limiting the possibility to provide fully custom routes from the backend. Without those changes, any on-chain liquidation threshold check based only on the amount of assets received after the swap route is executed cannot be effective.
Anti-slippage checks
Wasabi added the possibility to specify the acceptable percentage of price slippage to the frontend UI.
Reliance on off-chain sourced data
Wasabi acknowledged the issue, and opted to keep the current centralized design for the time being. They provided the below comment.
Wasabi’s order creation and liquidations are currently controlled by a single address. This allows us to create the most efficient trade orders and provide the best prices for our users while also protecting our LPs. The centralization of the orders help us block malicious users from creating paths that can drain value from Wasabi. Liquidations are currently only done by the team, but will be available to the public in the near future, allowing MEV opportunities while also increasing the overall health of our protocol.