2

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.

2 Answers 2

4

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.)

1
  • It is sort of misleading for the address displayed on etherscan as they showed it in lower cases which does not comply with EIP 55.
    – dezhi
    Commented Aug 19, 2021 at 21:37
0

Thanks @smarx for the hint.

However, I managed to find another solution:

from bitcoin import ecdsa_raw_sign
from bitcoin import der_encode_sig

def signing(transaction, privkey):
    signature = der_encode_sig(*ecdsa_raw_sign(transaction, privkey))
    return signature

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.