mirror of
https://github.com/logos-storage/nim-nitro.git
synced 2026-01-03 06:03:09 +00:00
Offset of dynamic elements is relative to the start of the tuple, not relative to the start of the element.
162 lines
4.8 KiB
Nim
162 lines
4.8 KiB
Nim
import std/unittest
|
|
import pkg/nitro/abi
|
|
import pkg/nitro/types
|
|
import pkg/stint
|
|
import ./examples
|
|
|
|
suite "ABI encoding":
|
|
|
|
proc zeroes(amount: int): seq[byte] =
|
|
newSeq[byte](amount)
|
|
|
|
test "encodes uint8":
|
|
check Abi.encode(42'u8) == 31.zeroes & 42'u8
|
|
|
|
test "encodes booleans":
|
|
check Abi.encode(false) == 31.zeroes & 0'u8
|
|
check Abi.encode(true) == 31.zeroes & 1'u8
|
|
|
|
test "encodes uint16, 32, 64":
|
|
check Abi.encode(0xABCD'u16) ==
|
|
30.zeroes & 0xAB'u8 & 0xCD'u8
|
|
check Abi.encode(0x11223344'u32) ==
|
|
28.zeroes & 0x11'u8 & 0x22'u8 & 0x33'u8 & 0x44'u8
|
|
check Abi.encode(0x1122334455667788'u64) ==
|
|
24.zeroes &
|
|
0x11'u8 & 0x22'u8 & 0x33'u8 & 0x44'u8 &
|
|
0x55'u8 & 0x66'u8 & 0x77'u8 & 0x88'u8
|
|
|
|
test "encodes ranges":
|
|
type SomeRange = range[0x0000'u16..0xAAAA'u16]
|
|
check Abi.encode(SomeRange(0x1122)) == 30.zeroes & 0x11'u8 & 0x22'u8
|
|
|
|
test "encodes enums":
|
|
type SomeEnum = enum
|
|
one = 1
|
|
two = 2
|
|
check Abi.encode(one) == 31.zeroes & 1'u8
|
|
check Abi.encode(two) == 31.zeroes & 2'u8
|
|
|
|
test "encodes stints":
|
|
let uint256 = UInt256.example
|
|
check Abi.encode(uint256) == @(uint256.toBytesBE)
|
|
let uint128 = UInt128.example
|
|
check Abi.encode(uint128) == 16.zeroes & @(uint128.toBytesBE)
|
|
|
|
test "encodes byte arrays":
|
|
let bytes3 = [1'u8, 2'u8, 3'u8]
|
|
check Abi.encode(bytes3) == @bytes3 & 29.zeroes
|
|
let bytes32 = array[32, byte].example
|
|
check Abi.encode(bytes32) == @bytes32
|
|
let bytes33 = array[33, byte].example
|
|
check Abi.encode(bytes33) == @bytes33 & 31.zeroes
|
|
|
|
test "encodes byte sequences":
|
|
let bytes3 = @[1'u8, 2'u8, 3'u8]
|
|
let bytes3len = Abi.encode(bytes3.len.uint64)
|
|
check Abi.encode(bytes3) == bytes3len & bytes3 & 29.zeroes
|
|
let bytes32 = @(array[32, byte].example)
|
|
let bytes32len = Abi.encode(bytes32.len.uint64)
|
|
check Abi.encode(bytes32) == bytes32len & bytes32
|
|
let bytes33 = @(array[33, byte].example)
|
|
let bytes33len = Abi.encode(bytes33.len.uint64)
|
|
check Abi.encode(bytes33) == bytes33len & bytes33 & 31.zeroes
|
|
|
|
test "encodes ethereum addresses":
|
|
let address = EthAddress.example
|
|
check Abi.encode(address) == 12.zeroes & @(address.toArray)
|
|
|
|
test "encodes tuples":
|
|
let a = true
|
|
let b = @[1'u8, 2'u8, 3'u8]
|
|
let c = 0xAABBCCDD'u32
|
|
let d = @[4'u8, 5'u8, 6'u8]
|
|
var writer: AbiWriter
|
|
writer.startTuple()
|
|
writer.write(a)
|
|
writer.write(b)
|
|
writer.write(c)
|
|
writer.write(d)
|
|
writer.finishTuple()
|
|
check writer.finish() ==
|
|
Abi.encode(a) &
|
|
Abi.encode(4 * 32'u8) & # offset from start of tuple
|
|
Abi.encode(c) &
|
|
Abi.encode(6 * 32'u8) & # offset from start of tuple
|
|
Abi.encode(b) &
|
|
Abi.encode(d)
|
|
|
|
test "encodes nested tuples":
|
|
let a = true
|
|
let b = @[1'u8, 2'u8, 3'u8]
|
|
let c = 0xAABBCCDD'u32
|
|
let d = @[4'u8, 5'u8, 6'u8]
|
|
var writer: AbiWriter
|
|
writer.startTuple()
|
|
writer.write(a)
|
|
writer.write(b)
|
|
writer.startTuple()
|
|
writer.write(c)
|
|
writer.write(d)
|
|
writer.finishTuple()
|
|
writer.finishTuple()
|
|
check writer.finish() ==
|
|
Abi.encode(a) &
|
|
Abi.encode(6 * 32'u8) & # offset from start of tuple
|
|
Abi.encode(c) &
|
|
Abi.encode(2 * 32'u8) & # offset from start of tuple
|
|
Abi.encode(d) &
|
|
Abi.encode(b)
|
|
|
|
test "encodes arrays":
|
|
let element1 = seq[byte].example
|
|
let element2 = seq[byte].example
|
|
var expected: AbiWriter
|
|
expected.startTuple()
|
|
expected.write(element1)
|
|
expected.write(element2)
|
|
expected.finishTuple()
|
|
check Abi.encode([element1, element2]) == expected.finish()
|
|
|
|
test "encodes sequences":
|
|
let element1 = seq[byte].example
|
|
let element2 = seq[byte].example
|
|
var expected: AbiWriter
|
|
expected.write(2'u8)
|
|
expected.startTuple()
|
|
expected.write(element1)
|
|
expected.write(element2)
|
|
expected.finishTuple()
|
|
check Abi.encode(@[element1, element2]) == expected.finish()
|
|
|
|
test "encodes sequence as dynamic element":
|
|
let s = @[42.u256, 43.u256]
|
|
var writer: AbiWriter
|
|
writer.startTuple()
|
|
writer.write(s)
|
|
writer.finishTuple()
|
|
check writer.finish() ==
|
|
Abi.encode(32'u8) & # offset from start of tuple
|
|
Abi.encode(s)
|
|
|
|
test "encodes array of static elements as static element":
|
|
let a = [[42'u8], [43'u8]]
|
|
var writer: AbiWriter
|
|
writer.startTuple()
|
|
writer.write(a)
|
|
writer.finishTuple()
|
|
check writer.finish() == Abi.encode(a)
|
|
|
|
test "encodes array of dynamic elements as dynamic element":
|
|
let a = [@[42'u8], @[43'u8]]
|
|
var writer: AbiWriter
|
|
writer.startTuple()
|
|
writer.write(a)
|
|
writer.finishTuple()
|
|
check writer.finish() ==
|
|
Abi.encode(32'u8) & # offset from start of tuple
|
|
Abi.encode(a)
|
|
|
|
# https://medium.com/b2expand/abi-encoding-explanation-4f470927092d
|
|
# https://docs.soliditylang.org/en/v0.8.1/abi-spec.html#formal-specification-of-the-encoding
|