What you do with your money is your own business - that’s why nothing here is ever advice. However, if you want to YOLO your money into a memecoin, it’s worth reading the source code first. Some things are obvious scams - they might as well come out and say “this is a scam” in all caps. However, you can still be scammed by old-fashioned means, even if the source code is clean.
Today, we are looking at the infamous rugpull scam - no malicious code (or jacket) required. We’ll be looking at the HORSE token on Uniswap V2.
Rugpull
Let’s look at the following token, HORSE. The pool’s address is 0x77A838d43Aa717b5C0eEd82E3A3078560e9429b3
Can you spot the rug pull? Open the dexscreener link and notice the following:
This pool was alive for less than 10 minutes.
The first (and only) liquidity add came at block 18401564. Address ending in 33b03A added 700.00B HORSE and 1.00 WETH. This set a price of 1 WETH == 700B HORSE
Trading happens for about 8 minutes. It’s all buys followed by a selloff from six addresses
33b03A rugs the entire pool at block 18401609, removing 641.34B HORSE for 1.090 WETH
Transaction fees aside, 33b03A made 0.09 WETH profit off of this rugpull. Roughly $200.
Don’t interact with pools that have only one liquidity provider unless they have locked their liquidity.
Don’t interact with pools where the larger liquidity providers haven’t locked their liquidity tokens away for a fixed time period.
Here are some things you might be wondering.
How did the scammer make a profit in WETH by pulling their liquidity?
Why does low liquidity mean the end of the pool?
To answer (1), we need to understand how liquidity and pricing works in Uniswap V2.
Uniswap V2 liquidity pools pair two tokens. It’s the famous tokenA * tokenB = k AMM formula. Price quotes are calculated as the ratio of tokens. I.E. 1 tokenB will buy me tokenA/tokenB of tokenA.
The way k gets set in tokenA * tokenB = k is via liquidity provision. When someone creates a pool, they usually supply it with some liquidity. In the case of the scam HORSE token, the scammer supplied it with 700B HORSE and 1 WETH. So k would be 700B (ignoring token decimal precision for now). The scammer was the only person to supply liquidity to the pool, so they own 100% of the tokens in the pool. That means that at any time, they could choose to remove all of their liquidity, and take all of the tokens.
Note that if they did that immediately, they’d just get back their 700B HORSE and 1 WETH. No profit. They’d actually lose money on the deal, due to fees.
However, recall that the price of assets in the pool depends on the ratio of the two assets. As people trade with the pool, this ratio changes. Buying HORSE adds WETH to the pool and removes HORSE, thereby increasing the price of HORSE relative to WETH.
Note also that buying HORSE (which is worthless outside of this pool) puts WETH into the pool (which still holds value outside of this pool). This means that if the scammer waits for some trades to occur before rugging, then they will receive more WETH than they put into the pull when they pull out all of their liquidity. This is how they can turn a profit (0.09 WETH in this example).
To answer (2), low liquidity makes it nearly impossible to execute trades. You will experience extreme price slippage. This is because the price that your trade executes at is calculated differently from the quote price ratios shown above. (see this excellent resource for more details). In pools with large liquidity, your trade will probably not affect the ratio of the two tokens too much, so the price is closer to the quote price. In pools with low liquidity, even a small trade will cause extreme imbalances, and will likely not even execute.
We can calculate liquidity at any block using the following snippet. It just calls `getReserves` on the pool.
def get_liquidity(block_number):
reserves = pair_contract.functions.getReserves().call(block_identifier=block_number)
return reserves # Returns a tuple (reserveA, reserveB, timestamp)
At block 18401607 - seconds before the rugpull, liquidity was (HORSE, WETH):
Liquidity at block 18401607: [641342741409094395804348315203, 1092675012040400162]
After the rugpull at block 18401609, the liquidity was
Liquidity at block 18401609: [766551193, 1]
Massively lower. Keep in mind both tokens are 18 decimal places, so that’s 1/10e18 WETH, not 1 WETH!
Selling any amount of HORSE would net you at most 1/10e18 WETH, so the pool is effectively dead. It has been rugged.
Conclusion
Be sure to check the number of liquidity providers before using a pool. If only one or two people have provided liquidity, then they own the pool. Also ensure that the providers have locked their tokens using a 3rd party liquidity locking service. There can be cases where a pool has only one provider who has locked all of their LP tokens. In this case, the odds of getting rugged are lower. But you can still be scammed via other means, which we’ll look at in the future.
Until then, stay safe out there.