[SOLVED] Polygon endpoint - Error: invalid sender - ETH Endpoint works fine

Hello :slight_smile:

I am trying to sign a transaction on the polygon network with Web3.py, but when I submit the transaction, I get the following error.

ValueError: {'code': -32000, 'message': 'invalid sender'}

The funny thing is that it works when I run the whole thing through the ETH mainnet Endpoint. Does anyone know where the error could be? :thinking:

Not working code (Polygon):

from web3 import Web3
import json

w3 = Web3(Web3.HTTPProvider('https://speedy-nodes-nyc.moralis.io/XXX/polygon/mainnet'))

# dummy account
private_key = "09f8998d3d0a5776cb9d656205f0e1734493de179fbe7fedd9d7107472ecbbf8"
address_user = "0x08d7FA722746e2f57aF9723A5f276e1DdF1cef73"
nonce = w3.eth.get_transaction_count(address_user)

# contract
abi = json.loads("...ABI...")
address = "...contract address..."
contract = w3.eth.contract(abi=abi, address=address)

# txn
deposit_txn = contract.functions.deposit(13, 0).buildTransaction({
    "gas": 70000,
    'maxFeePerGas': w3.toWei('2', 'gwei'),
    'maxPriorityFeePerGas': w3.toWei('1', 'gwei'),
    'nonce': nonce,
    'from': address_user,
    'chainId': 0x89

signed_txn = w3.eth.account.sign_transaction(deposit_txn, private_key=private_key)

The same code gives me the error code “insufficient funds for gas * price + value” when I use the ETH endpoint and remove ‘chainId’: 0x89 from the transaction. From this I conclude that it works for ETH and only polygon causes a problem.

Hopefully someone here can help me, because I have no idea what else to try :frowning:

Many thanks in advance

1 Like

You can get an existing transaction row data with a command like:

curl -H “Content-Type: application/json” -X POST --data ‘{“jsonrpc”:“2.0”,“method”:“eth_getRawTransactionByHash”,“params”:[“TRANSACTION_HASH_HERE”],“id”:1}’ https://speedy-nodes-nyc.moralis.io/ID_HERE/eth/ropsten

And then you can look at a tool like https://www.ethereumdecoder.com/ to see what were the fields for that transaction (there are better tools but didn’t find them now on a fast google search) (note that the transaction row data that you get here is the one after the digital signature was applied, the last 3 fields are related to the digital signature: v, r, s)

An example of output can be:

  "nonce": 1,
  "gasPrice": {
    "_hex": "..."
  "gasLimit": {
    "_hex": "..."
  "to": "....",
  "value": {
    "_hex": "...."
  "data": "....",
  "v": 42,
  "r": "...",
  "s": "...."

Then you could know what fields to set. I don’t know where from you took maxFeePerGas, maxPriorityFeePerGas.

1 Like

Hey @cryptokid,

thank you for the quick reply!

I tried it like you said, but I didn’t get anywhere with it either. Nevertheless, I was able to solve the problem by using Web3.js instead of Web3.py :sweat_smile:

I don’t know what I did wrong but the JS Version worked first try :man_shrugging:

Can you post the solution here?

JavaScript Code which got me the desired result:

var Web3 = require('web3');
const web3 = new Web3('https://speedy-nodes-nyc.moralis.io/XXX/polygon/mainnet');

const user_address = "0x08d7FA722746e2f57aF9723A5f276e1DdF1cef73";
const user_private_key = "09f8998d3d0a5776cb9d656205f0e1734493de179fbe7fedd9d7107472ecbbf8";

const abi = JSON.parse('... ABI...');
const contract_address = "...contract address...";

const init = async () => {

    const contract = new web3.eth.Contract(abi, contract_address);


    const tx = contract.methods.deposit(13, 0);
    const gas = await tx.estimateGas({from: user_address});
    const gasPrice = await web3.eth.getGasPrice();
    const data = tx.encodeABI();
    const nonce = await web3.eth.getTransactionCount(user_address);
    const txData = {
        from: user_address,
        to: contract_address,
        chainId: 137
    const receipt = await web3.eth.sendTransaction(txData);
    console.log("Transaction hash: ${receipt.transactionHash}");