Token Balance not changing after simulating swap on uniswap v2

defisolidityuniswapweb3.pyweb3js

Hi I am trying to mock the process of buying and selling token through uniswap v2 router.
I start with a local network fork anvil --fork-url https://mainnet.infura.io/xxx
Then I have to do 2 things under the test account (which has 1,000 eth):

  1. wrap eth by calling deposit
  2. buy $uni token with $weth through swapExactETHForTokens.

The full code is available at https://gist.github.com/reinforcementwonder/a2a26b514ca065c2344be269d4d08824

I give a minimum example here:

import time
from abi import UNISWAPV2_ROUTER_ABI, UNISWAPV2_LP_ABI
from web3 import Account, Web3
from eth_utils import to_checksum_address
from util import Token, account_status_for_tokens_and_pool
# setup our account and chain connection - we will use ganache here
chain_id = 1
rpc_endpoint = "http://127.0.0.1:8545"  # our local ganache instance
web3 = Web3(Web3.HTTPProvider(rpc_endpoint))
account = Account.from_key(
    "anvil-secret-key")

WETH_TOKEN_ADDRESS = "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
UNI_TOKEN_ADDRESS = "0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"

UNI_WETH_POOL_ADDRESS = "0xd3d2e2692501a5c9ca623199d38826e513033a17"

UNISWAP_V2_SWAP_ROUTER_ADDRESS = "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D"

router_contract = web3.eth.contract(
    address=to_checksum_address(UNISWAP_V2_SWAP_ROUTER_ADDRESS), abi=UNISWAPV2_ROUTER_ABI)
# ------------------ SETUP ------------------
WETH = Token(to_checksum_address(WETH_TOKEN_ADDRESS), "WETH", 18)
TARGET_TOKEN = Token(to_checksum_address(UNI_TOKEN_ADDRESS), "UNI", 18)
pool_contract = web3.eth.contract(
    address=to_checksum_address(UNI_WETH_POOL_ADDRESS), abi=UNISWAPV2_LP_ABI)
# ------------------ FINISH SETUP ------------------

# DEPOSIT WETH
eth_to_wrap = Web3.to_wei(10, 'ether')
tx = WETH.contract.functions.deposit().build_transaction({
    'chainId': chain_id,
    "from": account.address,
    'gas': 1_000_000,
    "maxPriorityFeePerGas": web3.eth.max_priority_fee,
    "maxFeePerGas": 500 * 10**10,
    'nonce': web3.eth.get_transaction_count(account.address),
    'value': eth_to_wrap
})
signed_buy_tx = web3.eth.account.sign_transaction(tx, account.key)
tx_hash = web3.eth.send_raw_transaction(signed_buy_tx.rawTransaction)
receipt = web3.eth.wait_for_transaction_receipt(tx_hash)
if receipt and receipt['status'] == 1:
    print(
        f"[WRAP ETH]tx hash: {Web3.to_hex(tx_hash)} confirmed at [{receipt['blockNumber']}]")

print("eth balance before buy", WETH.contract.functions.balanceOf(
    account.address).call()/10**18)

before_buy_eth_balance = web3.eth.get_balance(account.address)/10**18

# prepare the swap function call parameters
buy_path = [WETH.address, TARGET_TOKEN.address]
# amount_to_buy_for =
amount_to_buy_for = Web3.to_wei(1, 'ether')

buy_tx_params = {
    "nonce": web3.eth.get_transaction_count(account.address),
    "from": account.address,
    "chainId": chain_id,
    "gas": 1_000_000,
    "maxPriorityFeePerGas": web3.eth.max_priority_fee,
    "maxFeePerGas": 500 * 10**10,
    "value": amount_to_buy_for,
}
buy_tx = router_contract.functions.swapExactETHForTokens(
    0,  # min amount out
    buy_path,
    account.address,
    int(time.time())+180  # deadline now + 180 sec
).build_transaction(buy_tx_params)

signed_buy_tx = web3.eth.account.sign_transaction(buy_tx, account.key)

tx_hash = web3.eth.send_raw_transaction(signed_buy_tx.rawTransaction)
receipt = web3.eth.wait_for_transaction_receipt(tx_hash)
if receipt and receipt['status'] == 1:
    print(
        f"[BUY] tx hash: {Web3.to_hex(tx_hash)} confirmed at [{receipt['blockNumber']}]")
print("eth balance after buy",
      WETH.contract.functions.balanceOf(account.address).call()/10**18)

However, I find the balance of weth for my account did not change, as reflected in the output:

[WRAP ETH]tx hash: 0xc53e44cbca6fcc6d544ce6128f42ea67b1f39c62a541cb83dfdf78fdb988a4f5 confirmed at [19034035]
eth balance before buy 10.0
[BUY] tx hash: 0x2a99b2c0129464852d0fae56bf9290d7b5f05ac5a9d7aa05187f1d35e56fbefd confirmed at [19034036]
eth balance after buy 10.0

This is really strange. Appreciate anyone can give some advice.

Best Answer

You're almost there. Once you call the deposit() on the WETH contract, your ETH will be converted to WETH which is a ERC20 token. So you should be calling swapExactTokensForTokens() instead of swapExactETHForTokens().

Don't forget approve the router contract on WETH contract before swapping!

Modified part of code will look something like below:

amount_to_buy_for = Web3.to_wei(1, 'ether');
approve_tx_params = {
    "nonce": web3.eth.get_transaction_count(account.address),
    "from": account.address,
    "chainId": chain_id,
    "gas": 1_000_000,
    "maxPriorityFeePerGas": web3.eth.max_priority_fee,
    "maxFeePerGas": 500 * 10**10,
    "value": 0,
}
approve_tx = WETH.contract.functions.approve(
    router_contract, # contract_address
    amount_to_buy_for  # amount_to_swap
).build_transaction(approve_tx_params)

signed_approve_tx = web3.eth.account.sign_transaction(approve_tx, account.key)

approve_tx_hash = web3.eth.send_raw_transaction(signed_approve_tx.rawTransaction)
approval_receipt = web3.eth.wait_for_transaction_receipt(approve_tx_hash)

buy_tx_params = {
    "nonce": web3.eth.get_transaction_count(account.address),
    "from": account.address,
    "chainId": chain_id,
    "gas": 1_000_000,
    "maxPriorityFeePerGas": web3.eth.max_priority_fee,
    "maxFeePerGas": 500 * 10**10,
    "value": 0,
}

buy_tx = router_contract.functions.swapExactTokensForTokens(
    amount_to_buy_for, # amount_in
    0,  # min amount out
    buy_path,
    account.address,
    int(time.time())+180  # deadline now + 180 sec
).build_transaction(buy_tx_params)

signed_buy_tx = web3.eth.account.sign_transaction(buy_tx, account.key)

tx_hash = web3.eth.send_raw_transaction(signed_buy_tx.rawTransaction)
receipt = web3.eth.wait_for_transaction_receipt(tx_hash)
if receipt and receipt['status'] == 1:
    print(
        f"[BUY] tx hash: {Web3.to_hex(tx_hash)} confirmed at [{receipt['blockNumber']}]")
print("eth balance after buy",
      WETH.contract.functions.balanceOf(account.address).call()/10**18)

PS: I'm not familiar with web3py but hope the above snippet makes sense. Just added approval tx before swap and changed the method to swapExactTokensForTokens.

Related Topic