mirror of https://github.com/status-im/nim-eth.git
78 lines
2.4 KiB
Nim
78 lines
2.4 KiB
Nim
|
# eth
|
||
|
# Copyright (c) 2024 Status Research & Development GmbH
|
||
|
# Licensed and distributed under either of
|
||
|
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
|
||
|
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
|
||
|
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||
|
|
||
|
import ./[keys, transactions, transactions_rlp]
|
||
|
|
||
|
export keys, transactions
|
||
|
|
||
|
proc signature*(tx: Transaction): Opt[Signature] =
|
||
|
var bytes {.noinit.}: array[65, byte]
|
||
|
bytes[0 .. 31] = tx.R.toBytesBE()
|
||
|
bytes[32 .. 63] = tx.S.toBytesBE()
|
||
|
|
||
|
bytes[64] =
|
||
|
if tx.txType != TxLegacy:
|
||
|
tx.V.byte
|
||
|
elif tx.V >= EIP155_CHAIN_ID_OFFSET:
|
||
|
byte(1 - (tx.V and 1))
|
||
|
elif tx.V == 27 or tx.V == 28:
|
||
|
byte(tx.V - 27)
|
||
|
else:
|
||
|
return Opt.none(Signature)
|
||
|
|
||
|
Signature.fromRaw(bytes).mapConvertErr(void)
|
||
|
|
||
|
proc `signature=`*(tx: var Transaction, param: tuple[sig: Signature, eip155: bool]) =
|
||
|
let raw = param.sig.toRaw()
|
||
|
|
||
|
tx.R = UInt256.fromBytesBE(raw.toOpenArray(0, 31))
|
||
|
tx.S = UInt256.fromBytesBE(raw.toOpenArray(32, 63))
|
||
|
|
||
|
let v = raw[64].uint64
|
||
|
tx.V =
|
||
|
case tx.txType
|
||
|
of TxLegacy:
|
||
|
if param.eip155:
|
||
|
v + uint64(tx.chainId) * 2 + 35
|
||
|
else:
|
||
|
v + 27'u64
|
||
|
else:
|
||
|
v
|
||
|
|
||
|
proc sign*(tx: Transaction, pk: PrivateKey, eip155: bool): (Signature, bool) =
|
||
|
let hash = tx.rlpHashForSigning(eip155)
|
||
|
|
||
|
(sign(pk, SkMessage(hash.data)), eip155)
|
||
|
|
||
|
proc recoverKey*(tx: Transaction): Opt[PublicKey] =
|
||
|
## Recovering key / sender is a costly operation - make sure to reuse the
|
||
|
## outcome!
|
||
|
##
|
||
|
## Returns `none` if the signature is invalid with respect to the rest of
|
||
|
## the transaction data.
|
||
|
let
|
||
|
sig = ?tx.signature()
|
||
|
txHash = tx.rlpHashForSigning(tx.isEip155())
|
||
|
|
||
|
recover(sig, SkMessage(txHash.data)).mapConvertErr(void)
|
||
|
|
||
|
proc recoverSender*(tx: Transaction): Opt[Address] =
|
||
|
## Recovering key / sender is a costly operation - make sure to reuse the
|
||
|
## outcome!
|
||
|
##
|
||
|
## Returns `none` if the signature is invalid with respect to the rest of
|
||
|
## the transaction data.
|
||
|
let key = ?tx.recoverKey()
|
||
|
ok key.to(Address)
|
||
|
|
||
|
proc creationAddress*(tx: Transaction, sender: Address): Address =
|
||
|
let hash = keccak256(rlp.encodeList(sender, tx.nonce))
|
||
|
hash.to(Address)
|
||
|
|
||
|
proc getRecipient*(tx: Transaction, sender: Address): Address =
|
||
|
tx.to.valueOr(tx.creationAddress(sender))
|