A few days ago, we found an unusual trade on the block chain. It was a trade filled on the 0x v1 Exchange, trading MANA for WETH, listing OpenRelay as the relayer. The first thing that made us tilt our heads was that this order didn’t actually pay any fees. At first we thought someone had found a way to get an order into our order book without the required fees. But when we looked up the order on our order book, it wasn’t there.

We’re not sure exactly how this happened, but we know the broad strokes. When someone creates a 0x order, they can list anything they want for the following parameters:

But while it’s possible to create an order with any parameters you like, relayers generally constrain what orders they will accept on their order book. As a condition of listing an order, most relayers require that orders:

Given these constraints many people assume that if a relayer is listed as the fee recipient on an order, that the relayer was involved in the transaction. This is not necessarily the case, and appears to not have been the case with the weird transaction we mentioned above. With 0x orders, anyone could list any address they like as the fee recipient for a given order, and it’s not necessarily the case that the fee recipient has any knowledge of the order or has approved it in any way.

Gaslighting With Embiggen

Rather than just write a blog post laying out the fact that you shouldn’t assume an order listing a relayer as the fee recipient actually has anything to do with the relayer, we decided we’d exploit the issue to draw some attention to it, while trying not to cause any real problems.

So we set out to make a bunch of Embiggen trades that purport to take place on relayers who don’t even list Embiggen, and then a few other weird trades.

We used massive to create our orders. We created a CSV enumerating:

For the feeRecipient column, we used each of the relayers on the 0x relayer registry. We used the following Massive pipeline to generate signed orders:

massive 0x csv --input=orders.csv | \
massive 0x expiration --duration 864000 | \
massive 0x setExchange --mainnet | \
massive 0x setSalt | \
massive 0x sign --replace-on-mismatch /path/to/private-key > orders.massive

So now we have a file several valid 0x orders, offering MBGN for NOT, pretending to be from every 0x relayer in the registry. Note that most of these relayers would not have accepted our order if we’d uploaded it; our orders violate their constraints. But the 0x exchange contract will consider them to be perfectly valid, and we expected that several other services would incorrectly assume that those trades actually went through their respective relayers.

We bundled those orders up in a script, and executed them all in one batch transaction.

Then we checked various DEX tracking sites.

Here’s Etherscan’s DEX tracker:

Etherscan DEX Tracker

And here’s 0xtracker.com:

0xTracker.com

Both trackers attributed the trades to relayers such as RadarRelay, Tokenlon, TokenJar, TheOcean, Star Bit, ERC dEX, LedgerDex, Shark Relay and more.

We checked several of the relayers’ own historical trades reported, and none of them reported the MBGN/NOT trades, presumably because they don’t support MBGN/NOT as a token pair. We’re curious what would have happened if that had been a false trade of a pair they actually supported, but we don’t have an answer to that.

Implications

Now, we traded MBGN for NOT precisely because nobody was going to attribute any value to these trades. But what if we had filled orders of MBGN for a more valuable token like WETH or DAI?

There are a number of services out there that uses completed DEX trades as a source of pricing information. For example, coinmarketcap.com watches RadarRelay and DDEX for trading volume. Presumably there are traders out there also pulling pricing information based on trades attributed to these relayers.

If people assume that executed trades attributed to reputable DEXes are indicators of real trading volume for a token pair, they might decide to trade based on that information. For example if we listed a bunch of MBGN on OpenRelay at a price of 1 DAI/MBGN, then created a bunch of fake trading volume on RadarRelay at 10 DAI/MBGN (even though RadarRelay doesn’t have a DAI/MBGN market), someone might decide that OpenRelay’s 1 DAI/MBGN orders were a good price, even though there’s nowhere they could actually sell at that price.

Now, we’re just speculating that people would be willing to trade based on our fake trading volume, but given the services above that attribute our fake orders to their corresponding DEXes, we suspect there’s a non-zero chance people would consider our trades when evaluating token prices.

Pricing

Getting accurate pricing on a decentralized system is hard. It’s generally impossible to tell if trading volume is real, or just individuals trading between their own accounts. As we’ve shown here, it’s even possible to misattribute trades to a DEX that had nothing to do with the trade.

This is a big part of the reason OpenRelay tries to avoid pricing related questions. We don’t want our users to take our word on the market price of an asset. We’ll give you orders that can be filled at a certain price, but we don’t offer any APIs that provide a wider market view of an asset’s price. It’s also a big part of why we charge a flat fee — so that we don’t have to figure out how much an asset is worth so we can charge a percentage.

What do we do about it?

The first thing is to be very cautious of using on-chain transactions as sources of pricing information. They could just be people trading with themselves to shore up trading volume, and you can’t even assume that the DEX they’re supposed to be trading through is involved in the transaction.

Beyond that, there are some steps tracking tools like 0xtracker.com and Etherscan’s DEX Tracker could take to report a bit more accurately.

The 0x Standard Relayer API provides an /asset_pairs endpoint where you can find out what token pairs they accept. If a relayer doesn’t accept a given token pair, trades in that token pair probably shouldn’t be attributed to that relayer.

Additionally, some relayers use an order matching model, where either the takerAddress or senderAddress fields must correspond to the relayer; we saw DEX tracking tools attribute orders to those relayers even when those fields didn’t match, which would be a good indication that the orders should be treated as suspect.

Finally, there’s also an /order/HASH endpoint in the Standard Relayer API. On OpenRelay, that endpoint will provide order information about a specified order even if the order has been filled. Other relayers may drop records for filled and expired orders, but if fake orders become a real problem, providing that as a way for tracking services to check that an order really came from a given relay might be a good option.

If we want to have strong guarantees that a given relayer was actually involved in a transaction we would need to have the relayer sign the order to indicate their involvement. This isn’t without trade-offs however, as it would take gas to verify the relayer’s signatures, and is otherwise unnecessary for filling an order.