219 lines
6.4 KiB
Nim

# import std/json
import std/strformat
import std/strutils
import std/sugar
# import pkg/eth/common/eth_types_json_serialization
import pkg/chronicles except fromJson, `%`, `%*`, toJson
import pkg/json_rpc/jsonmarshal
import pkg/questionable/results
import pkg/stew/byteutils
import ../../basics
import ../../transaction
import ../../blocktag
import ../../provider
import ./json
export jsonmarshal
export json
export chronicles except fromJson, `%`, `%*`, toJson
# {.push raises: [].}
type JsonSerializationError = object of EthersError
func toException*(v: ref CatchableError): ref SerializationError = (ref SerializationError)(msg: v.msg)
template raiseSerializationError(message: string) =
raise newException(JsonSerializationError, message)
proc getOrRaise*[T, E](self: ?!T, exc: typedesc[E]): T {.raises: [E].} =
let val = self.valueOr:
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):
raiseSerializationError("'" & fieldName & "' field not found in " & $json)
# Address
func `%`*(address: Address): JsonNode =
%($address)
func fromJson(_: type Address, json: JsonNode): ?!Address =
expectJsonKind(Address, JString, json)
without address =? Address.init(json.getStr), error:
return failure newException(SerializationError,
"Failed to convert '" & $json & "' to Address: " & error.msg)
success address
# proc readValue*(
# r: var JsonReader[JrpcConv],
# result: var Address) {.raises: [SerializationError, IOError].} =
# let json = r.readValue(JsonNode)
# result = Address.fromJson(json).getOrRaise(SerializationError)
# proc writeValue*(
# writer: var JsonWriter[JrpcConv],
# value: Address
# ) {.raises:[IOError].} =
# writer.writeValue(%value)
# Filter
# func `%`*(filter: Filter): JsonNode =
# %*{
# "fromBlock": filter.fromBlock,
# "toBlock": filter.toBlock
# }
# proc writeValue*(
# writer: var JsonWriter[JrpcConv],
# value: Filter
# ) {.raises:[IOError].} =
# writer.writeValue(%value)
# EventFilter
# func `%`*(filter: EventFilter): JsonNode =
# %*{
# "address": filter.address,
# "topics": filter.topics
# }
# proc writeValue*(
# writer: var JsonWriter[JrpcConv],
# value: EventFilter
# ) {.raises:[IOError].} =
# writer.writeValue(%value)
# UInt256
func `%`*(integer: UInt256): JsonNode =
%("0x" & toHex(integer))
func fromJson*(_: type UInt256, json: JsonNode): ?!UInt256 =
without result =? UInt256.fromHex(json.getStr()).catch, error:
return UInt256.failure error.msg
success result
# proc writeValue*(
# w: var JsonWriter, value: StUint) {.inline, raises: [IOError].} =
# echo "writing UInt256 value to hex: ", value.toString, ", in hex: ", value.toHex
# w.writeValue %value
# proc readValue*(
# r: var JsonReader, value: var StUint
# ) {.inline, raises: [IOError, SerializationError].} =
# let json = r.readValue(JsonNode)
# value = typeof(value).fromJson(json).getOrRaise(SerializationError)
# TransactionHash
# proc readValue*(
# r: var JsonReader, value: var TransactionHash
# ) {.inline, raises: [IOError, SerializationError].} =
# let json = r.readValue(JsonNode)
# value = TransactionHash.fromJson(json).getOrRaise(SerializationError)
# Transaction
# proc writeValue*(
# writer: var JsonWriter[JrpcConv],
# value: Transaction
# ) {.raises:[IOError].} =
# writer.writeValue(%value)
# Block
# proc readValue*(r: var JsonReader[JrpcConv], result: var Option[Block])
# {.raises: [SerializationError, IOError].} =
# var json = r.readValue(JsonNode)
# if json.isNil or json.kind == JNull:
# result = none Block
# result = Option[Block].fromJson(json).getOrRaise(SerializationError)
# BlockTag
# proc writeValue*(
# writer: var JsonWriter[JrpcConv],
# value: BlockTag
# ) {.raises:[IOError].} =
# writer.writeValue($value)
func `%`*(tag: BlockTag): JsonNode =
% $tag
func fromJson*(_: type BlockTag, json: JsonNode): ?!BlockTag =
expectJsonKind(BlockTag, JString, json)
let jsonVal = json.getStr
if jsonVal[0..1].toLowerAscii == "0x":
without blkNum =? UInt256.fromHex(jsonVal).catch, error:
return BlockTag.failure error.msg
return success BlockTag.init(blkNum)
case jsonVal:
of "earliest": return success BlockTag.earliest
of "latest": return success BlockTag.latest
of "pending": return success BlockTag.pending
else: return failure newException(SerializationError,
"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)
# result = BlockTag.fromJson(json).getOrRaise(SerializationError)
# PastTransaction
# proc readValue*(r: var JsonReader[JrpcConv], result: var Option[PastTransaction])
# {.raises: [SerializationError, IOError].} =
# var json = r.readValue(JsonNode)
# result = Option[PastTransaction].fromJson(json).getOrRaise(SerializationError)
# TransactionReceipt
# proc readValue*(r: var JsonReader[JrpcConv], result: var Option[TransactionReceipt])
# {.raises: [SerializationError, IOError].} =
# var json = r.readValue(JsonNode)
# result = Option[TransactionReceipt].fromJson(json).getOrRaise(SerializationError)
proc writeValue*[T: not JsonNode](
writer: var JsonWriter[JrpcConv],
value: T) {.raises:[IOError].} =
writer.writeValue(%value)
proc readValue*[T: not JsonNode](
r: var JsonReader[JrpcConv],
result: var T) {.raises: [SerializationError, IOError].} =
var json = r.readValue(JsonNode)
# when T of JsonNode:
# result = json
# return
# echo "[conversions.readValue] converting '", json, "' into ", T
static: echo "[conversions.readValue] converting into ", T
result = T.fromJson(json).getOrRaise(SerializationError)