import pkg/stint import pkg/stew/endians2 import pkg/stew/byteutils import pkg/questionable/results import pkg/upraises import ./encoding import ./integers import ./address export stint export address push: {.upraises:[].} type AbiDecoder* = object bytes: seq[byte] stack: seq[Tuple] last: int Tuple = object start: int index: int Padding = enum padLeft, padRight UInt = SomeUnsignedInt | StUint Int = SomeSignedInt | StInt func read*(decoder: var AbiDecoder, T: type): ?!T func init(_: type Tuple, offset: int): Tuple = Tuple(start: offset, index: offset) func init(_: type AbiDecoder, bytes: seq[byte], offset=0): AbiDecoder = AbiDecoder(bytes: bytes, stack: @[Tuple.init(offset)]) func currentTuple(decoder: var AbiDecoder): var Tuple = decoder.stack[^1] func index(decoder: var AbiDecoder): var int = decoder.currentTuple.index func `index=`(decoder: var AbiDecoder, value: int) = decoder.currentTuple.index = value func startTuple(decoder: var AbiDecoder): ?!void = decoder.stack.add(Tuple.init(decoder.index)) success() func finishTuple(decoder: var AbiDecoder) = doAssert decoder.stack.len > 1, "unable to finish a tuple that hasn't started" let tupl = decoder.stack.pop() decoder.index = tupl.index func updateLast(decoder: var AbiDecoder, index: int) = if index > decoder.last: decoder.last = index func advance(decoder: var AbiDecoder, amount: int): ?!void = decoder.index += amount decoder.updateLast(decoder.index) if decoder.index <= decoder.bytes.len: success() else: failure "reading past end" func skipPadding(decoder: var AbiDecoder, amount: int): ?!void = let index = decoder.index ?decoder.advance(amount) for i in index.. 1: decoder.readTail(T) else: decoder.decode(T) func finish(decoder: var AbiDecoder): ?!void = doAssert decoder.stack.len == 1, "not all tuples were finished" doAssert decoder.last mod 32 == 0, "encoding invariant broken" if decoder.last != decoder.bytes.len: failure "unread trailing bytes found" else: success() func decode*(_: type AbiDecoder, bytes: seq[byte], T: type): ?!T = var decoder = AbiDecoder.init(bytes) var value = ?decoder.decode(T) ?decoder.finish() success value