I am trying to test a code on rinkeby test network and I am trying to buy DAI tokens using WETH tokens. I have weth on my account (0.5) and I have ETH on my account as well (0.1). to sum up. I get an error saying the TRANSFER_FROM_FAILED. after looking at a lot of question and answers online this is the code I got. stuff I tried and do not appear on code since they didn't work are:

  1. use swapExactETHForTokensSupportingFeeOnTransferTokens instead of swapExactTokensForTokens, didn't work
  2. approve the pair address as well as the router (the code shows only approving the router address)

any idea why is this swap failing? here is an example of a fail transaction and the code: https://rinkeby.etherscan.io/tx/0x402fabb51e0bfc1eedf7fcecffa3cc8c134dd8fe80544ccee619fe7dc05a06af

# Enums
class Tokens(Enum):
    WBNB = 1
    BUSD = 2

pancakeSwapRouterContractAddress = '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D' # router has swap method
pancakeSwapFactoryContractAddress = '0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f'
pancakeSwapFactoryABIFile = open('pancakeSwapFactoryABI.json')
pancakeSwapRouterABIFile = open('pancakeSwapRouterABI.json')
IERC20ABIFile = open('ERC20ABI.json')
pancakeSwapFactoryABI = json.loads(pancakeSwapFactoryABIFile.read())
pancakeSwapRouterABI = json.loads(pancakeSwapRouterABIFile.read())
IERC20Abi = json.loads(IERC20ABIFile.read())

# add your blockchain connection information
InfuraUrl = 'https://rinkeby.infura.io/v3/<my-infura-api-key>'
web3 = Web3(Web3.HTTPProvider(InfuraUrl))
web3.middleware_onion.inject(geth_poa_middleware, layer=0)

# set personal account information
privateKeyFilePath = "../key/privateKey.txt" 
privateKeyFile = open(privateKeyFilePath)
privateKey = privateKeyFile.read() # private key will hold my account private key.

# Global Parameters
toeknNameToCheckSumAddressMapping = {
    Tokens.WBNB: "0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c",
    Tokens.BUSD: "0xe9e7CEA3DedcA5984780Bafc599bD69ADd087D56"
routerContract = web3.eth.contract(address=pancakeSwapRouterContractAddress, abi=pancakeSwapRouterABI)
factoryContract = web3.eth.contract(address=pancakeSwapFactoryContractAddress, abi=pancakeSwapFactoryABI)
ethContract = web3.eth.contract(address='0xc778417E063141139Fce010982780140Aa0cD5Ab', abi=IERC20Abi)
transactionCounts = 0
whenToFlushTransaction = 3
minValOfTransaction = 1000
currentDateFile = datetime.utcnow().date
slippage = 0.15

if __name__ == "__main__":
        newTokenAddress = Web3.toChecksumAddress('0xc7AD46e0b8a400Bb3C915120d284AafbA8fc4735') #dai address
        mainTokenAddress = Web3.toChecksumAddress('0xc778417E063141139Fce010982780140Aa0cD5Ab') # weth address
        myAccount = '0x8C64EAA77707cAc8018f34991d3F51E4F810Eb7D'
        AmountInEth = 0.05

        pairAddress = factoryContract.functions.getPair(newTokenAddress, mainTokenAddress).call()

        #get the nonce.  Prevents one from sending the transaction twice
        nonce = web3.eth.getTransactionCount(myAccount)
        deadline = int(time.time()) + 600 # 10 min ahead deadline
        path = [mainTokenAddress, newTokenAddress]
        amountIn = web3.toWei(AmountInEth, 'Ether')
        amounts = routerContract.functions.getAmountsOut(amountIn, path).call()
        isApproved = ethContract.functions.approve(pancakeSwapRouterContractAddress, amountIn).call({'from': myAccount})
        print(f'approved returned: {isApproved}')
        amountOut = int(amounts[1] - (amounts[1] * slippage))
        transaction = routerContract.functions.swapExactTokensForTokens(amountIn, amountOut, path, myAccount, deadline).buildTransaction({
                    'from': myAccount,
                    'gas': 250000,
                    'gasPrice': web3.toWei("5", 'gwei'),
                    'nonce': nonce,
        signedTransaction = web3.eth.account.sign_transaction(transaction, privateKey)
        tx_token = web3.eth.send_raw_transaction(signedTransaction.rawTransaction)
        print(f'tx token = {tx_token.hex()}')
    except Exception as ex:
        print(f"an exception of type {type(ex).__name__} occurred. Arguments:\n{ex.args}")

1 Answer 1


When trying to approve the router you use .call(..)

isApproved = ethContract.functions.approve(
    amountIn).call({'from': myAccount})

A call is executed in memory and any change is discarded immediately after returning, so the router isn't approved to transfer tokens from myAccount.

To make it work you have to call with .transact(..) or .buildTransaction(..) as you did for swapExactTokensForTokens.

  • Thanks a lot. I am new regarding working with python and web3.py so I didn't know much about that. your suggestion worked perfectly :). thanks a lot!!
    – BenGababy
    Apr 20, 2022 at 13:50

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.