From 0adf56c65b3b86831ea3e71a7872110cb9b05a1a Mon Sep 17 00:00:00 2001 From: Eric Mastro Date: Fri, 19 Aug 2022 15:09:37 +1000 Subject: [PATCH] Support distinct types for Event fields Add support for indexed (and non-indexed) Event fields types that are distinct `ValueType` or `SmallByteArray`. For example, ```nim type DistinctAlias = distinct array[32, byte] MyEvent = object of Event a {.indexed.}: DistinctAlias b: DistinctAlias # also allowed for non-indexed fields ## The below funcs generally need to be included for ABI ## encoding/decoding purposes when implementing distinct types. func toArray(value: DistinctAlias): array[32, byte] = array[32, byte](value) func encode*(encoder: var AbiEncoder, value: DistinctAlias) = encoder.write(value.toArray) func decode*(decoder: var AbiDecoder, T: type DistinctAlias): ?!T = let d = ?decoder.read(type array[32, byte]) success DistinctAlias(d) ``` --- Readme.md | 29 +++++++++++++++++++++++++++++ ethers/events.nim | 8 ++++++-- testmodule/testEvents.nim | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 74 insertions(+), 2 deletions(-) diff --git a/Readme.md b/Readme.md index 531153c..518e8d6 100644 --- a/Readme.md +++ b/Readme.md @@ -106,6 +106,35 @@ type Transfer = object of Event Notice that `Transfer` inherits from `Event`, and that some event parameters are marked with `{.indexed.}` to match the definition in Solidity. +Note that valid types of indexed parameters are: +```nim +uint8 | uint16 | uint32 | uint64 | UInt256 | UInt128 | +int8 | int16 | int32 | int64 | Int256 | Int128 | +bool | Address | array[ 1..32, byte] +``` +Distinct types of valid types are also supported for indexed fields, eg: +```nim +type + DistinctAlias = distinct array[32, byte] + MyEvent = object of Event + a {.indexed.}: DistinctAlias + b: DistinctAlias # also allowed for non-indexed fields + +## The below funcs generally need to be included for ABI +## encoding/decoding purposes when implementing distinct types. + +func toArray(value: DistinctAlias): array[32, byte] = + array[32, byte](value) + +func encode*(encoder: var AbiEncoder, value: DistinctAlias) = + encoder.write(value.toArray) + +func decode*(decoder: var AbiDecoder, + T: type DistinctAlias): ?!T = + let d = ?decoder.read(type array[32, byte]) + success DistinctAlias(d) +``` + You can now subscribe to Transfer events by calling `subscribe` on the contract instance. diff --git a/ethers/events.nim b/ethers/events.nim index 23f9058..85a28e3 100644 --- a/ethers/events.nim +++ b/ethers/events.nim @@ -1,4 +1,5 @@ import std/macros +import std/typetraits import pkg/contractabi import ./basics import ./provider @@ -40,7 +41,10 @@ func decode*[E: Event](_: type E, data: seq[byte], topics: seq[Topic]): ?!E = if field.hasCustomPragma(indexed): if i >= topics.len: return failure "indexed event parameter not found" - if typeof(field) is ValueType or typeof(field) is SmallByteArray: - field = ?AbiDecoder.decode(@(topics[i]), typeof(field)) + if typeof(field) is ValueType or + typeof(field) is SmallByteArray or + typeof(field).distinctBase is ValueType or + typeof(field).distinctBase is SmallByteArray: + field = ?AbiDecoder.decode(@(topics[i]), typeof(field)) inc i success event diff --git a/testmodule/testEvents.nim b/testmodule/testEvents.nim index 3636cdf..a104b46 100644 --- a/testmodule/testEvents.nim +++ b/testmodule/testEvents.nim @@ -3,6 +3,26 @@ import pkg/ethers import pkg/contractabi import ./examples +## Define outside the scope of the suite to allow for exporting +## To use custom distinct types, these procs will generally need +## to be defined in the application code anyway, to support ABI +## encoding/decoding +type + DistinctAlias = distinct array[32, byte] + +proc `==`*(x, y: DistinctAlias): bool {.borrow.} + +func toArray(value: DistinctAlias): array[32, byte] = + array[32, byte](value) + +func encode*(encoder: var AbiEncoder, value: DistinctAlias) = + encoder.write(value.toArray) + +func decode*(decoder: var AbiDecoder, + T: type DistinctAlias): ?!T = + let d = ?decoder.read(type array[32, byte]) + success DistinctAlias(d) + suite "Events": type @@ -25,6 +45,9 @@ suite "Events": d {.indexed.}: seq[byte] e {.indexed.}: (Address, UInt256) f {.indexed.}: array[33, byte] + IndexedWithDistinctType = object of Event + a {.indexed.}: DistinctAlias + b: DistinctAlias proc example(_: type SimpleEvent): SimpleEvent = SimpleEvent( @@ -47,6 +70,14 @@ suite "Events": e: array[32, byte].example ) + proc example(_: type IndexedWithDistinctType): IndexedWithDistinctType = + IndexedWithDistinctType( + a: DistinctAlias(array[32, byte].example) + ) + + func encode(_: type AbiEncoder, value: DistinctAlias): seq[byte] = + @(value.toArray) + func encode[T](_: type Topic, value: T): Topic = let encoded = AbiEncoder.encode(value) result[0..