trufflesuite/truffle

View on GitHub
packages/codec/lib/basic/encode/index.ts

Summary

Maintainability
A
0 mins
Test Coverage
import type * as Format from "@truffle/codec/format";
import * as Conversion from "@truffle/codec/conversion";
import * as Evm from "@truffle/codec/evm";

//UGH -- it turns out TypeScript can't handle nested tagged unions
//see: https://github.com/microsoft/TypeScript/issues/18758
//so, I'm just going to have to throw in a bunch of type coercions >_>

/**
 * Handles encoding of basic types; yes the input type is broader than
 * it should be but it's hard to fix this without causing other problems,
 * sorry!
 * @Category Encoding (low-level)
 */
export function encodeBasic(input: Format.Values.Value): Uint8Array {
  let bytes: Uint8Array;
  switch (input.type.typeClass) {
    case "userDefinedValueType":
      return encodeBasic((<Format.Values.UserDefinedValueTypeValue>input).value);
    case "uint":
    case "int":
      return Conversion.toBytes(
        (<Format.Values.UintValue | Format.Values.IntValue>input).value.asBN,
        Evm.Utils.WORD_SIZE
      );
    case "enum":
      return Conversion.toBytes(
        (<Format.Values.EnumValue>input).value.numericAsBN,
        Evm.Utils.WORD_SIZE
      );
    case "bool": {
      bytes = new Uint8Array(Evm.Utils.WORD_SIZE); //is initialized to zeroes
      if ((<Format.Values.BoolValue>input).value.asBoolean) {
        bytes[Evm.Utils.WORD_SIZE - 1] = 1;
      }
      return bytes;
    }
    case "bytes":
      switch (input.type.kind) {
        //deliberately not handling dynamic case!
        case "static":
          bytes = Conversion.toBytes(
            (<Format.Values.BytesValue>input).value.asHex
          );
          let padded = new Uint8Array(Evm.Utils.WORD_SIZE); //initialized to zeroes
          padded.set(bytes);
          return padded;
      }
    case "address":
      return Conversion.toBytes(
        (<Format.Values.AddressValue>input).value.asAddress,
        Evm.Utils.WORD_SIZE
      );
    case "contract":
      return Conversion.toBytes(
        (<Format.Values.ContractValue>input).value.address,
        Evm.Utils.WORD_SIZE
      );
    case "function": {
      switch (input.type.visibility) {
        //for our purposes here, we will NOT count internal functions as a
        //basic type!  so no handling of internal case
        case "external":
          let coercedInput: Format.Values.FunctionExternalValue = <
            Format.Values.FunctionExternalValue
          >input;
          let encoded = new Uint8Array(Evm.Utils.WORD_SIZE); //starts filled w/0s
          let addressBytes = Conversion.toBytes(
            coercedInput.value.contract.address
          ); //should already be correct length
          let selectorBytes = Conversion.toBytes(coercedInput.value.selector); //should already be correct length
          encoded.set(addressBytes);
          encoded.set(selectorBytes, Evm.Utils.ADDRESS_SIZE); //set it after the address
          return encoded;
      }
      break; //to satisfy TS
    }
    case "fixed":
    case "ufixed":
      let bigValue = (<Format.Values.FixedValue | Format.Values.UfixedValue>(
        input
      )).value.asBig;
      let shiftedValue = Conversion.shiftBigUp(bigValue, input.type.places);
      return Conversion.toBytes(shiftedValue, Evm.Utils.WORD_SIZE);
  }
}