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):
- wrap eth by calling
deposit
- 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, yourETH
will be converted toWETH
which is a ERC20 token. So you should be callingswapExactTokensForTokens()
instead ofswapExactETHForTokens()
.Don't forget approve the router contract on WETH contract before swapping!
Modified part of code will look something like below: