[Ethereum] How to simply sign an Ethereum transaction

ecdsapythonsignatureweb3.py

I want to use blockcypher to work with the Ethereum network.

In the documentation they give an example of a signer tool written on Go, but I'm use Python.

What is the simplest way to sign a transaction?

I tried using web3.py, but I ran into some difficulties.

Here they give the following example:

transaction = {
       'to': '0xF0109fC8DF283027b6285cc889F5aA624EaC1F55',
       'value': 1000000000,
       'gas': 2000000,
       'gasPrice': 234567897654321,
       'nonce': 0,
       'chainId': 1
}
key = '0x4c0883a69102937d6231471b5dbb6204fe5129617082792ae468d01a3f362318'
signed = w3.eth.account.signTransaction(transaction, key)
signed.rawTransaction
HexBytes('0xf86a8086d55698372431831e848094f0109fc8df283027b6285cc889f5aa624eac1f55843b9aca008025a009ebb6ca057a0535d6186462bc0b465b561c94a295bdb0621fc19208ab149a9ca0440ffd775ce91a833ab410777204d5341a6f9fa91216a6f3ee2c051fea6a0428')
signed.hash
HexBytes('0xd8f64a42b57be0d565f385378db2f6bf324ce14a594afc05de90436e9ce01f60')
signed.r
4487286261793418179817841024889747115779324305375823110249149479905075174044
signed.s
30785525769477805655994251009256770582792548537338581640010273753578382951464
signed.v
37

But I do not understand some of the values that need to be passed to the transaction.

What is nonce, chainId?

Using such data:

transaction = {
    'to': '0xe980e77404ae62ab0f2d6b8510bd951e25185414',
    'value': value,
    'gas': 2000000,
    'gasPrice': 1000000000,,
    'nonce': 0,
    'chainId': 1
}

I get this error:

TypeError: Transaction had invalid fields: {'to': '0xe980e77404ae62ab0f2d6b8510bd951e25185414'}

Next, I tried to use ecdsa

But I was not able to find a simple example. I do not understand anything at all in cryptography, and I need the easiest way to send a transaction to the network without hammering through the details.

UPDATE

I tried to avoid using w3, since I only need to sign a transaction.

I was able to do this to create a signature:

import hashlib
import binascii

import ecdsa

def sign(privkey, message):
    sk = ecdsa.SigningKey.from_string(
        binascii.unhexlify(privkey),
        curve=ecdsa.SECP256k1,
        hashfunc=hashlib.sha256
    )
    signature = binascii.hexlify(
        sk.sign(
            binascii.unhexlify(message),
            hashfunc=hashlib.sha256
        )
    )
    return signature

And the function works fine, I return a byte string like this:

b'4ace74a83082b5fc6d356083932b493e9fafbe0fabca19be3e77ccda188d08c6352f1fccb144e18b95a3f7e18f71fe95d79a9dd8ad9ecaa7490315f06a00177f'

But the length of this line is 128 characters, and in the example of the blockcypher a string of 148 characters.

After trying to send a signed transaction to the network, I receive such a reply:

{'error': 'Could not compute an address from provided signature: invalid transaction v, r, s values.'}

Most likely, I'm creating the wrong signature, but how to make the right one?

It seems I'm almost there, but still it's not working out.

Best Answer

Version 4.x of web3.py requires all addresses use a proper EIP 55 checksum. In my testing, I receive the same error as you until I convert the address to the correct checksummed form (note the capitalization):

0xe980E77404ae62aB0F2d6b8510BD951e25185414

(Note that you also have an extra comma that makes your code syntactically invalid, but I assume that's just a copy/paste error.)

Related Topic