diff --git a/ethers/contract.nim b/ethers/contract.nim index daeecb3..4e3fdf8 100644 --- a/ethers/contract.nim +++ b/ethers/contract.nim @@ -101,8 +101,8 @@ proc call(contract: Contract, overrides = TransactionOverrides()) {.async.} = var transaction = createTransaction(contract, function, parameters, overrides) - if signer =? contract.signer and transaction.sender.isNone: - transaction.sender = some(await signer.getAddress()) + if signer =? contract.signer and transaction.`from`.isNone: + transaction.`from` = some(await signer.getAddress()) discard await contract.provider.call(transaction, overrides) @@ -114,8 +114,8 @@ proc call(contract: Contract, overrides = TransactionOverrides()): Future[ReturnType] {.async.} = var transaction = createTransaction(contract, function, parameters, overrides) - if signer =? contract.signer and transaction.sender.isNone: - transaction.sender = some(await signer.getAddress()) + if signer =? contract.signer and transaction.`from`.isNone: + transaction.`from` = some(await signer.getAddress()) let response = await contract.provider.call(transaction, overrides) return decodeResponse(ReturnType, returnMultiple, response) diff --git a/ethers/provider.nim b/ethers/provider.nim index 8fd3fe2..d5dd22d 100644 --- a/ethers/provider.nim +++ b/ethers/provider.nim @@ -39,7 +39,7 @@ type provider*: Provider hash* {.serialize.}: TransactionHash TransactionReceipt* = object - sender* {.serialize.}: ?Address + `from`* {.serialize.}: ?Address to* {.serialize.}: ?Address contractAddress* {.serialize.}: ?Address transactionIndex* {.serialize.}: UInt256 @@ -51,7 +51,7 @@ type blockNumber* {.serialize.}: ?UInt256 cumulativeGasUsed* {.serialize.}: UInt256 effectiveGasPrice* {.serialize.}: ?UInt256 - status*: TransactionStatus + status* {.serialize.}: TransactionStatus `type`* {.serialize.}: TransactionType LogHandler* = proc(log: Log) {.gcsafe, raises:[].} BlockHandler* = proc(blck: Block) {.gcsafe, raises:[].} @@ -63,7 +63,7 @@ type PastTransaction* = object blockHash* {.serialize.}: BlockHash blockNumber* {.serialize.}: UInt256 - sender* {.serialize.}: Address + `from`* {.serialize.}: Address gas* {.serialize.}: UInt256 gasPrice* {.serialize.}: UInt256 hash* {.serialize.}: TransactionHash @@ -87,7 +87,7 @@ template raiseProviderError(msg: string) = func toTransaction*(past: PastTransaction): Transaction = Transaction( - sender: some past.sender, + `from`: some past.`from`, gasPrice: some past.gasPrice, data: past.input, nonce: some past.nonce, diff --git a/ethers/providers/jsonrpc/conversions.nim b/ethers/providers/jsonrpc/conversions.nim index 8cdd5b0..895088e 100644 --- a/ethers/providers/jsonrpc/conversions.nim +++ b/ethers/providers/jsonrpc/conversions.nim @@ -31,6 +31,15 @@ proc getOrRaise*[T, E](self: ?!T, exc: typedesc[E]): T {.raises: [E].} = raise newException(E, self.error.msg) val +template mapFailure*[T, V, E]( + exp: Result[T, V], + exc: typedesc[E], +): Result[T, ref CatchableError] = + ## Convert `Result[T, E]` to `Result[E, ref CatchableError]` + ## + + exp.mapErr(proc (e: V): ref CatchableError = (ref exc)(msg: e.msg)) + proc expectFields(json: JsonNode, expectedFields: varargs[string]) = for fieldName in expectedFields: if not json.hasKey(fieldName): @@ -161,6 +170,16 @@ func fromJson*(_: type BlockTag, json: JsonNode): ?!BlockTag = "Failed to convert '" & $json & "' to BlockTag: must be one of 'earliest', 'latest', 'pending'") +# TransactionStatus | TransactionType + +proc fromJson*[E: TransactionStatus | TransactionType]( + T: type E, + json: JsonNode +): ?!T = + expectJsonKind(string, JString, json) + let integer = ? fromHex[int](json.str).catch.mapFailure(SerializationError) + success T(integer) + # proc readValue*(r: var JsonReader[JrpcConv], # result: var BlockTag) {.raises:[SerializationError, IOError].} = # var json = r.readValue(JsonNode) diff --git a/ethers/providers/jsonrpc/json.nim b/ethers/providers/jsonrpc/json.nim index 66f6194..8681a59 100644 --- a/ethers/providers/jsonrpc/json.nim +++ b/ethers/providers/jsonrpc/json.nim @@ -10,6 +10,7 @@ import pkg/chronicles import pkg/contractabi import pkg/stew/byteutils import pkg/stint +import pkg/questionable import pkg/questionable/results import ../../basics @@ -204,7 +205,6 @@ proc fromJson*[T: ref object or object]( _: type T, json: JsonNode ): ?!T = - when T is JsonNode: return success T(json) @@ -212,17 +212,25 @@ proc fromJson*[T: ref object or object]( var res = when type(T) is ref: T.new() else: T.default # Leave this in, it's good for debugging: - # trace "deserializing object", to = $T, json + trace "deserializing object", to = $T, json for name, value in fieldPairs(when type(T) is ref: res[] else: res): - if jsonVal =? json{name}.catch and not jsonVal.isNil: + logScope: + field = $T & "." & name + + if name in json and + jsonVal =? json{name}.catch and + not jsonVal.isNil: + without parsed =? type(value).fromJson(jsonVal), e: error "error deserializing field", - field = $T & "." & name, json = jsonVal, error = e.msg return failure(e) value = parsed + + else: + debug "object field does not exist in json, skipping", json success(res) proc parse*(json: string): ?!JsonNode = @@ -240,48 +248,6 @@ proc fromJson*[T: ref object or object]( let json = ? parse(string.fromBytes(bytes)) T.fromJson(json) - -# import std/streams -# import std/parsejson - -# type StringStreamFixed = ref object of StringStream -# closeImplFixed: proc (s: StringStreamFixed) -# {.nimcall, raises: [IOError, OSError], tags: [WriteIOEffect], gcsafe.} - -# proc closeImpl*: proc (s: StringStreamFixed) -# {.nimcall, raises: [IOError, OSError], tags: [WriteIOEffect], gcsafe.} = discard - -# proc ssCloseFixed(s: StringStreamFixed) = -# # var s = StringStream(s) -# s.data = "" - -# proc close*(s: StringStreamFixed) {.raises: [IOError, OSError].} = -# ## Closes the stream `s`. -# ## -# ## See also: -# ## * `flush proc <#flush,Stream>`_ -# # runnableExamples: -# # var strm = newStringStream("The first line\nthe second line\nthe third line") -# # ## do something... -# # strm.close() -# if not isNil(s.closeImplFixed): s.closeImplFixed(s) - -# proc newStringStreamFixed*(s: sink string = ""): owned StringStreamFixed {.raises:[].} = -# var ss = StringStreamFixed(newStringStream(s)) -# ss.closeImplFixed = ssCloseFixed -# ss - - -# proc parseJson*(buffer: string; rawIntegers = false, rawFloats = false): JsonNode {.raises: [IOError, OSError, JsonParsingError, ValueError].} = -# ## Parses JSON from `buffer`. -# ## If `buffer` contains extra data, it will raise `JsonParsingError`. -# ## If `rawIntegers` is true, integer literals will not be converted to a `JInt` -# ## field but kept as raw numbers via `JString`. -# ## If `rawFloats` is true, floating point literals will not be converted to a `JFloat` -# ## field but kept as raw numbers via `JString`. -# result = parseJson(newStringStreamFixed(buffer), "input", rawIntegers, rawFloats) - - proc fromJson*( _: type JsonNode, json: string @@ -293,6 +259,7 @@ proc fromJson*[T: ref object or object]( _: type T, json: string ): ?!T = + echo "[T.fromJson] T: ", T, ", json string: ", json let json = ? parse(json) T.fromJson(json) diff --git a/ethers/signer.nim b/ethers/signer.nim index 07ded5b..e60d963 100644 --- a/ethers/signer.nim +++ b/ethers/signer.nim @@ -57,7 +57,7 @@ method estimateGas*(signer: Signer, transaction: Transaction, blockTag = BlockTag.latest): Future[UInt256] {.base, async.} = var transaction = transaction - transaction.sender = some(await signer.getAddress) + transaction.`from` = some(await signer.getAddress) try: return await signer.provider.estimateGas(transaction) except ProviderError as e: @@ -97,7 +97,7 @@ method populateTransaction*(signer: Signer, Future[Transaction] {.base, async.} = echo "[signer.populatetransaction] signer type: ", typeof signer - if sender =? transaction.sender and sender != await signer.getAddress(): + if sender =? transaction.`from` and sender != await signer.getAddress(): raiseSignerError("from address mismatch") if chainId =? transaction.chainId and chainId != await signer.getChainId(): raiseSignerError("chain id mismatch") @@ -110,8 +110,8 @@ method populateTransaction*(signer: Signer, var populated = transaction try: - if transaction.sender.isNone: - populated.sender = some(await signer.getAddress()) + if transaction.`from`.isNone: + populated.`from` = some(await signer.getAddress()) if transaction.chainId.isNone: populated.chainId = some(await signer.getChainId()) if transaction.gasPrice.isNone and (transaction.maxFee.isNone or transaction.maxPriorityFee.isNone): @@ -150,7 +150,7 @@ method cancelTransaction*( # cancels a transaction by sending with a 0-valued transaction to ourselves # with the failed tx's nonce - without sender =? tx.sender: + without sender =? tx.`from`: raiseSignerError "transaction must have sender" without nonce =? tx.nonce: raiseSignerError "transaction must have nonce" diff --git a/ethers/transaction.nim b/ethers/transaction.nim index 19ac8dc..4d3128b 100644 --- a/ethers/transaction.nim +++ b/ethers/transaction.nim @@ -8,7 +8,7 @@ type AccessList = 1, Dynamic = 2 Transaction* = object - sender* {.serialize.}: ?Address + `from`* {.serialize.}: ?Address to* {.serialize.}: Address data* {.serialize.}: seq[byte] value* {.serialize.}: UInt256 @@ -22,7 +22,7 @@ type func `$`*(transaction: Transaction): string = result = "(" - if sender =? transaction.sender: + if sender =? transaction.`from`: result &= "from: " & $sender & ", " result &= "to: " & $transaction.to & ", " result &= "value: " & $transaction.value & ", " diff --git a/ethers/wallet.nim b/ethers/wallet.nim index 83b21fb..a773a8f 100644 --- a/ethers/wallet.nim +++ b/ethers/wallet.nim @@ -64,7 +64,7 @@ method getAddress(wallet: Wallet): Future[Address] {.async.} = proc signTransaction*(wallet: Wallet, transaction: Transaction): Future[seq[byte]] {.async.} = - if sender =? transaction.sender and sender != wallet.address: + if sender =? transaction.`from` and sender != wallet.address: raiseWalletError "from address mismatch" return wallet.privateKey.sign(transaction) diff --git a/testmodule/providers/jsonrpc/testJsonRpcSigner.nim b/testmodule/providers/jsonrpc/testJsonRpcSigner.nim index 34d78ea..1b057f3 100644 --- a/testmodule/providers/jsonrpc/testJsonRpcSigner.nim +++ b/testmodule/providers/jsonrpc/testJsonRpcSigner.nim @@ -61,7 +61,7 @@ suite "JsonRpcSigner": test "populate does not overwrite existing fields": let signer = provider.getSigner() var transaction = Transaction.example - transaction.sender = some await signer.getAddress() + transaction.`from` = some await signer.getAddress() transaction.nonce = some UInt256.example transaction.chainId = some await signer.getChainId() transaction.gasPrice = some UInt256.example @@ -72,7 +72,7 @@ suite "JsonRpcSigner": test "populate fails when sender does not match signer address": let signer = provider.getSigner() var transaction = Transaction.example - transaction.sender = accounts[1].some + transaction.`from` = accounts[1].some expect SignerError: discard await signer.populateTransaction(transaction)