import pkg/stew/endians2 import ../basics include questionable/errorban export basics type AbiEncoder* = object stack: seq[Tuple] Tuple = object bytes: seq[byte] postponed: seq[Split] dynamic: bool Split = object head: Slice[int] tail: seq[byte] proc write*[T](encoder: var AbiEncoder, value: T) proc encode*[T](_: type AbiEncoder, value: T): seq[byte] proc init*(_: type AbiEncoder): AbiEncoder = AbiEncoder(stack: @[Tuple()]) proc append(tupl: var Tuple, bytes: openArray[byte]) = tupl.bytes.add(bytes) proc postpone(tupl: var Tuple, bytes: seq[byte]) = var split: Split split.head.a = tupl.bytes.len tupl.append(AbiEncoder.encode(0'u64)) split.head.b = tupl.bytes.high split.tail = bytes tupl.postponed.add(split) proc finish(tupl: Tuple): seq[byte] = var bytes = tupl.bytes for split in tupl.postponed: let offset = bytes.len bytes[split.head] = AbiEncoder.encode(offset.uint64) bytes.add(split.tail) bytes proc append(encoder: var AbiEncoder, bytes: openArray[byte]) = encoder.stack[^1].append(bytes) proc postpone(encoder: var AbiEncoder, bytes: seq[byte]) = if encoder.stack.len > 1: encoder.stack[^1].postpone(bytes) else: encoder.stack[0].append(bytes) proc setDynamic(encoder: var AbiEncoder) = encoder.stack[^1].dynamic = true proc startTuple*(encoder: var AbiEncoder) = encoder.stack.add(Tuple()) proc encode(encoder: var AbiEncoder, tupl: Tuple) = if tupl.dynamic: encoder.postpone(tupl.finish()) encoder.setDynamic() else: encoder.append(tupl.finish()) proc finishTuple*(encoder: var AbiEncoder) = encoder.encode(encoder.stack.pop()) proc pad(encoder: var AbiEncoder, len: int) = let padlen = (32 - len mod 32) mod 32 for _ in 0..