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) ```
This commit is contained in:
parent
e1a1a3805b
commit
0adf56c65b
29
Readme.md
29
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.
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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..<Topic.len] = encoded[0..<Topic.len]
|
||||
|
@ -71,6 +102,14 @@ suite "Events":
|
|||
let data = AbiEncoder.encode( (event.a, event.c) )
|
||||
check IndexedEvent.decode(data, topics) == success event
|
||||
|
||||
test "decodes indexed fields with distinct types":
|
||||
let event = IndexedWithDistinctType.example
|
||||
var topics: seq[Topic]
|
||||
topics.add Topic.default
|
||||
topics.add Topic.encode(event.a)
|
||||
let data = AbiEncoder.encode( (event.b,) )
|
||||
check IndexedWithDistinctType.decode(data, topics) == success event
|
||||
|
||||
test "fails when data is incomplete":
|
||||
let event = SimpleEvent.example
|
||||
let invalid = AbiEncoder.encode( (event.a,) )
|
||||
|
|
Loading…
Reference in New Issue