diff --git a/Readme.md b/Readme.md index 314bbf3..25cb9a4 100644 --- a/Readme.md +++ b/Readme.md @@ -32,13 +32,7 @@ AbiEncoder.encode([1'u8, 2'u8, 3'u8]) AbiEncoder.encode(@[1'u8, 2'u8, 3'u8]) # encode tuples -var encoder = AbiEncoder.init() -encoder.startTuple() -encoder.write(42'u8) -encoder.write(@[1'u8, 2'u8, 3'u8]) -encoder.write(true) -encoder.finishTuple() -encoder.finish() +AbiEncoder.encode( (42'u8, @[1'u8, 2'u8, 3'u8], true) ) ``` [1]: https://docs.soliditylang.org/en/latest/abi-spec.html diff --git a/contractabi/encoding.nim b/contractabi/encoding.nim index 5f093c8..08b4251 100644 --- a/contractabi/encoding.nim +++ b/contractabi/encoding.nim @@ -54,7 +54,7 @@ func postpone(encoder: var AbiEncoder, bytes: seq[byte]) = func setDynamic(encoder: var AbiEncoder) = encoder.stack[^1].dynamic = true -func startTuple*(encoder: var AbiEncoder) = +func startTuple(encoder: var AbiEncoder) = encoder.stack.add(Tuple()) func encode(encoder: var AbiEncoder, tupl: Tuple) = @@ -64,7 +64,7 @@ func encode(encoder: var AbiEncoder, tupl: Tuple) = else: encoder.append(tupl.finish()) -func finishTuple*(encoder: var AbiEncoder) = +func finishTuple(encoder: var AbiEncoder) = encoder.encode(encoder.stack.pop()) func pad(encoder: var AbiEncoder, len: int) = @@ -114,6 +114,12 @@ func encode[T](encoder: var AbiEncoder, value: seq[T]) = func encode(encoder: var AbiEncoder, value: string) = encoder.encode(value.toBytes) +func encode(encoder: var AbiEncoder, tupl: tuple) = + encoder.startTuple() + for element in tupl.fields: + encoder.write(element) + encoder.finishTuple() + func write*[T](encoder: var AbiEncoder, value: T) = var writer = AbiEncoder.init() writer.encode(value) diff --git a/tests/contractabi/testDecoding.nim b/tests/contractabi/testDecoding.nim index c1272b6..d6e44d3 100644 --- a/tests/contractabi/testDecoding.nim +++ b/tests/contractabi/testDecoding.nim @@ -68,15 +68,7 @@ suite "ABI decoding": let b = @[1'u8, 2'u8, 3'u8] let c = 0xAABBCCDD'u32 let d = @[4'u8, 5'u8, 6'u8] - - var encoder= AbiEncoder.init() - encoder.startTuple() - encoder.write(a) - encoder.write(b) - encoder.write(c) - encoder.write(d) - encoder.finishTuple() - let encoding = encoder.finish() + let encoding = AbiEncoder.encode( (a, b, c, d) ) var decoder = AbiDecoder.init(encoding) decoder.startTuple(dynamic=true) @@ -93,17 +85,7 @@ suite "ABI decoding": let c = 0xAABBCCDD'u32 let d = @[4'u8, 5'u8, 6'u8] - var encoder= AbiEncoder.init() - encoder.startTuple() - encoder.write(a) - encoder.write(b) - encoder.startTuple() - encoder.write(c) - encoder.write(d) - encoder.finishTuple() - encoder.finishTuple() - let encoding = encoder.finish() - + let encoding = AbiEncoder.encode( (a, b, (c, d)) ) var decoder = AbiDecoder.init(encoding) decoder.startTuple(dynamic=true) check decoder.read(bool) == a @@ -118,49 +100,35 @@ suite "ABI decoding": test "reads elements after dynamic tuple": let a = @[1'u8, 2'u8, 3'u8] let b = 0xAABBCCDD'u32 - var encoder = AbiEncoder.init() - encoder.startTuple() - encoder.write(a) - encoder.finishTuple() - encoder.write(b) - let encoding = encoder.finish() + let encoding = AbiEncoder.encode( ((a,), b) ) var decoder = AbiDecoder.init(encoding) decoder.startTuple(dynamic=true) + decoder.startTuple(dynamic=true) check decoder.read(seq[byte]) == a decoder.finishTuple() check decoder.read(uint32) == b + decoder.finishTuple() decoder.finish() test "reads elements after static tuple": let a = 0x123'u16 let b = 0xAABBCCDD'u32 - var encoder = AbiEncoder.init() - encoder.startTuple() - encoder.write(a) - encoder.finishTuple() - encoder.write(b) - let encoding = encoder.finish() + let encoding = AbiEncoder.encode( ((a,), b) ) var decoder = AbiDecoder.init(encoding) decoder.startTuple(dynamic=false) + decoder.startTuple(dynamic=false) check decoder.read(uint16) == a decoder.finishTuple() check decoder.read(uint32) == b + decoder.finishTuple() decoder.finish() test "reads static tuple inside dynamic tuple": let a = @[1'u8, 2'u8, 3'u8] let b = 0xAABBCCDD'u32 - - var encoder= AbiEncoder.init() - encoder.startTuple() - encoder.write(a) - encoder.startTuple() - encoder.write(b) - encoder.finishTuple() - encoder.finishTuple() - let encoding = encoder.finish() + let encoding = AbiEncoder.encode( (a, (b,)) ) var decoder = AbiDecoder.init(encoding) decoder.startTuple(dynamic=true) @@ -172,12 +140,7 @@ suite "ABI decoding": decoder.finish() test "reads empty tuples": - var encoder = AbiEncoder.init() - encoder.startTuple() - encoder.startTuple() - encoder.finishTuple() - encoder.finishTuple() - let encoding = encoder.finish() + let encoding = AbiEncoder.encode( ((),) ) var decoder = AbiDecoder.init(encoding) decoder.startTuple(dynamic=false) diff --git a/tests/contractabi/testEncoding.nim b/tests/contractabi/testEncoding.nim index 24fe46a..daeafdf 100644 --- a/tests/contractabi/testEncoding.nim +++ b/tests/contractabi/testEncoding.nim @@ -68,14 +68,7 @@ suite "ABI encoding": let b = @[1'u8, 2'u8, 3'u8] let c = 0xAABBCCDD'u32 let d = @[4'u8, 5'u8, 6'u8] - var encoder= AbiEncoder.init() - encoder.startTuple() - encoder.write(a) - encoder.write(b) - encoder.write(c) - encoder.write(d) - encoder.finishTuple() - check encoder.finish() == + check AbiEncoder.encode( (a, b, c, d) ) == AbiEncoder.encode(a) & AbiEncoder.encode(4 * 32'u8) & # offset in tuple AbiEncoder.encode(c) & @@ -88,16 +81,7 @@ suite "ABI encoding": let b = @[1'u8, 2'u8, 3'u8] let c = 0xAABBCCDD'u32 let d = @[4'u8, 5'u8, 6'u8] - var encoder= AbiEncoder.init() - encoder.startTuple() - encoder.write(a) - encoder.write(b) - encoder.startTuple() - encoder.write(c) - encoder.write(d) - encoder.finishTuple() - encoder.finishTuple() - check encoder.finish() == + check AbiEncoder.encode( (a, b, (c, d)) ) == AbiEncoder.encode(a) & AbiEncoder.encode(3 * 32'u8) & # offset of b in outer tuple AbiEncoder.encode(5 * 32'u8) & # offset of inner tuple in outer tuple @@ -106,65 +90,29 @@ suite "ABI encoding": AbiEncoder.encode(2 * 32'u8) & # offset of d in inner tuple AbiEncoder.encode(d) - test "encodes element after dynamic tuple": - let a = @[1'u8, 2'u8, 3'u8] - let b = 0xAABBCCDD'u32 - var encoder= AbiEncoder.init() - encoder.startTuple() - encoder.write(a) - encoder.finishTuple() - encoder.write(b) - check encoder.finish() == - AbiEncoder.encode(1 * 32'u8) & # offset of a in tuple - AbiEncoder.encode(a) & - AbiEncoder.encode(b) - test "encodes arrays": - let element1 = seq[byte].example - let element2 = seq[byte].example - var expected= AbiEncoder.init() - expected.startTuple() - expected.write(element1) - expected.write(element2) - expected.finishTuple() - check AbiEncoder.encode([element1, element2]) == expected.finish() + let a, b = seq[byte].example + check AbiEncoder.encode([a, b]) == AbiEncoder.encode( (a,b) ) test "encodes sequences": - let element1 = seq[byte].example - let element2 = seq[byte].example - var expected= AbiEncoder.init() - expected.write(2'u8) - expected.startTuple() - expected.write(element1) - expected.write(element2) - expected.finishTuple() - check AbiEncoder.encode(@[element1, element2]) == expected.finish() + let a, b = seq[byte].example + check AbiEncoder.encode(@[a, b]) == + AbiEncoder.encode(2'u64) & + AbiEncoder.encode( (a, b) ) test "encodes sequence as dynamic element": let s = @[42.u256, 43.u256] - var encoder= AbiEncoder.init() - encoder.startTuple() - encoder.write(s) - encoder.finishTuple() - check encoder.finish() == + check AbiEncoder.encode( (s,) ) == AbiEncoder.encode(32'u8) & # offset in tuple AbiEncoder.encode(s) test "encodes array of static elements as static element": let a = [[42'u8], [43'u8]] - var encoder= AbiEncoder.init() - encoder.startTuple() - encoder.write(a) - encoder.finishTuple() - check encoder.finish() == AbiEncoder.encode(a) + check AbiEncoder.encode( (a,) ) == AbiEncoder.encode(a) test "encodes array of dynamic elements as dynamic element": let a = [@[42'u8], @[43'u8]] - var encoder= AbiEncoder.init() - encoder.startTuple() - encoder.write(a) - encoder.finishTuple() - check encoder.finish() == + check AbiEncoder.encode( (a,) ) == AbiEncoder.encode(32'u8) & # offset in tuple AbiEncoder.encode(a)