Event decoding from data and topics

This commit is contained in:
Mark Spanbroek 2022-02-01 15:49:36 +01:00 committed by markspanbroek
parent 27d6e89672
commit 21f98c4086
4 changed files with 115 additions and 0 deletions

View File

@ -4,9 +4,11 @@ import pkg/contractabi
import ./basics import ./basics
import ./provider import ./provider
import ./signer import ./signer
import ./events
export basics export basics
export provider export provider
export events
type type
Contract* = ref object of RootObj Contract* = ref object of RootObj

34
ethers/events.nim Normal file
View File

@ -0,0 +1,34 @@
import std/macros
import pkg/contractabi
import ./basics
type
Event* = object of RootObj
Topic* = array[32, byte]
ValueType = uint8 | uint16 | uint32 | uint64 | UInt256 | UInt128 |
int8 | int16 | int32 | int64 | Int256 | Int128 |
bool | Address
push: {.upraises: [].}
template indexed* {.pragma.}
func decode[E: Event](decoder: var AbiDecoder, _: type E): ?!E =
var event: E
for field in event.fields:
if not field.hasCustomPragma(indexed):
field = ?decoder.read(typeof(field))
success event
func decode*[E: Event](_: type E, data: seq[byte], topics: seq[Topic]): ?!E =
bind decode
var event = ?Abidecoder.decode(data, E)
var i = 1
for field in event.fields:
if field.hasCustomPragma(indexed):
if i >= topics.len:
return failure "indexed event parameter not found"
if typeof(field) is ValueType:
field = ?AbiDecoder.decode(@(topics[i]), typeof(field))
inc i
success event

View File

@ -1,5 +1,6 @@
import ./testJsonRpcProvider import ./testJsonRpcProvider
import ./testJsonRpcSigner import ./testJsonRpcSigner
import ./testContracts import ./testContracts
import ./testEvents
{.warning[UnusedImport]:off.} {.warning[UnusedImport]:off.}

78
testmodule/testEvents.nim Normal file
View File

@ -0,0 +1,78 @@
import pkg/asynctest
import pkg/ethers
import pkg/contractabi
import ./examples
suite "Events":
type
SimpleEvent = object of Event
a: UInt256
b: Address
IndexedEvent = object of Event
a: UInt256
b {.indexed.}: Address
c: Address
d {.indexed.}: UInt256
ComplexIndexedEvent = object of Event
a {.indexed.}: array[42, UInt256]
b {.indexed.}: seq[UInt256]
c {.indexed.}: string
d {.indexed.}: seq[byte]
e {.indexed.}: (Address, UInt256)
proc example(_: type SimpleEvent): SimpleEvent =
SimpleEvent(
a: UInt256.example,
b: Address.example
)
proc example(_: type IndexedEvent): IndexedEvent =
IndexedEvent(
a: UInt256.example,
b: Address.example,
c: Address.example,
d: UInt256.example
)
func encode[T](_: type Topic, value: T): Topic =
let encoded = AbiEncoder.encode(value)
result[0..<Topic.len] = encoded[0..<Topic.len]
test "decodes event fields":
let event = SimpleEvent.example
let data = AbiEncoder.encode( (event.a, event.b) )
check SimpleEvent.decode(data, @[]) == success event
test "decodes indexed fields":
let event = IndexedEvent.example
var topics: seq[Topic]
topics.add Topic.default
topics.add Topic.encode(event.b)
topics.add Topic.encode(event.d)
let data = AbiEncoder.encode( (event.a, event.c) )
check IndexedEvent.decode(data, topics) == success event
test "fails when data is incomplete":
let event = SimpleEvent.example
let invalid = AbiEncoder.encode( (event.a,) )
check SimpleEvent.decode(invalid, @[]).isFailure
test "fails when topics are incomplete":
let event = IndexedEvent.example
var invalid: seq[Topic]
invalid.add Topic.default
invalid.add Topic.encode(event.b)
let data = AbiEncoder.encode( (event.a, event.c) )
check IndexedEvent.decode(data, invalid).isFailure
test "ignores indexed complex arguments":
let topics = @[
Topic.default,
Topic.example,
Topic.example,
Topic.example,
Topic.example,
Topic.example
]
check ComplexIndexedEvent.decode(@[], topics) == success ComplexIndexedEvent()