2

I tried to execute a swap using Web3py with the following function:

def swap(node, account_address, pvt_key, contract_address, contract_abi, action_type, amount_in, amount_out_min):
    #load USDC and WETH contracts. Those are the tokens we are going to use.
    weth_addr = web3.Web3.toChecksumAddress('0x7ceb23fd6bc0add59e62ac25578270cff1b9f619')
    usdc_addr = web3.Web3.toChecksumAddress('0x2791bca1f2de4661ed88a30c99a7a9449aa84174')
    
    #connect to polygon node
    w3 = web3.Web3(web3.Web3.HTTPProvider(node))
    w3.middleware_onion.inject(geth_poa_middleware, layer=0)

    #This is the smart contract we will interact with to buy or sell the tokens.
    contract_addr = web3.Web3.toChecksumAddress(contract_address.lower())
    contract = w3.eth.contract(contract_addr, abi=contract_abi)

    #set a correct gas price. This line of code could be surely optimized.
    gasPrice = w3.toWei(200, 'gwei')    
    
    amount_eth = int(amount_in*10**18)
        
    swap_path = [weth_addr, usdc_addr]
    amount_usdc = contract.functions.getAmountsOut(amount_eth, swap_path).call()[1]

        #execute swap
    min_amount_eth = int(amount_eth*0.97)
    deadline = int(time.time() + 60)
    function = contract.functions.swapExactTokensForTokens(
      amount_eth,
      amount_usdc,
      swap_path,
      account_address,
      deadline
    )

    tx = function.buildTransaction({
      'from': account_address,
      'nonce': w3.eth.getTransactionCount(account_address),
      'gasPrice': gasPrice,
    })
        
    signed_tx = w3.eth.account.signTransaction(tx, pvt_key)
    tx_hash = w3.eth.sendRawTransaction(signed_tx.rawTransaction)
    tx_receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
    print(tx_receipt)

But I get the error:

web3.exceptions.ContractLogicError: execution reverted: TransferHelper: TRANSFER_FROM_FAILED

So as suggested in [previous and similar questions][1] I approved spending of tokens as shown in the code following:

def swap(node, account_address, pvt_key, contract_address, contract_abi, action_type, amount_in, amount_out_min):
    #load USDC and WETH contracts. Those are the tokens we are going to use.
    weth_addr = web3.Web3.toChecksumAddress('0x7ceb23fd6bc0add59e62ac25578270cff1b9f619')
    usdc_addr = web3.Web3.toChecksumAddress('0x2791bca1f2de4661ed88a30c99a7a9449aa84174')
    
    #connect to polygon node
    w3 = web3.Web3(web3.Web3.HTTPProvider(node))
    w3.middleware_onion.inject(geth_poa_middleware, layer=0)

    usdc_abi = ''''''
    usdc_contract = w3.eth.contract(weth_addr, abi=usdc_abi)
    weth_abi = ''''''
    weth_contract = w3.eth.contract(weth_addr, abi=weth_abi)


    #This is the smart contract we will interact with to buy or sell the tokens.
    contract_addr = web3.Web3.toChecksumAddress(contract_address.lower())
    contract = w3.eth.contract(contract_addr, abi=contract_abi)

    #set a correct gas price. This line of code could be surely optimized.
    gasPrice = w3.toWei(200, 'gwei')    

    nonce = w3.eth.getTransactionCount(account_address)

    tx = usdc_contract.functions.approve(account_address, 1000000).buildTransaction({
        'from': account_address, 
        'nonce': nonce
        })
        
    signed_tx = w3.eth.account.signTransaction(tx, pvt_key)
    tx_hash = w3.eth.sendRawTransaction(signed_tx.rawTransaction)
    tx_receipt = w3.eth.wait_for_transaction_receipt(tx_hash)

    nonce = w3.eth.getTransactionCount(account_address)
    
    tx = weth_contract.functions.approve(account_address, 1000000).buildTransaction({
        'from': account_address, 
        'nonce': nonce
        })
        
    signed_tx = w3.eth.account.signTransaction(tx, pvt_key)
    tx_hash = w3.eth.sendRawTransaction(signed_tx.rawTransaction)
    tx_receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
    
    if action_type == 1 or action_type == 0:
        #we need to sell eth for usdc
        amount_eth = int(amount_in*10**18)
        
        swap_path = [weth_addr, usdc_addr]
        amount_usdc = contract.functions.getAmountsOut(amount_eth, swap_path).call()[1]

        #execute swap
        min_amount_eth = int(amount_eth*0.97)
        deadline = int(time.time() + 60)
        function = contract.functions.swapExactTokensForTokens(
          amount_eth,
          amount_usdc,
          swap_path,
          account_address,
          deadline
        )

        tx = function.buildTransaction({
          'from': account_address,
          'nonce': w3.eth.getTransactionCount(account_address),
          'gasPrice': gasPrice,
        })
        
        signed_tx = w3.eth.account.signTransaction(tx, pvt_key)
        tx_hash = w3.eth.sendRawTransaction(signed_tx.rawTransaction)
        tx_receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
        print(tx_receipt)

But still getting the same error. Why transfer fails if I approve the token spending? Can't figure it out. Thank you. [1]: swap Tokens fails due to TRANSFER_FROM_FAILED

1 Answer 1

3

You are getting an error because you approve the wrong address to spend tokens.

tx = usdc_contract.functions.approve(account_address, 1000000).buildTransaction({
    'from': account_address, 
    'nonce': nonce
    })

Instead of approving your own address, account_address, you should approve the contract_address to spend tokens on your behalf.

Change the approval on both USDC and WETH then your code should work.

4
  • finally works! thanls :) Commented Apr 12, 2023 at 9:46
  • Ehy I am sorry but I faced the same issue again. I am basically trying to sell USDC for WETH. The USDC spending has been approved several time but I got the same 'TRANSFER FROM FAILED' error. This is how code currently looks like: pastebin.com/1pFyCS9w . Can you please help me solving the issue? Commented Apr 12, 2023 at 10:36
  • can you open a new question, with more details about the error, it was working so you changed something?
    – Adam Boudj
    Commented Apr 12, 2023 at 12:52
  • i didn't change nothing, the wETH->USDC swap works well. But when I try to do the inverted swap (USDC->wETH) I get the same error (TRANSFER_FROM_FAILED') even if I approved the USDC transfer... Commented Apr 12, 2023 at 13:28

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.