z0r0z / helios

Token-based Exchange

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

recommendation: change how ETH is handled in pairs

wschwab opened this issue · comments

Hi there! We were reviewing Helios on a a Solidity Friday (link to shameless self-plug here), and had an observation we'd like to share. First I just wanted to say that this is a really cool idea, and we really enjoyed reading through it.

As of now, when ETH is sent while creating a pair, ETH becomes the token0 of the pair, and is represented by the zero address. This assignment is done after token0 and token1 are sorted, ensuring that token0 is the address with the higher number (source). This means that in the current structure, the following considerations must be made when creating pairs with ETH:

  • two addresses must be passed into the function (source)
  • the lower of these addresses will be the token paired with ETH
  • the higher will be replaced by the zero address, which is used when ETH is in a pair

This would make the "best" address to pass in with the token address to pair with ETH 0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF, since it will be higher than any other address passed in, and will then be replaced with the zero address for ETH. I'd like to recommend changing this. For one, it makes ETH pairs behave differently than all other pairs - in all other pairs the higher address is token0, whereas since ETH is represented by the zero address, in ETH pairs it will always be lower address first. In addition, 0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF is just a bit of a pain to work with.

One possibility would be replacing token1 with the zero address to represent ETH instead of token0. This would make it possible to pass in the zero address as one of the token addresses, which is easy to use both in Solidity (address(0)) and in helper libraries in other languages (eg ethers.constants.AddressZero in ethers.js). It will always be sorted as token1 too, and ETH pairs will behave just like any other pair in terms of ordering by the higher address first.

This would mean taking this and replacing it with:

// if ETH attached, overwrite token0 and token0amount
if (msg.value != 0) {
    token1 = address(0);
    token1amount = uint112(msg.value);
    token0._safeTransferFrom(msg.sender, address(this), token0amount);
} else {
    token0._safeTransferFrom(msg.sender, address(this), token0amount);
    token1._safeTransferFrom(msg.sender, address(this), token1amount);
}

I wanted to open this as an issue instead of a PR just because I figured you may have additional reasons why you did things this way, but would be happy to make a PR myself if you'd like.

Cheers!

commented

would it help if we make the smaller address token0?

I think that would also work, the main reason I suggested this way was since I didn't know how big of a pain it would be to change that. I had also thought at the time that Uniswap also did larger first, but just went and looked it up (here) and it looks like Uniswap is also lower first, so then I'd think it's better to go that way just to keep consistency between platforms too.