degenTy
degenTy

Reputation: 360

Execution Reverted on Base Layer 2 Buy transaction using web3.py

I'm trying to write a service using python and web3.py to execute a "buy" transaction on a Base smart contract.

I can't figure out why my buy transactions aren't working from my code but seemingly the same transaction is working fine on the UI site for this contract. This is my wallet I've been testing with the failed txns are sent from the code: https://basescan.org/address/0xf276b155bed843b3daf21847ce25cf3f806bdca0

My python code to execute the buy looks like this, the transactions are successfully sent and return hashes, but the buy transaction is reverted: (I also tried converting the gas values from str to hex because thats how the txn looked from the website, as well as removing value key)

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from .models import Holding
import os
import sys
from web3 import Web3
from eth_account import Account
from .config import w3, CONTRACT_ADDRESS, GAS_LIMIT, VIRTUALS_CA
from .contract_abi import CONTRACT_ABI
from .virtual_protocol_contract import VIRTUAL_ABI
from .utils import estimate_gas_price

class BuyTokenView(APIView):
    def post(self, request):
        data = request.data

        # Validate input
        if 'contract_address' not in data:
            return Response({"error": "Missing required fields"}, status=status.HTTP_400_BAD_REQUEST)

        ca = data['contract_address']
        amount = data['amount']
        private_key = load_environment()
        account = setup_account(private_key)
        print(f"Connected with address: {account.address}")
        # Execute transaction
        execute_buy_transaction(account, ca, float(amount))

        return Response({"Message": f"Buying Token {ca}"}, status=status.HTTP_200_OK)


def load_environment():
    """Load environment variables."""
    private_key = os.getenv('PRIVATE_KEY')
    if not private_key:
        print("Error: PRIVATE_KEY not found in environment variables")
        sys.exit(1)
    return private_key


def setup_account(private_key):
    """Setup account from private key."""
    try:
        account = Account.from_key(private_key)
        return account
    except ValueError as e:
        print(f"Error setting up account: {e}")
        sys.exit(1)


def execute_buy_transaction(account, token_address, amount):
    """Execute token purchase transaction."""
    contract = w3.eth.contract(address=CONTRACT_ADDRESS, abi=CONTRACT_ABI)
    virtuals_contract = w3.eth.contract(address=VIRTUALS_CA, abi=VIRTUAL_ABI)
    float_value = float(amount)
    approve_tokens(account, virtuals_contract, int(amount))

    # Prepare transaction
    transaction = contract.functions.buy(amountIn=int(amount), tokenAddress=token_address).build_transaction({
        'from': account.address,
        'gas': hex(GAS_LIMIT),
        'maxFeePerGas': hex(estimate_gas_price(w3)),
        'maxPriorityFeePerGas': hex(w3.to_wei('2', 'gwei')),
        'nonce': hex(w3.eth.get_transaction_count(account.address)),
    })
    transaction.pop('value', None)

    # Sign and send transaction
    try:
        signed_txn = w3.eth.account.sign_transaction(transaction, account.key)
        tx_hash = w3.eth.send_raw_transaction(signed_txn.raw_transaction)
        print(f"Transaction sent. Hash: {tx_hash.hex()}")

        # Wait for transaction receipt
        print("Waiting for transaction confirmation...")
        receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
        return receipt
    except Exception as e:
        print(f"Error executing transaction: {e}")
        return None


# Function to approve tokens
def approve_tokens(account, contract, amount):
    nonce = w3.eth.get_transaction_count(account.address)

    tx = {
        'nonce': nonce,
        'to': contract.address,
        'value': w3.to_wei(0, 'ether'),
        'gas': 200000,
        'gasPrice': w3.eth.gas_price,
        'data': contract.encode_abi("approve", args=[account.address, amount]),
        'chainId': w3.eth.chain_id
    }
    try:
        signed_tx = w3.eth.account.sign_transaction(tx, account.key)
        tx_hash = w3.eth.send_raw_transaction(signed_tx.raw_transaction)
        print(f"Approve Transaction sent. Hash: {tx_hash.hex()}")

        # Wait for transaction receipt
        print("Waiting for transaction confirmation...")
        receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
        return receipt
    except Exception as e:
        print(f"Error approving tokens: {e}")
        return None

Upvotes: 1

Views: 31

Answers (1)

degenTy
degenTy

Reputation: 360

Turns out I was approving the wrong CA in approve_tokens I wanted to approve a different spender address than the account.address I was originally using.

Upvotes: 1

Related Questions