Increase Speed and Security of Ethereum Transactions

Andrew Millen
2 min readNov 4, 2021

Keep your wallet safe and offline while sending transaction directly to the Ethereum network using Python.

Photo by Zoltan Tasi on Unsplash

Nowadays the fees on transactions in the Ethereum network are high. It is possible to overcome these fees without relying e.g. on the DeFi aggregators.

Let’s create an offline wallet first. Keep your private and public key safe.

# create a large random number
digit_list = []
for i in range(77):
random_int = np.random.randint(10)
digit_list("%d"%(random_int))
priv_key = int("".join(digit_list))
priv_key_hex = str(hex(priv_key))
pub_key = priv_key * curve.g
pub_key_hex = str(hex(P[0])) + str(hex(P[1]))[2:]
signer_priv_key = eth_keys.keys.PrivateKey(priv_key.to_bytes(32, "big"))
signer_pub_key = signer_priv_key.public_key
address = signer_pub_key.to_checksum_address()

Now we define the inputs to a transaction. The transaction inputs must follow the Ethereum protocol. See the EIP-155 for detailed information.

nonce = "09"
gasPrice = "04a817c800"
gasLimit = "5208"
toAddress = "a3d66a78874Bd9b37dCB22500cd00301a6634016"
value = "1bc16d674ec80000"
data = ""
chainId = "01"

With these inputs we can create the RLP encoded raw transaction hex.

rlp_inputs = [
nonce,
gasPrice,
gasLimit,
toAddress,
value,
data,
chainId,
"",
""
]
rlp_inputs_bytes = []
for inp in rlp_inputs:
rlp_inputs_bytes.append(bytes.fromhex(inp))
rlp_encoded = rlp.encode(rlp_inputs_bytes)

The RLP encoded transaction message can now be signed with the previously created private key and a random number. The output is a signature which consists of the values v, r, s.

# message hash
h = eth_utils.keccak(msg)
h = int.from_bytes(h, "big")
# create a large random number
digit_list = []
for i in range(77):
random_int = np.random.randint(10)
digit_list("%d"%(random_int))
k = int("".join(digit_list))
# random point
R = k * curve.g
r = R[0]
# parity
v = 35 + int(chainId)*2 + (R[1] % 2)
# signature proof
s = pow(k, -1, n) * (h + r*priv_key) % n
v_hex = "{0:#0{1}x}".format(v, 4)
r_hex = "{0:#0{1}x}".format(r, 64)
s_hex = "{0:#0{1}x}".format(s, 64)

Finally we use the transaction inputs and the signature to create the RLP encoded raw transaction hex.

rlp_inputs = [
nonce,
gasPrice,
gasLimit,
toAddress,
value,
data,
v[2:],
r[2:],
s[2:]
]
rlp_inputs_bytes = []
for inp in rlp_inputs:
rlp_inputs_bytes.append(bytes.fromhex(inp))
rlp_encoded = rlp.encode(rlp_inputs_bytes)
signed_raw_tx_hex = rlp_encoded.hex()

This raw transaction hex we can now broadcast directly to the Ethereum network on:

https://etherscan.io/pushTx

Following the steps above we were able to create a transaction offline and completely under our control. We decided when the transaction should be added to the blockchain by setting the nonce and we also decided which gas limit should to be applied.

Of course, if you choose a too low gas limit the mining nodes might never pick up your transaction from the transaction pool. Yet, if we were running a mining node in the Ethereum network, we could choose our particular transaction and still mine it.

If there is enough interest, I would take the time and provide full samples in a cleaned up GitHub repo. Just leave a comment to let me know!

--

--