Part I of III: How MetaMask Swap Really Works

Think you know how MetaMask and specifically MetaMask Swap works? In this article, we take you through the inner workings (now with software code!) of what happens when you use MetaMask Swap and help you figure out for yourself if the SEC’s complaint against Consensys has any merit.

DataFinnovation - ChainArgos - 4AC
ChainArgos
6 min readJul 10, 2024

--

“Sure, but where does the meat go?”

Here we will show how MetaMask’s Swap really works. This makes plain that the SEC’s complaint regarding MetaMask Swap being an unregistered broker is not crazy.

We also demonstrate how MetaMask Swap is not open-source software — it is partially open source which is, um, not the same as “open-source.”

This analysis requires using tools beyond just Etherscan, because Etherscan in effect suppresses what is happening here.

So we will use a few different explorers.

Starting with a Sample Swap

We are going to look at swap 0x66faafe68a2bc3ab0bca75fa84a50dfeca263789ad176d8411c7ad6fa17039f9 where 0x1aE2B2b7bd085215604a94aF9c900eCb81F0356e sold ~890k HOPPY for ~0.052 ETH via MetaMask Swap using the oneInchV5FeeDynamic execution strategy.

We call it an “execution strategy” while MetaMask calls it an “aggregator.”

Whatever.

It is the algorithm that the user told their broker to use to execute this order to sell HOPPY.

The Transaction

You can find most of the flows associated with this transaction on Etherscan.

Let’s look:

We can see immediately that the end user contacted, presumably via the MetaMask browser extension or similar, the “Metamask: Swap Router” contract.

The Metamask: Swap Router code is open source and you are welcome to read it.

As we can see on the transaction they called the “swap” function on that contract:

The important bits of the “swap” function are:

And the “swap” function gets called with these inputs:

What the “swap” then does is:

  1. Look up the adapter for the execution strategy.
  2. Send the incoming tokens to the Spender.
  3. Encode a bunch of data which contains approximately the execution instructions and adapter.
  4. Call “swap” on the Spender passing in that encoded execution data.

This feels a bit like a broker doesn’t it?

Note that the mapping from the execution strategy to the adapter is controlled by this address because it is the only one that can call setAdapter on the Router.

That address is a GnosisSafe and, well, you can go check the owners yourself.

So we keep going.

What does “swap” on the Spender do?

Again you can read the code but the key bit is:

This is another indirection scheme.

After some checking that, among other things, the message originates from the MetaMask: Swap Router, “swap” calls the adapter passing as input the execution instructions encoded by the router.

To review, the router took in oneInchV5FeeDynamic and looked up a smart contract address for that execution strategy.

Then the router munged together some input raw data (the data / bytes above) and passed the address plus the data along to the Spender along with the HOPPY tokens to sell.

Now the Spender is going to call the function at that just-looked-up address and pass in this munged data alongside the tokens the user wanted to sell.

What is the adapter address?

The adapter address is at 0x7CDf68CE9A05413Cbb76cb7F80EAF415A826E313.

You can check this yourself by going to etherscan and calling “adapters” with oneInchV5FeeDynamic as the input, and that address IS A CLOSED SOURCE CONTRACT.

But maybe you don’t believe us.

Ok.

Let’s use a much better (in our opinion) explorer when it comes to smart contract interactions.

Then we can see the whole transaction as:

  • Line 0 is the incoming call.
  • Line 5 is sending the HOPPY tokens to the Spender.
  • Line 39 is calling “swap” on the Spender.
  • Line 40 is passing that blob of data off to the 0x7cd contract. Because it is closed source we do not get a great view of what happens inside. But we can see a bit.
  • Line 41 literally tells us the Spender is now the owner of the HOPPY tokens and is delegating execution.
  • Line 45 does the execution and here we can see a bit inside the closed-source action. This does not mean it is open-source — it means we can see MetaMask’s closed-source code calling external functions which are themselves open-source in public:

So the aggregation router clearly chose to use Uniswap V2 here.

Great.

Line 126 then sends the fee off to the MetaMask: DS Proxy contract.

Fee processing is a whole different story. MetaMask gets the fees and we can explore those mechanics another time.

Finally, Line 133 sends the user their ETH.

This narrative skips some details regarding wrapping and unwrapping ETH because it is already too long.

Go check for yourself.

Do You Come Here Often?

This shows how often the Spender is calling this particular closed-source contract:

Suffice to say, the Spender calls the closed-source contract A LOT.

This is how MetaMask Swap works.

There are many such contracts and correspondingly many many such closed-source function invocations.

Here are a few examples:

  • 0x: 0x727fc6c510F5C5dCBA136471b2451baff0bE4078
  • oneInchV3: 0xD2742961d645218FbE0b50227C9b074d4FEC4937
  • 0xFeeDynamic: 0x3d1d55c23dFc759C5Ae48500cA88dDF477b3c9E5
  • pmmFeeDynamicv4: 0x7bBa8Bd42A19DA78326bE908E2cd52604399a748

If you can follow this description you can find more by watching the router’s incoming transactions.

A Review

Here is the workflow for a MetaMask Swap transaction as described above:

  1. User enters order including an execution strategy.
  2. This order is sent to an order router.
  3. Router looks up the execution adapter for that strategy.
  4. Router sends the tokens to sell, adapter address, and incoming order details to a spender contract.
  5. Spender delegates control over the received tokens as required for order execution.
  6. Spender calls a closed-source contract which effects the execution strategy.
  7. Fees are sent from Spender to the “MetaMask Fee Complex”.
  8. Sale proceeds are returned to the user.

If you think this looks similar to the way a broker works you are right.

This is also how a money transmitter works.

Note in particular that steps 4, 5, and 6 look an awful lot like the concepts of “transmittal order” and “transmittal of funds” from here.

If you can publish adapters, call setAdapter on the router and modify the input “data” blob you can do anything you like.

Even if you only have some of that power you can do pretty much anything you like with the input tokens.

This, surely, is a broker.

--

--