2022-02-01 14:49:36 +00:00
|
|
|
import pkg/asynctest
|
|
|
|
import pkg/ethers
|
|
|
|
import pkg/contractabi
|
|
|
|
import ./examples
|
|
|
|
|
2022-08-19 05:09:37 +00:00
|
|
|
## 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)
|
|
|
|
|
2022-02-01 14:49:36 +00:00
|
|
|
suite "Events":
|
|
|
|
|
|
|
|
type
|
|
|
|
SimpleEvent = object of Event
|
|
|
|
a: UInt256
|
|
|
|
b: Address
|
2022-04-13 08:05:41 +00:00
|
|
|
DynamicSizeEvent = object of Event
|
|
|
|
a: array[32, byte]
|
|
|
|
b: seq[byte]
|
2022-02-01 14:49:36 +00:00
|
|
|
IndexedEvent = object of Event
|
|
|
|
a: UInt256
|
|
|
|
b {.indexed.}: Address
|
|
|
|
c: Address
|
|
|
|
d {.indexed.}: UInt256
|
2022-03-29 08:26:31 +00:00
|
|
|
e {.indexed.}: array[32, byte]
|
2022-02-01 14:49:36 +00:00
|
|
|
ComplexIndexedEvent = object of Event
|
|
|
|
a {.indexed.}: array[42, UInt256]
|
|
|
|
b {.indexed.}: seq[UInt256]
|
|
|
|
c {.indexed.}: string
|
|
|
|
d {.indexed.}: seq[byte]
|
|
|
|
e {.indexed.}: (Address, UInt256)
|
2022-03-29 08:26:31 +00:00
|
|
|
f {.indexed.}: array[33, byte]
|
2022-08-19 05:09:37 +00:00
|
|
|
IndexedWithDistinctType = object of Event
|
|
|
|
a {.indexed.}: DistinctAlias
|
|
|
|
b: DistinctAlias
|
2022-02-01 14:49:36 +00:00
|
|
|
|
|
|
|
proc example(_: type SimpleEvent): SimpleEvent =
|
|
|
|
SimpleEvent(
|
|
|
|
a: UInt256.example,
|
|
|
|
b: Address.example
|
|
|
|
)
|
|
|
|
|
2022-04-13 08:05:41 +00:00
|
|
|
proc example(_: type DynamicSizeEvent): DynamicSizeEvent =
|
|
|
|
DynamicSizeEvent(
|
|
|
|
a: array[32, byte].example,
|
|
|
|
b: seq[byte].example
|
|
|
|
)
|
|
|
|
|
2022-02-01 14:49:36 +00:00
|
|
|
proc example(_: type IndexedEvent): IndexedEvent =
|
|
|
|
IndexedEvent(
|
|
|
|
a: UInt256.example,
|
|
|
|
b: Address.example,
|
|
|
|
c: Address.example,
|
2022-03-29 08:26:31 +00:00
|
|
|
d: UInt256.example,
|
|
|
|
e: array[32, byte].example
|
2022-02-01 14:49:36 +00:00
|
|
|
)
|
|
|
|
|
2022-08-19 05:09:37 +00:00
|
|
|
proc example(_: type IndexedWithDistinctType): IndexedWithDistinctType =
|
|
|
|
IndexedWithDistinctType(
|
|
|
|
a: DistinctAlias(array[32, byte].example)
|
|
|
|
)
|
|
|
|
|
|
|
|
func encode(_: type AbiEncoder, value: DistinctAlias): seq[byte] =
|
|
|
|
@(value.toArray)
|
|
|
|
|
2022-02-01 14:49:36 +00:00
|
|
|
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
|
|
|
|
|
2022-04-13 08:05:41 +00:00
|
|
|
test "decodes dynamically sized fields":
|
|
|
|
let event = DynamicSizeEvent.example
|
|
|
|
let data = AbiEncoder.encode( (event.a, event.b) )
|
|
|
|
check DynamicSizeEvent.decode(data, @[]) == success event
|
|
|
|
|
2022-02-01 14:49:36 +00:00
|
|
|
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)
|
2022-03-29 08:26:31 +00:00
|
|
|
topics.add Topic.encode(event.e)
|
2022-02-01 14:49:36 +00:00
|
|
|
let data = AbiEncoder.encode( (event.a, event.c) )
|
|
|
|
check IndexedEvent.decode(data, topics) == success event
|
|
|
|
|
2022-08-19 05:09:37 +00:00
|
|
|
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
|
|
|
|
|
2022-02-01 14:49:36 +00:00
|
|
|
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,
|
2022-03-29 08:26:31 +00:00
|
|
|
Topic.example,
|
2022-02-01 14:49:36 +00:00
|
|
|
Topic.example
|
|
|
|
]
|
|
|
|
check ComplexIndexedEvent.decode(@[], topics) == success ComplexIndexedEvent()
|