Eric 1172b7e56a
remove raises from async annotation for dynamic dispatch
- removes async: raises from getAddress and signTransaction because derived JsonRpcSigner methods were not being used when dynamically dispatched. Once `raises` was removed from the async annotation, the dynamic dispatch worked again. This is only the case for getAddress and signTransaction.
- add gcsafe annotation to wallet.provider so that it matches the base method
2024-01-30 17:40:14 +11:00

89 lines
2.7 KiB
Nim

import eth/keys
import ../basics
import ../provider
import ../transaction
import ../signer
import ./wallet/error
import ./wallet/signing
export keys
export WalletError
export signing
{.push raises: [].}
var rng {.threadvar.}: ref HmacDrbgContext
proc getRng: ref HmacDrbgContext =
if rng.isNil:
rng = newRng()
rng
type Wallet* = ref object of Signer
privateKey*: PrivateKey
publicKey*: PublicKey
address*: Address
provider*: ?Provider
proc new*(_: type Wallet, privateKey: PrivateKey): Wallet =
let publicKey = privateKey.toPublicKey()
let address = Address.init(publicKey.toCanonicalAddress())
Wallet(privateKey: privateKey, publicKey: publicKey, address: address)
proc new*(_: type Wallet, privateKey: PrivateKey, provider: Provider): Wallet =
let wallet = Wallet.new(privateKey)
wallet.provider = some provider
wallet
proc new*(_: type Wallet, privateKey: string): ?!Wallet =
let keyResult = PrivateKey.fromHex(privateKey)
if keyResult.isErr:
return failure newException(WalletError, "invalid key: " & $keyResult.error)
success Wallet.new(keyResult.get())
proc new*(_: type Wallet, privateKey: string, provider: Provider): ?!Wallet =
let wallet = ? Wallet.new(privateKey)
wallet.provider = some provider
success wallet
proc connect*(wallet: Wallet, provider: Provider) =
wallet.provider = some provider
proc createRandom*(_: type Wallet): Wallet =
result = Wallet()
result.privateKey = PrivateKey.random(getRng()[])
result.publicKey = result.privateKey.toPublicKey()
result.address = Address.init(result.publicKey.toCanonicalAddress())
proc createRandom*(_: type Wallet, provider: Provider): Wallet =
result = Wallet()
result.privateKey = PrivateKey.random(getRng()[])
result.publicKey = result.privateKey.toPublicKey()
result.address = Address.init(result.publicKey.toCanonicalAddress())
result.provider = some provider
method provider*(wallet: Wallet): Provider {.gcsafe, raises: [SignerError].} =
without provider =? wallet.provider:
raiseWalletError "Wallet has no provider"
provider
method getAddress*(wallet: Wallet): Future[Address] {.async.} =
return wallet.address
proc signTransaction*(wallet: Wallet,
transaction: Transaction): Future[seq[byte]] {.async: (raises:[WalletError]).} =
if sender =? transaction.`from` and sender != wallet.address:
raiseWalletError "from address mismatch"
return wallet.privateKey.sign(transaction)
method sendTransaction*(
wallet: Wallet,
transaction: Transaction): Future[TransactionResponse] {.async.} =
convertError:
let signed = await signTransaction(wallet, transaction)
if nonce =? transaction.nonce:
wallet.updateNonce(nonce)
return await provider(wallet).sendTransaction(signed)