diff --git a/ethers/providers/jsonrpc.nim b/ethers/providers/jsonrpc.nim index 727e653..f213fd1 100644 --- a/ethers/providers/jsonrpc.nim +++ b/ethers/providers/jsonrpc.nim @@ -2,6 +2,7 @@ import std/json import std/tables import std/uri import pkg/json_rpc/rpcclient +import pkg/json_rpc/errors import ../basics import ../provider import ../signer @@ -30,6 +31,12 @@ type template raiseProviderError(message: string) = raise newException(JsonRpcProviderError, message) +template convertError(body) = + try: + body + except JsonRpcError as error: + raiseProviderError(error.msg) + # Provider const defaultUrl = "http://localhost:8545" @@ -77,12 +84,14 @@ proc new*(_: type JsonRpcProvider, url=defaultUrl): JsonRpcProvider = proc send*(provider: JsonRpcProvider, call: string, arguments: seq[JsonNode] = @[]): Future[JsonNode] {.async.} = - let client = await provider.client - return await client.call(call, %arguments) + convertError: + let client = await provider.client + return await client.call(call, %arguments) proc listAccounts*(provider: JsonRpcProvider): Future[seq[Address]] {.async.} = - let client = await provider.client - return await client.eth_accounts() + convertError: + let client = await provider.client + return await client.eth_accounts() proc getSigner*(provider: JsonRpcProvider): JsonRpcSigner = JsonRpcSigner(provider: provider) @@ -91,60 +100,69 @@ proc getSigner*(provider: JsonRpcProvider, address: Address): JsonRpcSigner = JsonRpcSigner(provider: provider, address: some address) method getBlockNumber*(provider: JsonRpcProvider): Future[UInt256] {.async.} = - let client = await provider.client - return await client.eth_blockNumber() + convertError: + let client = await provider.client + return await client.eth_blockNumber() method getBlock*(provider: JsonRpcProvider, tag: BlockTag): Future[?Block] {.async.} = - let client = await provider.client - return await client.eth_getBlockByNumber(tag, false) + convertError: + let client = await provider.client + return await client.eth_getBlockByNumber(tag, false) method call*(provider: JsonRpcProvider, tx: Transaction, blockTag = BlockTag.latest): Future[seq[byte]] {.async.} = - let client = await provider.client - return await client.eth_call(tx, blockTag) + convertError: + let client = await provider.client + return await client.eth_call(tx, blockTag) method getGasPrice*(provider: JsonRpcProvider): Future[UInt256] {.async.} = - let client = await provider.client - return await client.eth_gasprice() + convertError: + let client = await provider.client + return await client.eth_gasprice() method getTransactionCount*(provider: JsonRpcProvider, address: Address, blockTag = BlockTag.latest): Future[UInt256] {.async.} = - let client = await provider.client - return await client.eth_getTransactionCount(address, blockTag) + convertError: + let client = await provider.client + return await client.eth_getTransactionCount(address, blockTag) method getTransactionReceipt*(provider: JsonRpcProvider, txHash: TransactionHash): Future[?TransactionReceipt] {.async.} = - let client = await provider.client - return await client.eth_getTransactionReceipt(txHash) + convertError: + let client = await provider.client + return await client.eth_getTransactionReceipt(txHash) method estimateGas*(provider: JsonRpcProvider, transaction: Transaction): Future[UInt256] {.async.} = - let client = await provider.client - return await client.eth_estimateGas(transaction) + convertError: + let client = await provider.client + return await client.eth_estimateGas(transaction) method getChainId*(provider: JsonRpcProvider): Future[UInt256] {.async.} = - let client = await provider.client - try: - return await client.eth_chainId() - except CatchableError: - return parse(await client.net_version(), UInt256) + convertError: + let client = await provider.client + try: + return await client.eth_chainId() + except CatchableError: + return parse(await client.net_version(), UInt256) proc subscribe(provider: JsonRpcProvider, name: string, filter: ?Filter, handler: SubscriptionHandler): Future[Subscription] {.async.} = - let client = await provider.client - doAssert client of RpcWebSocketClient, "subscriptions require websockets" + convertError: + let client = await provider.client + doAssert client of RpcWebSocketClient, "subscriptions require websockets" - let id = await client.eth_subscribe(name, filter) - provider.subscriptions[id] = handler + let id = await client.eth_subscribe(name, filter) + provider.subscriptions[id] = handler - return JsonRpcSubscription(id: id, provider: provider) + return JsonRpcSubscription(id: id, provider: provider) method subscribe*(provider: JsonRpcProvider, filter: Filter, @@ -164,10 +182,11 @@ method subscribe*(provider: JsonRpcProvider, return await provider.subscribe("newHeads", Filter.none, handler) method unsubscribe*(subscription: JsonRpcSubscription) {.async.} = - let provider = subscription.provider - provider.subscriptions.del(subscription.id) - let client = await provider.client - discard await client.eth_unsubscribe(subscription.id) + convertError: + let provider = subscription.provider + provider.subscriptions.del(subscription.id) + let client = await provider.client + discard await client.eth_unsubscribe(subscription.id) # Signer @@ -186,14 +205,16 @@ method getAddress*(signer: JsonRpcSigner): Future[Address] {.async.} = method signMessage*(signer: JsonRpcSigner, message: seq[byte]): Future[seq[byte]] {.async.} = - let client = await signer.provider.client - let address = await signer.getAddress() - return await client.eth_sign(address, message) + convertError: + 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.} = - let - client = await signer.provider.client - hash = await client.eth_sendTransaction(transaction) + convertError: + let + client = await signer.provider.client + hash = await client.eth_sendTransaction(transaction) - return TransactionResponse(hash: hash, provider: signer.provider) + return TransactionResponse(hash: hash, provider: signer.provider) diff --git a/testmodule/testJsonRpcProvider.nim b/testmodule/testJsonRpcProvider.nim index f097241..872305f 100644 --- a/testmodule/testJsonRpcProvider.nim +++ b/testmodule/testJsonRpcProvider.nim @@ -241,3 +241,17 @@ suite "JsonRpcProvider": wantedConfirms = int.high check receipt.hasBeenMined(currentBlock, wantedConfirms) + test "raises JsonRpcProviderError when something goes wrong": + let provider = JsonRpcProvider.new("http://invalid.") + expect JsonRpcProviderError: + discard await provider.listAccounts() + expect JsonRpcProviderError: + discard await provider.send("evm_mine") + expect JsonRpcProviderError: + discard await provider.getBlockNumber() + expect JsonRpcProviderError: + discard await provider.getBlock(BlockTag.latest) + expect JsonRpcProviderError: + discard await provider.subscribe(proc(_: Block) {.async.} = discard) + expect JsonRpcProviderError: + discard await provider.getSigner().sendTransaction(Transaction.example)