Reputation: 360
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
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