Refactor exceptions for providers and signers, fix more tests

- signer procs raise SignerError, provider procs raise ProviderError
- WalletError now inherits from SignerError
- move wallet module under signers
- create jsonrpo moudle under signers
- bump nim-json-rpc for null-handling fixes
- All jsonrpc provider tests passing, still need to fix others
This commit is contained in:
Eric 2024-01-29 22:20:48 +11:00
parent c261e96274
commit 59a7939e8f
No known key found for this signature in database
15 changed files with 250 additions and 170 deletions

View File

@ -8,7 +8,7 @@ requires "chronicles >= 0.10.3 & < 0.11.0"
requires "chronos#f0a2d4df61302d24baa6c0f1c257f92045c9ee57"
requires "contractabi >= 0.6.0 & < 0.7.0"
requires "questionable >= 0.10.2 & < 0.11.0"
requires "json_rpc"
requires "json_rpc >= 0.3.0 & < 0.4.0"
requires "stint"
requires "stew"
requires "eth"

View File

@ -88,13 +88,14 @@ template raiseProviderError(msg: string) =
func toTransaction*(past: PastTransaction): Transaction =
Transaction(
`from`: some past.`from`,
gasPrice: some past.gasPrice,
data: past.input,
nonce: some past.nonce,
to: past.to,
`type`: past.`type`,
data: past.input,
value: past.value,
nonce: some past.nonce,
chainId: past.chainId,
gasPrice: some past.gasPrice,
gasLimit: some past.gas,
chainId: past.chainId
`type`: past.`type`
)
method getBlockNumber*(
@ -246,7 +247,9 @@ proc ensureSuccess(
proc confirm*(
tx: TransactionResponse,
confirmations = EthersDefaultConfirmations,
timeout = EthersReceiptTimeoutBlks): Future[TransactionReceipt] {.async: (raises: [CancelledError, ProviderError, EthersError]).} =
timeout = EthersReceiptTimeoutBlks): Future[TransactionReceipt]
{.async: (raises: [CancelledError, ProviderError, EthersError]).} =
## Waits for a transaction to be mined and for the specified number of blocks
## to pass since it was mined (confirmations).
## A timeout, in blocks, can be specified that will raise an error if too many

View File

@ -26,14 +26,18 @@ type
JsonRpcProvider* = ref object of Provider
client: Future[RpcClient]
subscriptions: Future[JsonRpcSubscriptions]
JsonRpcSigner* = ref object of Signer
provider: JsonRpcProvider
address: ?Address
JsonRpcProviderError* = object of ProviderError
JsonRpcSubscription* = ref object of Subscription
subscriptions: JsonRpcSubscriptions
id: JsonNode
# Signer
JsonRpcSigner* = ref object of Signer
provider: JsonRpcProvider
address: ?Address
JsonRpcSignerError* = object of SignerError
proc raiseJsonRpcProviderError(
message: string) {.raises: [JsonRpcProviderError].} =
@ -50,7 +54,7 @@ template convertError(body) =
except JsonRpcError as error:
raiseJsonRpcProviderError(error.msg)
except CatchableError as error:
raiseJsonRpcProviderError(error.msg)
raise newException(JsonRpcProviderError, error.msg)
# Provider
@ -104,6 +108,7 @@ proc callImpl(
args: JsonNode): Future[JsonNode] {.async: (raises: [JsonRpcProviderError]).} =
without response =? (await client.call(call, %args)).catch, error:
echo "[jsonrpc.callImpl] error during call: ", error.msg
raiseJsonRpcProviderError error.msg
echo "[jsonrpc.callImpl] response: ", response.string
without json =? JsonNode.fromJson(response.string), error:
@ -111,16 +116,19 @@ proc callImpl(
raiseJsonRpcProviderError "Failed to parse response: " & error.msg
json
proc send*(
provider: JsonRpcProvider,
call: string,
arguments: seq[JsonNode] = @[]): Future[JsonNode] {.async.} =
arguments: seq[JsonNode] = @[]): Future[JsonNode]
{.async: (raises: [JsonRpcProviderError]).} =
convertError:
let client = await provider.client
return await client.callImpl(call, %arguments)
proc listAccounts*(provider: JsonRpcProvider): Future[seq[Address]] {.async.} =
proc listAccounts*(provider: JsonRpcProvider): Future[seq[Address]]
{.async: (raises: [JsonRpcProviderError]).} =
convertError:
let client = await provider.client
return await client.eth_accounts()
@ -228,7 +236,8 @@ method getChainId*(
method sendTransaction*(
provider: JsonRpcProvider,
rawTransaction: seq[byte]): Future[TransactionResponse] {.async: (raises:[ProviderError]).} =
rawTransaction: seq[byte]): Future[TransactionResponse]
{.async: (raises:[ProviderError]).} =
convertError:
let
@ -278,36 +287,55 @@ method close*(
# Signer
method provider*(signer: JsonRpcSigner): Provider =
proc raiseJsonRpcSignerError(
message: string) {.raises: [JsonRpcSignerError].} =
var message = message
if json =? JsonNode.fromJson(message):
if "message" in json:
message = json{"message"}.getStr
raise newException(JsonRpcSignerError, message)
template convertSignerError(body) =
try:
body
except JsonRpcError as error:
raiseJsonRpcSignerError(error.msg)
except CatchableError as error:
raise newException(JsonRpcSignerError, error.msg)
method provider*(signer: JsonRpcSigner): Provider {.gcsafe.} =
signer.provider
method getAddress*(
signer: JsonRpcSigner): Future[Address] {.async: (raises:[ProviderError]).} =
signer: JsonRpcSigner): Future[Address] {.async: (raises:[SignerError]).} =
if address =? signer.address:
return address
convertError:
convertSignerError:
let accounts = await signer.provider.listAccounts()
if accounts.len > 0:
return accounts[0]
raiseJsonRpcProviderError "no address found"
raiseJsonRpcSignerError "no address found"
method signMessage*(
signer: JsonRpcSigner,
message: seq[byte]): Future[seq[byte]] {.async: (raises:[JsonRpcProviderError]).} =
message: seq[byte]): Future[seq[byte]] {.async: (raises:[SignerError]).} =
convertError:
convertSignerError:
let client = await signer.provider.client
let address = await signer.getAddress()
return await client.eth_sign(address, message)
method sendTransaction*(
signer: JsonRpcSigner,
transaction: Transaction): Future[TransactionResponse] {.async: (raises:[JsonRpcProviderError]).} =
transaction: Transaction): Future[TransactionResponse]
{.async: (raises:[SignerError]).} =
convertError:
convertSignerError:
echo "[jsonrpc.sendTransaction]"
if nonce =? transaction.nonce:
signer.updateNonce(nonce)
let

View File

@ -127,6 +127,25 @@ func fromJson*(_: type UInt256, json: JsonNode): ?!UInt256 =
# Transaction
# TODO: add option that ignores none Option[T]
# TODO: add name option (gasLimit => gas, sender => from)
func `%`*(transaction: Transaction): JsonNode =
result = %*{
"to": transaction.to,
"data": %transaction.data,
"value": %transaction.value
}
if sender =? transaction.`from`:
result["from"] = %sender
if nonce =? transaction.nonce:
result["nonce"] = %nonce
if chainId =? transaction.chainId:
result["chainId"] = %chainId
if gasPrice =? transaction.gasPrice:
result["gasPrice"] = %gasPrice
if gasLimit =? transaction.gasLimit:
result["gas"] = %gasLimit
# proc writeValue*(
# writer: var JsonWriter[JrpcConv],
# value: Transaction
@ -172,6 +191,9 @@ func fromJson*(_: type BlockTag, json: JsonNode): ?!BlockTag =
# TransactionStatus | TransactionType
func `%`*(e: TransactionStatus | TransactionType): JsonNode =
% ("0x" & e.int8.toHex(1))
proc fromJson*[E: TransactionStatus | TransactionType](
T: type E,
json: JsonNode

View File

@ -9,9 +9,7 @@ type
Signer* = ref object of RootObj
lastSeenNonce: ?UInt256
populateLock: AsyncLock
type
SignerError* = object of EthersError
SignerError* = object of ProviderError
EstimateGasError* = object of SignerError
transaction*: Transaction
@ -28,46 +26,78 @@ proc raiseEstimateGasError(
parent: parent)
raise e
method provider*(signer: Signer):
Provider {.base, gcsafe, raises: [EthersError].} =
template convertError(body) =
try:
body
except EthersError as error:
raiseSignerError(error.msg)
except CatchableError as error:
raiseSignerError(error.msg)
method provider*(
signer: Signer): Provider {.base, gcsafe, raises: [SignerError].} =
doAssert false, "not implemented"
method getAddress*(signer: Signer): Future[Address] {.base, async: (raises:[ProviderError]).} =
method getAddress*(
signer: Signer): Future[Address] {.base, async: (raises:[SignerError]).} =
doAssert false, "not implemented"
method signMessage*(signer: Signer,
message: seq[byte]): Future[seq[byte]] {.base, async.} =
method signMessage*(
signer: Signer,
message: seq[byte]): Future[seq[byte]] {.base, async: (raises:[SignerError]).} =
doAssert false, "not implemented"
method sendTransaction*(signer: Signer,
transaction: Transaction): Future[TransactionResponse] {.base, async.} =
method sendTransaction*(
signer: Signer,
transaction: Transaction): Future[TransactionResponse]
{.base, async: (raises:[SignerError]).} =
doAssert false, "not implemented"
method getGasPrice*(signer: Signer):
Future[UInt256] {.base, gcsafe, raises: [EthersError].} =
signer.provider.getGasPrice()
method getGasPrice*(
signer: Signer): Future[UInt256] {.base, gcsafe, async: (raises: [SignerError]).} =
method getTransactionCount*(signer: Signer,
blockTag = BlockTag.latest):
Future[UInt256] {.base, async.} =
let address = await signer.getAddress()
return await signer.provider.getTransactionCount(address, blockTag)
convertError:
return await signer.provider.getGasPrice()
method getTransactionCount*(
signer: Signer,
blockTag = BlockTag.latest): Future[UInt256]
{.base, async: (raises:[SignerError]).} =
convertError:
let address = await signer.getAddress()
return await signer.provider.getTransactionCount(address, blockTag)
method estimateGas*(
signer: Signer,
transaction: Transaction,
blockTag = BlockTag.latest): Future[UInt256]
{.base, async: (raises:[SignerError]).} =
method estimateGas*(signer: Signer,
transaction: Transaction,
blockTag = BlockTag.latest): Future[UInt256] {.base, async.} =
var transaction = transaction
transaction.`from` = some(await signer.getAddress)
var address: Address
convertError:
address = await signer.getAddress
transaction.`from` = some(address)
try:
return await signer.provider.estimateGas(transaction)
except ProviderError as e:
raiseEstimateGasError transaction, e
method getChainId*(signer: Signer):
Future[UInt256] {.base, gcsafe, raises: [EthersError].} =
signer.provider.getChainId()
method getChainId*(
signer: Signer): Future[UInt256] {.base, async: (raises: [SignerError]).} =
convertError:
return await signer.provider.getChainId()
method getNonce(
signer: Signer): Future[UInt256] {.base, async: (raises: [SignerError]).} =
method getNonce(signer: Signer): Future[UInt256] {.base, gcsafe, async.} =
var nonce = await signer.getTransactionCount(BlockTag.pending)
if lastSeen =? signer.lastSeenNonce and lastSeen >= nonce:
@ -92,9 +122,10 @@ method decreaseNonce*(signer: Signer) {.base, gcsafe.} =
if lastSeen =? signer.lastSeenNonce and lastSeen > 0:
signer.lastSeenNonce = some lastSeen - 1
method populateTransaction*(signer: Signer,
transaction: Transaction):
Future[Transaction] {.base, async.} =
method populateTransaction*(
signer: Signer,
transaction: Transaction): Future[Transaction]
{.base, async: (raises: [CancelledError, AsyncLockError, SignerError]).} =
echo "[signer.populatetransaction] signer type: ", typeof signer
if sender =? transaction.`from` and sender != await signer.getAddress():
@ -127,7 +158,7 @@ method populateTransaction*(signer: Signer,
populated.gasLimit = some(await signer.estimateGas(populated))
except ProviderError as e:
signer.decreaseNonce()
raise e
raiseSignerError(e.msg)
except EstimateGasError as e:
signer.decreaseNonce()
raise e

View File

@ -0,0 +1,3 @@
import ../providers/jsonrpc
export provider, getAddress, signMessage, sendTransaction

79
ethers/signers/wallet.nim Normal file
View File

@ -0,0 +1,79 @@
import eth/keys
import ../basics
import ../provider
import ../transaction
import ../signer
import ./wallet/error
import ./wallet/signing
export keys
export WalletError
export signing
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 {.raises: [SignerError].} =
without provider =? wallet.provider:
raiseWalletError "Wallet has no provider"
provider
method getAddress(wallet: Wallet): Future[Address] {.async: (raises:[ProviderError]).} =
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: (raises:[ProviderError]).} =
let signed = await signTransaction(wallet, transaction)
if nonce =? transaction.nonce:
wallet.updateNonce(nonce)
return await provider(wallet).sendTransaction(signed)

View File

@ -0,0 +1,14 @@
import ../../basics
import ../../signer
type
WalletError* = object of SignerError
func raiseWalletError*(message: string) {.raises: [WalletError].}=
raise newException(WalletError, message)
template convertError(body) =
try:
body
except CatchableError as error:
raiseWalletError(error.msg)

View File

@ -2,9 +2,9 @@ import pkg/eth/keys
import pkg/eth/rlp
import pkg/eth/common/transaction as eth
import pkg/eth/common/eth_hash
import ../basics
import ../transaction as ethers
import ../provider
import ../../basics
import ../../transaction as ethers
import ../../provider
import ./error
type

View File

@ -1,76 +1,3 @@
import eth/keys
import ./basics
import ./provider
import ./transaction
import ./signer
import ./wallet/error
import ./wallet/signing
import ./signers/wallet
export keys
export WalletError
export signing
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 {.raises: [WalletError].} =
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.} =
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.} =
let signed = await signTransaction(wallet, transaction)
if nonce =? transaction.nonce:
wallet.updateNonce(nonce)
return await provider(wallet).sendTransaction(signed)
export wallet

View File

@ -1,7 +0,0 @@
import ../basics
type
WalletError* = object of EthersError
func raiseWalletError*(message: string) {.raises: [WalletError].}=
raise newException(WalletError, message)

View File

@ -2,6 +2,8 @@ import std/strutils
import std/unittest
import pkg/ethers/provider
import pkg/ethers/providers/jsonrpc/conversions
import pkg/questionable
import pkg/questionable/results
import pkg/stew/byteutils
func flatten(s: string): string =
@ -111,30 +113,6 @@ suite "JSON Conversions":
fail
check receipt.blockHash.isNone
test "newHeads subcription raises exception when deserializing to Log":
let json = """{
"parentHash":"0xd68d4d0f29307df51e1284fc8a13595ae700ef0f1128830a69e6854381363d42",
"sha3Uncles":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
"miner":"0x0000000000000000000000000000000000000000",
"stateRoot":"0x1f6f2d05de35bbfd50213be96ddf960d62b978b472c55d6ac223cd648cbbbbb0",
"transactionsRoot":"0xb9bb8a26abe091bb628ab2b6585c5af151aeb3984f4ba47a3c65d438283e069d",
"receiptsRoot":"0x33f229b7133e1ba3fb524b8af22d8184ca10b2da5bb170092a219c61ca023c1d",
"logsBloom":"0x00000000000000000000000000000000000000000020000000000002000000000000000000000000000000000000000000000000000008080000100200200000000000000000000000000008000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000010000040000000000100000000000800000000000000000000000000000000020000000000020000000000000000000000000000040000008000000000000000000020000000000002000000000000000000000000000000000000000000000000000001000010000000000000000020002000000020000000000000008002000000000000",
"difficulty":"0x2",
"number":"0x21d",
"gasLimit":"0x1c1b59a7",
"gasUsed":"0xda41b",
"timestamp":"0x6509410e",
"extraData":"0xd883010b05846765746888676f312e32302e32856c696e7578000000000000007102a27d75709b90ca9eb23cdaaccf4fc2d571d710f3bc5a7dc874f43af116a93ff832576a53c16f0d0aa1cd9e9a1dc0a60126c4d420f72b0866fc96ba6664f601",
"mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000",
"nonce":"0x0000000000000000",
"baseFeePerGas":"0x7",
"withdrawalsRoot":null,
"hash":"0x64066c7150c660e5357c4b6b02d836c10353dfa8edb32c805fca9367fd29c6e7"
}"""
expect ValueError:
discard Log.fromJson(parseJson(json))
test "correctly deserializes PastTransaction":
let json = %*{
"blockHash":"0x595bffbe897e025ea2df3213c4cc52c3f3d69bc04b49011d558f1b0e70038922",
@ -159,7 +137,7 @@ suite "JSON Conversions":
fail
check tx.blockHash == BlockHash(array[32, byte].fromHex("0x595bffbe897e025ea2df3213c4cc52c3f3d69bc04b49011d558f1b0e70038922"))
check tx.blockNumber == 0x22e.u256
check tx.sender == Address.init("0xe00b677c29ff8d8fe6068530e2bc36158c54dd34").get
check tx.`from` == Address.init("0xe00b677c29ff8d8fe6068530e2bc36158c54dd34").get
check tx.gas == 0x4d4bb.u256
check tx.gasPrice == 0x3b9aca07.u256
check tx.hash == TransactionHash(array[32, byte].fromHex("0xa31608907c338d6497b0c6ec81049d845c7d409490ebf78171f35143897ca790"))
@ -178,7 +156,7 @@ suite "JSON Conversions":
let tx = PastTransaction(
blockHash: BlockHash(array[32, byte].fromHex("0x595bffbe897e025ea2df3213c4cc52c3f3d69bc04b49011d558f1b0e70038922")),
blockNumber: 0x22e.u256,
sender: Address.init("0xe00b677c29ff8d8fe6068530e2bc36158c54dd34").get,
`from`: Address.init("0xe00b677c29ff8d8fe6068530e2bc36158c54dd34").get,
gas: 0x4d4bb.u256,
gasPrice: 0x3b9aca07.u256,
hash: TransactionHash(array[32, byte].fromHex("0xa31608907c338d6497b0c6ec81049d845c7d409490ebf78171f35143897ca790")),
@ -205,12 +183,12 @@ suite "JSON Conversions":
"nonce":"0x3",
"to":"0x92f09aa59dccb892a9f5406ddd9c0b98f02ea57e",
"transactionIndex":"0x3",
"type":"0x0",
"chainId":"0xc0de4",
"value":"0x0",
"v":"0x181bec",
"r":"0x57ba18460934526333b80b0fea08737c363f3cd5fbec4a25a8a25e3e8acb362a",
"s":"0x33aa50bc8bd719b6b17ad0bf52006bf8943999198f2bf731eb33c118091000f2",
"type":"0x0",
"chainId":"0xc0de4"
"s":"0x33aa50bc8bd719b6b17ad0bf52006bf8943999198f2bf731eb33c118091000f2"
}""".flatten
check $(%tx) == expected
@ -239,6 +217,7 @@ suite "JSON Conversions":
check %past.toTransaction == %*{
"to": !Address.init("0x92f09aa59dccb892a9f5406ddd9c0b98f02ea57e"),
"data": hexToSeqByte("0x6368a471d26ff5c7f835c1a8203235e88846ce1a196d6e79df0eaedd1b8ed3deec2ae5c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000012a00000000000000000000000000000000000000000000000000000000000000"),
"value": "0x0",
"from": !Address.init("0xe00b677c29ff8d8fe6068530e2bc36158c54dd34"),
"nonce": 0x3.u256,
"chainId": 0xc0de4.u256,

View File

@ -1,4 +1,3 @@
import std/json
import pkg/asynctest
import pkg/chronos
import pkg/ethers
@ -97,5 +96,5 @@ for url in ["ws://localhost:8545", "http://localhost:8545"]:
discard await provider.getBlock(BlockTag.latest)
expect JsonRpcProviderError:
discard await provider.subscribe(proc(_: Block) = discard)
expect JsonRpcProviderError:
expect JsonRpcSignerError:
discard await provider.getSigner().sendTransaction(Transaction.example)

View File

@ -52,7 +52,7 @@ suite "JsonRpcSigner":
let signer = provider.getSigner()
let transaction = Transaction.example
let populated = await signer.populateTransaction(transaction)
check !populated.sender == await signer.getAddress()
check !populated.`from` == await signer.getAddress()
check !populated.gasPrice == await signer.getGasPrice()
check !populated.nonce == await signer.getTransactionCount(BlockTag.pending)
check !populated.gasLimit == await signer.estimateGas(transaction)

View File

@ -64,6 +64,7 @@ suite "Web socket subscriptions":
client = newRpcWebSocketClient()
await client.connect("ws://localhost:8545")
subscriptions = JsonRpcSubscriptions.new(client)
subscriptions.init()
teardown:
await subscriptions.close()
@ -81,6 +82,7 @@ suite "HTTP polling subscriptions":
await client.connect("http://localhost:8545")
subscriptions = JsonRpcSubscriptions.new(client,
pollingInterval = 100.millis)
subscriptions.init()
teardown:
await subscriptions.close()