1

https://etherscan.io/tx/0x006a041ade99b4715e6578ac968932f47fa9f1be1a676ad66678260ca0fbb6d1

This appears like a vanilla UniswapV2Router02 swap, sending the well-known method swapExactTokensForETHSupportingFeeOnTransferTokens(uint256 amountIn, uint256 amountOutMin, address[] path, address to, uint256 deadline) to the well-known router address 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D.

The amountIn is 0x728e54491c400 which is 2,015,290.0 OC tokens in decimal notation (OC has 9 decimals). OC charges a 1% fee/tax, so the first swap sends 20,152.9 tokens right back to the OC contract, and swaps the remainder, 1,995,137.1 OC, for 0.186567242655743455 Ether. So far, everything as expected.

What throws me for a loop is that immediately after, everything seems to be happening a second time!

The event logs ( https://etherscan.io/tx/0x006a041ade99b4715e6578ac968932f47fa9f1be1a676ad66678260ca0fbb6d1#eventlog ) show that the sender asks for another, identical swap of 2,015,290.0 OC tokens, again split into 20,152.9 (1%) tax and the remainder, 1,995,137.1 OC, swapped for 0.176161447034409986 Ether.

Question 1: Why am I seeing double double? What's going on here?

Does it have to do with the fact that the miner is Flashbots (see https://etherscan.io/tx/0x006a041ade99b4715e6578ac968932f47fa9f1be1a676ad66678260ca0fbb6d1#statechange )? Is there some setting in Flashbots to execute transactions twice or trice? Where is this setting (number of repeats) visible on Etherscan?

One would assume that everything on the blockchain is public, so where does it say on Etherscan "This swapExactTokensForETHSupportingFeeOnTransferTokens() call is supposed to be executed twice in a row, with identical inputs"?

Question 2: In the end, how many OC tokens were "consumed" in the swap (left the transaction signer's wallet), and how much Ether was received by him in exchange? It appears that the answer is:

2,015,290 + 2,015,290 = 4,030,580 tokens left the signer's wallet.

0.186567242655743455 + 0.176161447034409986 = 0.3627286897 Ether was received back.

All this even though only one swap was defined as call argument?

3 Answers 3

2

Ok so I think I figured it out, studying the token's source code, this is a common scheme to "cash out" taxes/fees charged on every token trade or transfer.

What are taxes/fees? Taxes/fees are a percentage of the transaction value of every transaction back to the token contract. They are paid in tokens, not in ETH.

So when you buy 1,000,000 shitcoins, and tax is currently 10%, it means you get only 900,000 shitcoins and 100,000 shitcoins are sent right back to the token contract which acts as a wallet holding the accumulated taxes.

Token devs justify taxes/fees with "ongoing marketing expenses" for growing the project (whatever...). Taxes are also used as a device to artificially prop up a token's price, by taxing token sales higher during the first hours or days of a launch. You'll think twice before dumping that shitcoin minutes after you bought it, when you stand to lose half or more of your investment to "taxes".

Accumulating all these tokens poses a problem for the token dev, in that he needs to frequently "cash out" his "tax tokens" that accumulate over time.

Why not piggyback on your token holder's transactions and make THEM pay the gas for swapping the dev's accumulated tokens, and also front-run their sells so that you get a slightly higher ETH value for the tokens?

That's exactly what is happening here; as soon as a minimum amount of tax/fee tokens have accumulated, the smart contract swaps the loot into ETH and sends it to the token dev, and it does so BEFORE whatever swap was requested by the token holder, dinging the liquidity pool, causing a slightly lower sale price for the original investor.

In short: It's a system to cash out tax/fee tokens once they have reached a threshold, and make unsuspecting token holders pay the gas for the transaaction, AND also effectively doubling the tax by front-running one's own token holders sell txns.

No judgement though... it's all in the open so buyer beware.

1

Answering your Question 2 Yes you are right the transaction happens twice i have also checked the transaction on Tenderly which debugs the transaction an d swap function has been triggered twice.

1
  • Yes, the identical swap happens twice, just that the first time, the 0.18 ETH go to the contract creator's personal wallet, and it's paid for with tokens that the token contract itself is holding. The token mirrors its holders txns! Due to the first sale worth 0.18 ETH, the LP liquidity is increased by a bit, causing the original token holder's bag, to be sold in the 2nd swap, to be worth only 0.17 ETH. So what is the purpose of this scheme? To "advertise" a 1% tax but in reality, by mirroring its holder's buys and sells, to charge a clandestine 2% tax or even more? And gas is paid by seller!
    – blitter
    Aug 29, 2023 at 13:51
1

I can name a function jklh, then in that function I can put a call to make a swap on one pool, and then a call to make a swap on the other.

If I am a good bot designer I am likely not wasting gas on calling a router function or needing approvals, but I could if wanted make a call to swapExactTokens... at one v2 router, and then again at another.

This doesn't have anything to do with flashbots. Though it is likely one might use them so the opportunity isn't front run by other searchers.

You can use flashbots to bundle transactions, but not to make multiple contract calls in a single transaction, that is done from a contract.

2
  • Right so in the token source ( etherscan.io/token/… ) you can see there's a function manualSwap() external that, in turn, calls Uniswap's swapExactTokens...() - but where and why is it triggered? And whose tokens are swapped? Tokens that the token contract itself was holding? It seems that the aim here is, that the token, using its own funds, mirror all trades that its holders make? WTF...
    – blitter
    Aug 29, 2023 at 12:30
  • 1
    The token calls "swapTokensForEth", which calls swapExactTokensForETHSupportingFeeOnTransferTokens.. Tokens are balance of the contract "tokenBalance=balanceOf(address(this)); ...swapTokensForEth(tokenBalance)" Just looks like tax mechanics.
    – Maka
    Aug 29, 2023 at 14:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.