• Mark Tyneway's avatar
    core-utils: add GenesisJsonProvider and fix tests · 7c352b1e
    Mark Tyneway authored
    The `GenesisJsonProvider` implements the `ethers.Provider`
    interface and is constructed with a geth genesis file, either
    as an object or as a file to be read from disk. It implements
    a subset of the RPC methods that use the genesis file
    as the backing storage. It includes tests for its correctness.
    Not all methods are implemented, just the ones for the regenesis
    testing.
    
    This PR also moves the tests around in the `core-utils` package
    as some of the tests were being skipped. The `tests` directory is
    flattened, having so many subdirectories was not needed. The
    `package.json` test script is updated to ensure that all tests
    are run.
    
    Also add some deps that are required for the `GenesisJsonProvider`.
    7c352b1e
hex-strings.ts 2.38 KB
/* Imports: External */
import { BigNumber, ethers } from 'ethers'
import { hexZeroPad } from '@ethersproject/bytes'

/**
 * Removes "0x" from start of a string if it exists.
 *
 * @param str String to modify.
 * @returns the string without "0x".
 */
export const remove0x = (str: string): string => {
  if (str === undefined) {
    return str
  }
  return str.startsWith('0x') ? str.slice(2) : str
}

/**
 * Adds "0x" to the start of a string if necessary.
 *
 * @param str String to modify.
 * @returns the string with "0x".
 */
export const add0x = (str: string): string => {
  if (str === undefined) {
    return str
  }
  return str.startsWith('0x') ? str : '0x' + str
}

/**
 * Casts a hex string to a buffer.
 *
 * @param inp Input to cast to a buffer.
 * @return Input cast as a buffer.
 */
export const fromHexString = (inp: Buffer | string): Buffer => {
  if (typeof inp === 'string' && inp.startsWith('0x')) {
    return Buffer.from(inp.slice(2), 'hex')
  }

  return Buffer.from(inp)
}

/**
 * Casts an input to a hex string.
 *
 * @param inp Input to cast to a hex string.
 * @return Input cast as a hex string.
 */
export const toHexString = (inp: Buffer | string | number | null): string => {
  if (typeof inp === 'number') {
    return BigNumber.from(inp).toHexString()
  } else {
    return '0x' + fromHexString(inp).toString('hex')
  }
}

export const toRpcHexString = (n: number | BigNumber): string => {
  let num
  if (typeof n === 'number') {
    num = '0x' + n.toString(16)
  } else {
    num = n.toHexString()
  }

  if (num === '0x0') {
    return num
  } else {
    return num.replace(/^0x0/, '0x')
  }
}

export const padHexString = (str: string, length: number): string => {
  if (str.length === 2 + length * 2) {
    return str
  } else {
    return '0x' + str.slice(2).padStart(length * 2, '0')
  }
}

export const encodeHex = (val: any, len: number) =>
  remove0x(BigNumber.from(val).toHexString()).padStart(len, '0')

export const hexStringEquals = (stringA: string, stringB: string): boolean => {
  if (!ethers.utils.isHexString(stringA)) {
    throw new Error(`input is not a hex string: ${stringA}`)
  }

  if (!ethers.utils.isHexString(stringB)) {
    throw new Error(`input is not a hex string: ${stringB}`)
  }

  return stringA.toLowerCase() === stringB.toLowerCase()
}

export const bytes32ify = (value: number | BigNumber): string => {
  return hexZeroPad(BigNumber.from(value).toHexString(), 32)
}