1

I have been trying to buy tokens on uniswap V2 with we3 py with swapExactETHForTokens function. Every time, I try to execute this method it fails with execution reverted message. Can somebody please help me figure out what I am missing here?

    total_buy_amount_ether = 0.02 # for example
    totalMaxTokenToGet = router_contract.functions.getAmountsOut(
        web3.to_wei(Decimal(total_buy_amount_ether), "ether"),
        [WETH_address_checksum, token_address_checksum],
    ).call()


    # Define minimum amount to get based on slippage we can tolerate.
    total_min_tokens = total_max_tokens - (
        (total_max_tokens * int(max_slippage_percent)) / 100
    )

    buy_tx_params = {
        "nonce": web3.eth.get_transaction_count(metamask_address),
        "from": metamask_address,
        "chainId": int(ethereum_chain_id),
        "maxPriorityFeePerGas": web3.eth.max_priority_fee,
        "maxFeePerGas": 100 * 10**10,
        "value": web3.to_wei(total_buy_amount_ether, "ether"),
    }

    # https://web3py.readthedocs.io/en/latest/transactions.html
    swap_transaction = router_contract.functions.swapExactETHForTokens(
        web3.to_wei(Decimal(total_min_tokens), "wei"),
        [WETH_address_checksum, token_address_checksum],
        metamask_address,
        int(time.time()) + (60 * 3),
    ).build_transaction(buy_tx_params)
    
    
    signed_buy_tx = web3.eth.account.sign_transaction(swap_transaction, wallet_private_key)
    tx_hash=web3.eth.send_raw_transaction(signed_buy_tx.rawTransaction)

    tx_receipt = web3.eth.wait_for_transaction_receipt(tx_hash)

1 Answer 1

2

This looks like a decent script & it should work. What I'd look for is:

  • If your account has enough ETH for the swap
  • If the token that you are trying to get as a result has fees in the contract & and your max slippage is lower than what the target token with fees makes it possible

As an example, this is your script for Goerli that swaps 0.02 ETH for the UNI token via the UniswapV2Router. I tested it and it works.

from web3 import Web3
from decimal import Decimal
import time
import json

web3 = Web3(Web3.HTTPProvider('NODE_ENDPOINT'))

# Replace with your actual values.
metamask_address = 'YOUR_ADDRESS'
wallet_private_key = 'YOUR_PRIVATE_KEY'
ethereum_chain_id = 5
WETH_address_checksum = '0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6' //Wrapped ETH address that's set in UniswapV2Router contract
token_address_checksum = '0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984' //UNI token on Goerli
router_address = '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D' //UniswapV2Router on Goerli
max_slippage_percent = 1 //If you are swapping for a token that has fees/deflection etc, set this to like 10+

with open('routerabi.json', 'r') as f:
    router_contract_abi = json.load(f)

# Initialize contract
router_contract = web3.eth.contract(address=router_address, abi=router_contract_abi)

total_buy_amount_ether = 0.02 # for example
total_max_tokens = router_contract.functions.getAmountsOut(
    web3.to_wei(total_buy_amount_ether, "ether"),
    [WETH_address_checksum, token_address_checksum],
).call()[-1]

# Define minimum amount to get based on slippage we can tolerate.
total_min_tokens = total_max_tokens - (
    (total_max_tokens * int(max_slippage_percent)) / 100
)

buy_tx_params = {
    "nonce": web3.eth.get_transaction_count(metamask_address),
    "from": metamask_address,
    "chainId": int(ethereum_chain_id),
    "maxPriorityFeePerGas": web3.eth.max_priority_fee,
    "maxFeePerGas": 100 * 10**10,
    "value": web3.to_wei(total_buy_amount_ether, "ether"),
}

# https://web3py.readthedocs.io/en/latest/transactions.html
swap_transaction = router_contract.functions.swapExactETHForTokens(
    web3.to_wei(Decimal(total_min_tokens), "wei"),
    [WETH_address_checksum, token_address_checksum],
    metamask_address,
    int(time.time()) + (60 * 3),
).build_transaction(buy_tx_params)

signed_buy_tx = web3.eth.account.sign_transaction(swap_transaction, wallet_private_key)
tx_hash = web3.eth.send_raw_transaction(signed_buy_tx.rawTransaction)

tx_receipt = web3.eth.wait_for_transaction_receipt(tx_hash)

print(tx_receipt)

Goerli is going to be deprecated and Sepolia would have been better but I don't think there's Uniswap infra deployed there. If you need Goerli ETH, you can get some here https://faucet.chainstack.com/

5
  • Thank you so much for taking the time to go through it and test it. I appreciate it. I tried to perform some swaps and it turns out it works well on high liquidity or relatively stable pairs such as WETH-DAI. However, it almost never works when I listen to new PairCreated event and try to buy very small amount of mostly rubbish tokens. The second point that you suggested around fees might be the issue here.
    – user130198
    Jan 18 at 7:51
  • As a follow up, do you think I need to add gas price in the code? I see almost all the examples use gas price but the latest docs on web3 py suggest that maxPriorityFeePerGas and maxFeePerGas should be used.
    – user130198
    Jan 18 at 7:52
  • If you are listening to PairCreated, the slippage would definitely be an issue for quite a number of them as a lot have various fees/reflection mechanics.
    – Ake
    Jan 18 at 11:58
  • As for maxPriorityFeePerGas & maxFeePerGas, you see a lot examples just using the old pre EIP-1559 legacy code. Your example is up to date with maxPriorityFeePerGas & maxFeePerGas and is a better one.
    – Ake
    Jan 18 at 12:01
  • Also, in your PairCreated scenario you might be getting front-run, that'd be a third scenario in addition to the others listed. For example, you are swapping a new token that doesn't have fees in the contract but your tx is getting front-run, the exchange rate changes and your slippage doesn't allow for that & gets reverted. Pretty sure this is also what's happening. Check the blocks where you txs got mined & look for txs in the block position +1 and -1 to yours. eg if your tx is position 10, check for txs at 9 & 11 if they interact with the same token.
    – Ake
    Jan 18 at 12:05

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.