How to send ERC721 Token with Python

I want to call safeTransferFrom from a deployed Polygon contract.

safeTransferFrom has 3 arguments:

address from
address to
uint256 tokenId

How do I call this function? I found this tutorial but I’m not sure how to modify it to call a function. Use Python - Infura Docs

Here’s what I have so far:

import os
from dotenv import load_dotenv
from web3 import Web3

load_dotenv()

infura_url = "https://polygon-mainnet.infura.io/v3/API-KEY"
private_key = os.getenv('PRIVATE_KEY')

from_account = 'MY-POLYGON-ADDRESS'
to_account = 'CONTRACT-ADDRESS'

web3 = Web3(Web3.HTTPProvider(infura_url))
nonce = web3.eth.getTransactionCount(from_account)

tx = {
    'type': '0x2',
    'nonce': nonce,
    'from': from_account,
    'to': to_account,
    'value': web3.toWei(0.00, 'ether'),
    'maxFeePerGas': web3.toWei('TOTAL-FEE', 'gwei'),
    'maxPriorityFeePerGas': web3.toWei('PRIORITY-FEE', 'gwei'),
    'chainId': 137
}

gas = web3.eth.estimateGas(tx)
tx['gas'] = gas
signed_tx = web3.eth.account.sign_transaction(tx, private_key)
tx_hash = web3.eth.send_raw_transaction(signed_tx.rawTransaction)
print("Transaction hash: " + str(web3.toHex(tx_hash)))

Thanks!

1 Like

Hey, you’ll pretty much just need to create a contract object and then use this contract.functions method to send a tx and call safeTransferFrom since it’s write function. Something like:

myContract = web3.eth.contract(address=contract_address, abi=contract_abi)
myContract.functions.safeTransferFrom(web3.eth.accounts[1], 0x.., 1234).transact()

Alternatively, if you don’t want to use transact() you can craft the raw tx, sign and send like shown in this example (it’s just a different function to be called):

3 Likes

Figured it out, this is also how to call contract functions with web3 using Python. I hope this post helps anyone looking how to do this.

from web3 import Web3

#all instances of brackets denote info you should input (brackets should be removed),
#except for the abi, see below for specific formatting.

#register with infura and get the url at api keys > project name > endpoints > polygon > mainnet
#you need to add a credit card for their free plan and add-on polygon network support when checking out
infura_url = "https://polygon-mainnet.infura.io/v3/[API LINK KEY]"

#use metamask to get private key and put the hex string here in quotes
private_key = "[SENDING ADDRESS PRIVATE KEY]"

#put addresses here in quotes, begins with 0x
from_account = "[SENDING ADDRESS]"
to_account = "[RECEIVING ADDRESS]"

web3 = Web3(Web3.HTTPProvider(infura_url))
nonce = web3.eth.getTransactionCount(from_account)

#replace with id of token you want to send, NO quotes
tokenId = [TOKEN ID]

#contract address here in quotes
contract_address = "[CONTRACT ADDRESS]"

#put entire abi here, go to polygonscan > contract address > contract tab > contract abi
#line should be formatted like this:
#abi = '[{"inputs":[]...'
abi = '[ABI]'

contract = web3.eth.contract(address=contract_address, abi=abi)

tx = contract.functions.safeTransferFrom(from_account, to_account, tokenId).buildTransaction(
	{
		'from': from_account,
		'nonce': nonce,
		'gas': [GAS LIMIT], #gas limit you want i.e. 100000, NO quotes
		'maxFeePerGas': web3.toWei('[TOTAL FEE]', 'gwei'), #total gas fee here (base fee + priority), i.e. web3.toWei('150', 'gwei') can use https://polygonscan.com/gastracker
		'maxPriorityFeePerGas': web3.toWei('[PRIORITY FEE]', 'gwei'), #priority fee here, i.e. web3.toWei('50', 'gwei')
		'chainId': 137 #polygon chain is 137, use https://chainlist.org/ to get your chain id if using a different chain
	}
)

signed_tx = web3.eth.account.sign_transaction(tx, private_key)
tx_hash = web3.eth.send_raw_transaction(signed_tx.rawTransaction)
print("Transaction hash: " + str(web3.toHex(tx_hash)))
3 Likes

Thanks traian, I appreciate it! I happened to figure it out on my own, I posted a complete code snippet of my solution for those looking for more specific instruction.

2 Likes

This topic was automatically closed after 30 days. New replies are no longer allowed.