Skip to content

Commit

Permalink
📚 Ethernaut Research: Exclusive Order Flow & Payable Multicall Safety
Browse files Browse the repository at this point in the history
Add Kwenta Mentorship Research Documents
  • Loading branch information
JaredBorders authored Mar 23, 2024
2 parents 1de65d5 + e2d79e7 commit 0d48db6
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 0 deletions.
32 changes: 32 additions & 0 deletions docs/exclusive-order-flow-mev.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Exclusive order flow potential MEV opportunities

MEV is a measure of the profit a miner (or validator, sequencer, etc.) can make through their ability to arbitrarily include, exclude, or re-order transactions within the blocks they produce.

As part of conditional orders execution process in Smart Margin v3, orders executed by a trusted executor will not undergo on-chain verification (see more details on the [wiki](https://github.com/Kwenta/smart-margin-v3/wiki/Conditional-Orders)), making it less gas-intensive and cheaper.

Auditors pointed out that given the exclusive nature of conditional orders that are marked as only executable by trusted parties, MEV opportunities exist. This document identifies what these might be and solutions to prevent exclusive order flow from being exploited by ourselves.
##
Having exclusive order flow can be a bad thing because the ability to arbitrarily include or exclude a transaction can create MEV. In our case, Kwenta trusted executor could potentially choose to include or exclude specific conditional orders thus creating potential MEV.
In order to extract this MEV, Kwenta would have to act as a trader themselves (or make a third party profitable).

In all of the examples below, we will assume that all orders are executed through the trustedExecutor.

## Exploiting Market price manipulation

Let's say Kwenta opens a long trade on asset A (same logic can be applied for short trades) then proceeds excluding every short order on asset A only accepting long orders. This would impact market price positively, allowing Kwenta to close their trade with profits, thus extracting value from excluding specific orders.

## Exploiting Funding Rates

Let's say that Kwenta opens a short trade on asset B, then proceeds to only accept long orders on this asset (up until maximum OI which does not trigger asymmetric funding rate [sip-354](https://sips.synthetix.io/sips/sip-354/)), making skew long. In this setup, funding goes up, then if every order on asset B is excluded, Kwenta could exploit the funding rate by maintaining their short position.

## Priority fee reordering

Although this is something that would be hard to exploit and that is not currently possible in the current smart contract as we only cover base fees with maxExecutorFee, technically, using all of the maximum fee that can be paid to the executor(uint256 maxExecutorFee) to add a priority fee on top of the base fee could exploit some MEV through a reordering of transactions.

## Risk assessment

The presented MEV opportunities are informative for users to understand how the trusted executor could act as a bad actor but do not represent real risks, as little value would be hard to exploit from these, and Kwenta would immediatly loose its users trust in doing so, which would be detrimental to Kwenta's interests as the protocol generates revenue on transactions fee.

Kwenta uses a trusted executor so that no on-chain verification occurs, making it less gas-intensive and cheaper for the user, this is why the user relies on the trustedExecutor to execute the order only when the off-chain conditions are satisfied.

These MEV opportunities could be alleviated by making contracts immutable, but contracts need to remain upgradeable as Synthetix evolves and some adaptation is required.
40 changes: 40 additions & 0 deletions docs/multicallablepayble.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# MulticallablePayable


The MulticallablePayable [contract](https://github.com/Kwenta/smart-margin-v3/blob/cacb85bd4c913a85c6bc978b1e8cde2585cee19a/src/utils/MulticallablePayable.sol#L7) is Kwenta's Multicall implementation that enables a single call to call multiple methods on itself. It is slightly different from Synthetix [TrustedMulticallForwarder](https://github.com/Synthetixio/synthetix-v3/blob/0591c4cb5d36b6720dbc5b867e87f5274aaa518d/auxiliary/TrustedMulticallForwarder/src/TrustedMulticallForwarder.sol#L8), and this document aims to focus on the key differences between them, as well as presenting alternative options.

## Kwenta MulticallablePayable contract
```
function multicall(bytes[] calldata data)
public
payable
returns (bytes[] memory)
```

`multicall` applies `DELEGATECALL` with the current contract to each calldata in `data`, and store the `abi.encode` formatted results of each `DELEGATECALL` into `results`. If any of the `DELEGATECALL`s reverts, the entire context is reverted,
and the error is bubbled up.

This function is *payable* in order to support multicalls including [EIP7412.fulfillOracleQuery()](https://github.com/Kwenta/smart-margin-v3/blob/cacb85bd4c913a85c6bc978b1e8cde2585cee19a/src/utils/EIP7412.sol).
Inside a delegatecall, `msg.sender` and `msg.value` are persisted (see: https://www.paradigm.xyz/2021/08/two-rights-might-make-a-wrong), and although `EIP7412.fulfillOracleQuery()` is payable and uses `msg.value`, double spending is not possible in the SMV3 Engine context as it's the only function that makes use of `msg.value`.

## Synthetix TrustedMulticallForwarder

A TrustedMulticallForwarder is required because sometimes it is necessary to send multiple commands at the same time from an Externally Owned Account, but EOAs dont support calling more than one function in a transaction.The TrustedMulticallForwarder aggregates results from multiple function calls.
It can be used for Synthetix v3 Account Creation/Permission Granting, or for any adress to send multiple orders at the same time. All transactions should be prepared as a multicall and sent to the `TrustedMulticallForwarder` contracts using `aggregate3Value`.

Unlike Kwenta's `MulticallablePayable`, Synthetix `TrustedMulticallForwarder` includes [ERC-2771](https://eips.ethereum.org/EIPS/eip-2771) trusted forwarder functionality.

Considering we have account abstraction used by our front-end, there is no real point for Kwenta to have ERC-2771 implemented, as meta-transactions can be executed directly by any account without the necessity for trusted relayers or forwarders.

Although we could use Synthetix `TrustedMulticallForwarder`, our own implementation of `MulticallablePayable` is more suited to account abstraction used by frontend and 1ct as we don't need ERC-2771.

## Alternatives

It's important to note that `MulticallablePayable` is adapted from Solady/Solmate Multicallable implementation and that Synthetix `TrustedMulticallForwarder` is derived from [Multicall3](https://github.com/mds1/multicall).

Solady's multicall implementation is the same that `MulticallablePayable`, with the exception that the multicall function is deliberately made non-payable to guard against double spending (see above why we had to make it payable).

Other alternatives of Multicall exists, for instance OpenZeppelin's has a Multicall but it does not directly support value transfers, which does not align with our requirements.

Overall, each solution has its tradeoffs, such as simplicity, features, integration with existing libraries, gas efficiency, and suitability for specific use cases, but Kwenta `MulticallablePayable` implementation seems to be the most suited implementation for our needs, that is reliable as it's derived from well-established projects (Solady/Solmate have lots of forks around the ecosystem), on top of being gas efficient.
Moreover, having our own implementation means it's easier to adapt to new configurations/needs.

0 comments on commit 0d48db6

Please sign in to comment.