decode method

  1. @override
Object decode(
  1. Uint8List encoded
)
override

Decode ABI encoded byte array to dart values from ABI type schemes @param encoded byte array of ABI encoding @throws IllegalArgumentException if encoded byte array cannot match with ABI encoding rules

Implementation

@override
Object decode(Uint8List encoded) {
  final dynamicSeg = <int>[];
  final valuePartition = <Uint8List>[];
  var iterIndex = 0;

  for (var i = 0; i < childTypes.length; i++) {
    if (childTypes[i].isDynamic()) {
      if (iterIndex + AbiType.ABI_DYNAMIC_HEAD_BYTE_LEN > encoded.length) {
        throw ArgumentError(
            'ill formed tuple dynamic typed element encoding: not enough bytes for index');
      }
      final encodedIndex = Uint8List(AbiType.ABI_DYNAMIC_HEAD_BYTE_LEN);
      Array.copy(encoded, iterIndex, encodedIndex, 0,
          AbiType.ABI_DYNAMIC_HEAD_BYTE_LEN);
      final index = BigIntEncoder.decodeBytesToUint(encodedIndex).toInt();
      dynamicSeg.add(index);
      valuePartition.add(Uint8List.fromList([]));
      iterIndex += AbiType.ABI_DYNAMIC_HEAD_BYTE_LEN;
    } else if (childTypes[i] is TypeBool) {
      final childTypeArr = List<AbiType>.from(childTypes);
      var before = AbiType.findBoolLR(childTypeArr, i, -1);
      var after = AbiType.findBoolLR(childTypeArr, i, 1);
      if (before % 8 != 0) {
        throw ArgumentError('expected bool number mod 8 == 0');
      }
      after = min(after, 7);
      for (var boolIndex = 0; boolIndex <= after; boolIndex++) {
        var boolMask = (0x80 >> boolIndex);
        var append = ((encoded[iterIndex] & boolMask) != 0) ? 0x80 : 0x00;
        valuePartition.add(Uint8List.fromList([append]));
      }
      i += after;
      iterIndex++;
    } else {
      var expectedLen = childTypes[i].byteLength();
      if (iterIndex + expectedLen > encoded.length) {
        throw ArgumentError(
            'ill formed tuple static typed element encoding: not enough bytes');
      }
      final partition = Uint8List(expectedLen);
      Array.copy(encoded, iterIndex, partition, 0, expectedLen);
      valuePartition.add(partition);
      iterIndex += expectedLen;
    }
    if (i != childTypes.length - 1 && iterIndex >= encoded.length) {
      throw ArgumentError('input bytes not enough to decode');
    }
  }

  if (dynamicSeg.isNotEmpty) {
    dynamicSeg.add(encoded.length);
    iterIndex = encoded.length;
  }

  if (iterIndex < encoded.length) {
    throw ArgumentError('input bytes not fully consumed');
  }

  var indexTemp = -1;
  for (var v in dynamicSeg) {
    if (v >= indexTemp) {
      indexTemp = v;
    } else {
      throw ArgumentError(
          'dynamic segments should display a [l, r] scope where l <= r');
    }
  }

  var segIndex = 0;
  for (var i = 0; i < childTypes.length; i++) {
    if (childTypes[i].isDynamic()) {
      final length = dynamicSeg[segIndex + 1] - dynamicSeg[segIndex];
      final partition = Uint8List(length);
      Array.copy(encoded, dynamicSeg[segIndex], partition, 0, length);
      valuePartition[i] = partition;
      segIndex++;
    }
  }

  final values =
      List<Object?>.filled(childTypes.length, null, growable: false);
  for (var i = 0; i < childTypes.length; i++) {
    values[i] = childTypes[i].decode(valuePartition[i]);
  }

  return values.whereNotNull().toList();
}