Functionality

MEV Protection

Our MEV protection does not simply block >2 trades per block but rather allows 2 trades then reverts further ones only if they change the type of trade from the 2nd. For example, 100 buys in a row can occur. 1 sell then 100 buys can occur. 1 sell, 1 buy, then 1 sell cannot occur.

The goal with this protection isn’t as general as to protect against all “MEV” (arbitrage in general is fine) but rather protect against sandwich attacks specifically.

It doesn’t allow every combination that would likely be safe. For example, 1 buy, 1 sell, then 1 buy would be reverted but wouldn’t be able to be sandwiched. We accept that it’s not perfect in order to keep it simple.

Bootstrapping Liquidity

This is the main benefit to the dex and is talked about at a higher level extensively elsewhere in the documentation. At a low level, what occurs is that a user initially sets: an amount of virtual Ether they want their initial liquidity to have, an amount of virtual tokens they want that Ether to be matched with, and an amount of Ether they’d like to raise for their AMM. We say Ether here but really it’s the native token of the chain, which may change from one chain to another.

The bootstrapping functions initially as a bonding curve. Tokens that are not bought from it cannot be sold into it, so as to avoid a situation where someone tries to sell tokens from elsewhere and there is no longer enough Ether in the pool for everyone to sell. This necessary restriction also functions as our vesting protection. Once enough Ether is raised, the pool turns into a “full” AMM, which essentially just means all vesting restrictions are lifted.

When a user creates a pool and enters the amounts they want to start with and raise, we can calculate how many tokens they must deposit. This amount of tokens equates to the number of tokens that must be sold in the bootstrapping period to raise the required Ether, and the number of tokens that must be matched with the raised Ether when the pool becomes a full AMM.

For example, a user may want their liquidity to be 100 Ether, matched with 100 tokens (so that each token is worth 1 Ether), and they want to raise 10 Ether. To raise 10 Ether they need to sell ~9.1 tokens, then 9.1 tokens will also need to be in the AMM at that point to maintain the same price at a lower liquidity threshold. So upon pool creation the user will need to deposit ~18.2 tokens.

Vesting Protection

Our vesting protection is extremely simple. It doesn’t allow tokens bought from outside of the pool to be sold into it until the bootstrapping period is over. This is helpful to avoid teams from dumping tokens while the bootstrapping is ongoing, but is also a necessity to ensure there aren’t situations where the pool doesn’t have enough Ether to pay people out.

If we did allow selling into the bonding curve with tokens from elsewhere, we would have problems of people not being able to sell because the price would be trying to go below the amount of real Ether the pool owns.

Fees in Ether

Pools take fees from users in Ether, not in tokens and not in liquidity. We do this so that teams creating pools don’t need to sell their tokens or sell their liquidity to profit from trading. This also allows us to easily have Ether for buybacks and burns of tokens and rewarding the development team without needing to sell liquidity from every individual pool.

These fees are withdrawable separately from the pool’s liquidity, similar to Uniswap V3. This is necessary because teams with locked liquidity must be able to profit from trading (once the bootstrapping period has concluded).

Liquidity Locks

Our liquidity locks are unique from what’s currently the norm. Instead of a simple timestamp where funds can be unlocked, teams can withdraw only 25% of tokens every 7 days. The core safety of this strategy is that this amount does not rollover. For example, if you withdraw 25% of your initial liquidity this week, you can withdraw the same amount next week. But if you withdraw 25% this week then wait a year, you can still only withdraw that amount again before needing to wait another week.

We use this method so that users can never be blindsided by a liquidity rug pull. With the current methods a team can simply wait until a lock is over then withdraw all liquidity. With our method users will always be able to see when a team is withdrawing liquidity and will be able to act based on that.

In addition to these locks, liquidity may not be withdrawn before the bootstrapping period is over and 30 days have passed since that point. The pool must be an unrestricted AMM for 30 days before any liquidity is able to be withdrawn.

Takeover Function

This function exists to avoid griefing. Because only one pool can be created for each token (since we only allow a token to be matched with Weth for simplicity’s sake), and that one pool has settings that could affect its performance, there are possible scenarios where a griefer starts a pool that has bad settings to block someone from creating a useful pool.

The griefer could, for example, set the pool so that 1 token is worth 100 virtual Ether and they want to raise 100 Ether. No one would buy the token at this price, and the pool would never be able to turn into an unrestricted AMM.

If a team calls the takeover function they must pay all tokens that are currently in there +10%, and any Ether that the pool was started with. They can then lower the amount of virtual Ether or Ether to be raised, but not make it higher. The reasoning for adding 10% extra is so that there’s a certain cost to the takeover. It generally shouldn’t matter in legitimate scenarios because a griefer will have very few tokens compared to the virtual Ether, but it will matter for someone attempting to use the takeover function to grief a legitimate pool.

If the settings for the bootstrapping were allowed to be raised, a griefer could decide that paying 10% of the pool amount in tokens is worth raising virtual Ether/raise amount to give more trouble to the team.

Last updated