Refactor wallet signing
This commit is contained in:
parent
f1a1221d14
commit
842bf4d0a2
|
@ -1,11 +1,9 @@
|
||||||
import eth/keys
|
import eth/keys
|
||||||
import eth/rlp
|
|
||||||
import eth/common
|
|
||||||
import eth/common/transaction as ct
|
|
||||||
import ./provider
|
import ./provider
|
||||||
import ./transaction as tx
|
import ./transaction
|
||||||
import ./signer
|
import ./signer
|
||||||
import ./wallet/error
|
import ./wallet/error
|
||||||
|
import ./wallet/signing
|
||||||
|
|
||||||
export keys
|
export keys
|
||||||
export WalletError
|
export WalletError
|
||||||
|
@ -17,8 +15,6 @@ proc getRng: ref HmacDrbgContext =
|
||||||
rng = newRng()
|
rng = newRng()
|
||||||
rng
|
rng
|
||||||
|
|
||||||
type SignableTransaction = common.Transaction
|
|
||||||
|
|
||||||
type Wallet* = ref object of Signer
|
type Wallet* = ref object of Signer
|
||||||
privateKey*: PrivateKey
|
privateKey*: PrivateKey
|
||||||
publicKey*: PublicKey
|
publicKey*: PublicKey
|
||||||
|
@ -58,61 +54,13 @@ method provider*(wallet: Wallet): Provider =
|
||||||
method getAddress(wallet: Wallet): Future[Address] {.async.} =
|
method getAddress(wallet: Wallet): Future[Address] {.async.} =
|
||||||
return wallet.address
|
return wallet.address
|
||||||
|
|
||||||
proc signTransaction(tr: var SignableTransaction, pk: PrivateKey) =
|
proc signTransaction*(wallet: Wallet,
|
||||||
# Temporary V value, used to signal to the hashing function the
|
transaction: Transaction): Future[seq[byte]] {.async.} =
|
||||||
# chain id that we'd like to use for an EIP-155 signature
|
if sender =? transaction.sender and sender != wallet.address:
|
||||||
tr.V = int64(uint64(tr.chainId)) * 2 + 35
|
|
||||||
|
|
||||||
let h = tr.txHashNoSignature
|
|
||||||
let s = sign(pk, SkMessage(h.data))
|
|
||||||
|
|
||||||
let r = toRaw(s)
|
|
||||||
let v = r[64]
|
|
||||||
|
|
||||||
tr.R = fromBytesBE(UInt256, r.toOpenArray(0, 31))
|
|
||||||
tr.S = fromBytesBE(UInt256, r.toOpenArray(32, 63))
|
|
||||||
|
|
||||||
case tr.txType:
|
|
||||||
of TxLegacy:
|
|
||||||
tr.V = int64(v) + int64(uint64(tr.chainId))*2 + 35
|
|
||||||
of TxEip1559:
|
|
||||||
tr.V = int64(v)
|
|
||||||
else:
|
|
||||||
raiseWalletError "Transaction type not supported"
|
|
||||||
|
|
||||||
proc signTransaction*(wallet: Wallet, tx: tx.Transaction): Future[seq[byte]] {.async.} =
|
|
||||||
if sender =? tx.sender and sender != wallet.address:
|
|
||||||
raiseWalletError "from address mismatch"
|
raiseWalletError "from address mismatch"
|
||||||
|
|
||||||
without nonce =? tx.nonce and chainId =? tx.chainId and gasLimit =? tx.gasLimit:
|
return wallet.privateKey.sign(transaction)
|
||||||
raiseWalletError "Transaction is not properly populated"
|
|
||||||
|
|
||||||
var s: SignableTransaction
|
method sendTransaction*(wallet: Wallet, transaction: Transaction): Future[TransactionResponse] {.async.} =
|
||||||
|
let signed = await signTransaction(wallet, transaction)
|
||||||
if maxFee =? tx.maxFee and maxPriorityFee =? tx.maxPriorityFee:
|
return await provider(wallet).sendTransaction(signed)
|
||||||
s.txType = TxEip1559
|
|
||||||
s.maxFee = GasInt(maxFee.truncate(uint64))
|
|
||||||
s.maxPriorityFee = GasInt(maxPriorityFee.truncate(uint64))
|
|
||||||
elif gasPrice =? tx.gasPrice:
|
|
||||||
s.txType = TxLegacy
|
|
||||||
s.gasPrice = GasInt(gasPrice.truncate(uint64))
|
|
||||||
else:
|
|
||||||
raiseWalletError "Transaction is not properly populated"
|
|
||||||
|
|
||||||
s.chainId = ChainId(chainId.truncate(uint64))
|
|
||||||
s.gasLimit = GasInt(gasLimit.truncate(uint64))
|
|
||||||
s.value = tx.value
|
|
||||||
s.nonce = nonce.truncate(uint64)
|
|
||||||
s.to = some EthAddress(tx.to)
|
|
||||||
s.payload = tx.data
|
|
||||||
signTransaction(s, wallet.privateKey)
|
|
||||||
|
|
||||||
return rlp.encode(s)
|
|
||||||
|
|
||||||
method sendTransaction*(wallet: Wallet, tx: tx.Transaction): Future[TransactionResponse] {.async.} =
|
|
||||||
let rawTX = await signTransaction(wallet, tx)
|
|
||||||
return await provider(wallet).sendTransaction(rawTX)
|
|
||||||
|
|
||||||
#TODO add functionality to sign messages
|
|
||||||
|
|
||||||
#TODO add functionality to create wallets from Mnemoniks or Keystores
|
|
||||||
|
|
|
@ -0,0 +1,64 @@
|
||||||
|
import pkg/eth/keys
|
||||||
|
import pkg/eth/rlp
|
||||||
|
import pkg/eth/common/transaction as eth
|
||||||
|
import ../basics
|
||||||
|
import ../transaction as ethers
|
||||||
|
import ./error
|
||||||
|
|
||||||
|
type
|
||||||
|
Transaction = ethers.Transaction
|
||||||
|
SignableTransaction = eth.Transaction
|
||||||
|
|
||||||
|
func toSignableTransaction(transaction: Transaction): SignableTransaction =
|
||||||
|
var signable: SignableTransaction
|
||||||
|
|
||||||
|
without nonce =? transaction.nonce:
|
||||||
|
raiseWalletError "missing nonce"
|
||||||
|
|
||||||
|
without chainId =? transaction.chainId:
|
||||||
|
raiseWalletError "missing chain id"
|
||||||
|
|
||||||
|
without gasLimit =? transaction.gasLimit:
|
||||||
|
raiseWalletError "missing gas limit"
|
||||||
|
|
||||||
|
signable.nonce = nonce.truncate(uint64)
|
||||||
|
signable.chainId = ChainId(chainId.truncate(uint64))
|
||||||
|
signable.gasLimit = GasInt(gasLimit.truncate(uint64))
|
||||||
|
signable.to = some EthAddress(transaction.to)
|
||||||
|
signable.value = transaction.value
|
||||||
|
signable.payload = transaction.data
|
||||||
|
|
||||||
|
if maxFee =? transaction.maxFee and
|
||||||
|
maxPriorityFee =? transaction.maxPriorityFee:
|
||||||
|
signable.txType = TxEip1559
|
||||||
|
signable.maxFee = GasInt(maxFee.truncate(uint64))
|
||||||
|
signable.maxPriorityFee = GasInt(maxPriorityFee.truncate(uint64))
|
||||||
|
elif gasPrice =? transaction.gasPrice:
|
||||||
|
signable.txType = TxLegacy
|
||||||
|
signable.gasPrice = GasInt(gasPrice.truncate(uint64))
|
||||||
|
else:
|
||||||
|
raiseWalletError "missing gas price"
|
||||||
|
|
||||||
|
signable
|
||||||
|
|
||||||
|
func sign(key: PrivateKey, transaction: SignableTransaction): seq[byte] =
|
||||||
|
var transaction = transaction
|
||||||
|
|
||||||
|
# Temporary V value, used to signal to the hashing function
|
||||||
|
# that we'd like to use an EIP-155 signature
|
||||||
|
transaction.V = int64(uint64(transaction.chainId)) * 2 + 35
|
||||||
|
|
||||||
|
let hash = transaction.txHashNoSignature().data
|
||||||
|
let signature = key.sign(SkMessage(hash)).toRaw()
|
||||||
|
|
||||||
|
transaction.R = UInt256.fromBytesBE(signature[0..<32])
|
||||||
|
transaction.S = UInt256.fromBytesBE(signature[32..<64])
|
||||||
|
transaction.V = int64(signature[64])
|
||||||
|
|
||||||
|
if transaction.txType == TxLegacy:
|
||||||
|
transaction.V += int64(uint64(transaction.chainId)) * 2 + 35
|
||||||
|
|
||||||
|
rlp.encode(transaction)
|
||||||
|
|
||||||
|
func sign*(key: PrivateKey, transaction: Transaction): seq[byte] =
|
||||||
|
key.sign(transaction.toSignableTransaction())
|
Loading…
Reference in New Issue