Support encoding of signed integers

This commit is contained in:
Mark Spanbroek 2021-12-08 17:27:54 +01:00
parent 56005d623d
commit 8131170475
2 changed files with 30 additions and 7 deletions

View File

@ -67,22 +67,30 @@ func encode(encoder: var AbiEncoder, tupl: Tuple) =
func finishTuple(encoder: var AbiEncoder) =
encoder.encode(encoder.stack.pop())
func pad(encoder: var AbiEncoder, len: int) =
func pad(encoder: var AbiEncoder, len: int, padding=0'u8) =
let padlen = (32 - len mod 32) mod 32
for _ in 0..<padlen:
encoder.append([0'u8])
encoder.append([padding])
func padleft(encoder: var AbiEncoder, bytes: openArray[byte]) =
encoder.pad(bytes.len)
func padleft(encoder: var AbiEncoder, bytes: openArray[byte], padding=0'u8) =
encoder.pad(bytes.len, padding)
encoder.append(bytes)
func padright(encoder: var AbiEncoder, bytes: openArray[byte]) =
func padright(encoder: var AbiEncoder, bytes: openArray[byte], padding=0'u8) =
encoder.append(bytes)
encoder.pad(bytes.len)
encoder.pad(bytes.len, padding)
func encode(encoder: var AbiEncoder, value: SomeUnsignedInt | StUint) =
encoder.padleft(value.toBytesBE)
func encode[bits](encoder: var AbiEncoder, value: StInt[bits]) =
let bytes = value.stuint(bits).toBytesBE
let padding = if value.isNegative: 0xFF'u8 else: 0x00'u8
encoder.padleft(bytes, padding)
func encode(encoder: var AbiEncoder, value: SomeSignedInt) =
encoder.write(value.i256)
func encode(encoder: var AbiEncoder, value: bool) =
encoder.encode(if value: 1'u8 else: 0'u8)

View File

@ -1,5 +1,6 @@
import std/unittest
import std/sequtils
import pkg/stint
import pkg/stew/byteutils
import contractabi
@ -27,6 +28,16 @@ suite "ABI encoding":
0x11'u8 & 0x22'u8 & 0x33'u8 & 0x44'u8 &
0x55'u8 & 0x66'u8 & 0x77'u8 & 0x88'u8
test "encodes int8, 16, 32, 64":
check AbiEncoder.encode(1'i8) == 31.zeroes & 0x01'u8
check AbiEncoder.encode(-1'i8) == 0xFF'u8.repeat(32)
check AbiEncoder.encode(1'i16) == 31.zeroes & 0x01'u8
check AbiEncoder.encode(-1'i16) == 0xFF'u8.repeat(32)
check AbiEncoder.encode(1'i32) == 31.zeroes & 0x01'u8
check AbiEncoder.encode(-1'i32) == 0xFF'u8.repeat(32)
check AbiEncoder.encode(1'i64) == 31.zeroes & 0x01'u8
check AbiEncoder.encode(-1'i64) == 0xFF'u8.repeat(32)
test "encodes ranges":
type SomeRange = range[0x0000'u16..0xAAAA'u16]
check AbiEncoder.encode(SomeRange(0x1122)) == 30.zeroes & 0x11'u8 & 0x22'u8
@ -40,9 +51,13 @@ suite "ABI encoding":
test "encodes stints":
let uint256 = UInt256.example
check AbiEncoder.encode(uint256) == @(uint256.toBytesBE)
let uint128 = UInt128.example
check AbiEncoder.encode(uint256) == @(uint256.toBytesBE)
check AbiEncoder.encode(uint128) == 16.zeroes & @(uint128.toBytesBE)
check AbiEncoder.encode(1.i256) == 31.zeroes & 0x01'u8
check AbiEncoder.encode(1.i128) == 31.zeroes & 0x01'u8
check AbiEncoder.encode(-1.i256) == 0xFF'u8.repeat(32)
check AbiEncoder.encode(-1.i128) == 0xFF'u8.repeat(32)
test "encodes byte arrays":
let bytes3 = [1'u8, 2'u8, 3'u8]