UNPKG

0xweb

Version:

Contract package manager and other web3 tools

144 lines (129 loc) 4.89 kB
import { TEth } from '@dequanto/models/TEth'; import { $buffer } from './$buffer'; import { $require } from './$require'; export namespace $hex { export const ZERO = '0x' /** * Adds '00' bytes to the hex string. * @param hex * @param byteSize Min bytes count in the hex string */ export function padBytes(hex: TEth.Hex, byteSize: number, opts?: { padEnd?: boolean }): TEth.Hex { let length = byteSize * 2; hex = ensure(hex); if (hex.length === length + 2) { return hex; } hex = hex.substring(2)[ opts?.padEnd ? 'padEnd' : 'padStart' ](length, '0') as TEth.Hex; return `0x${hex}`; } /** * Trims '00' bytes from start or end, e.g. 0x68656c6c6f000000 => 0x68656c6c6f */ export function trimBytes(hex: TEth.Hex): TEth.Hex { if (hex.startsWith('0x00') === false && hex.endsWith('00') === false) { return hex; } return hex.replace(/^0x(0{2})+/, '').replace(/(0{2})+$/, '') as TEth.Hex; } export function trimLeadingZerosFromNumber(hex: string) { hex = hex.replace(/^0x0*/, ''); return hex === ''? '0x0' : `0x${hex}`; } export function getBytes (hex: string, offset: number, length: number): TEth.Hex { let start = hex.startsWith('0x') ? 2 : 0; let offsetChars = offset * 2; let lengthChars = length * 2; return (`0x` + hex.substring(start + offsetChars, start + offsetChars + lengthChars)) as TEth.Hex; } export function getBytesLength (hex: string) { let pfx = hex.startsWith('0x') ? 2 : 0; let chars = hex.length - pfx; $require.True(chars % 2 === 0, `Expect buffer to have even length, got ${chars}`); return chars / 2; } export function getNumber (hex: string, byteIndex: number, bytesCount: number = 1): number { let start = hex.startsWith('0x') ? 2 : 0; let i = start + byteIndex * 2; return parseInt(hex.substring(i, i + 2 * bytesCount), 16); } export function raw (hex: string) { return hex.startsWith('0x') ? hex.substring(2) : hex; } export function concat (arr: (string | TEth.Hex | Uint8Array)[]) { return ('0x' + arr.map(ensure).map(raw).join('')) as TEth.Hex; } export function split (hex: TEth.Hex, bytes: number = 32) { let str = raw(hex); let args = []; while (str.length > 0) { args.push('0x' + str.substring(0, bytes * 2)); str = str.substring(bytes * 2); } return args; } export function toHex (value: string | boolean | number | bigint): TEth.Hex { switch (typeof value) { case 'string': { if (value.startsWith('0x')) { return value as TEth.Hex; } return $buffer.toHex($buffer.fromString(value)); } case 'number': case 'bigint': let hex = value.toString(16); return ('0x' + hex) as TEth.Hex; case 'boolean': return value ? '0x1' : '0x0'; } throw new Error(`Invalid value to convert to hex: ${value}`); } export function toHexBuffer (value: string | boolean | number | bigint): TEth.Hex { value = toHex(value); if (value.length % 2 === 1) { value = '0x0' + value.substring(2); } return value as TEth.Hex; } export function convert (hex: string, abiType: 'uint256' | 'address' | 'bool' | 'string' | string) { if (abiType === 'bool') { return Boolean(Number(hex)); } let bigintMatch = /int(?<size>\d+)?$/.exec(abiType); if (bigintMatch) { let size = Number(bigintMatch.groups.size ?? 256); if (size < 16) { return Number(hex); } return BigInt(hex); } return hex; } /** * Adds `0x` to the start if not present */ export function ensure (mix: string | number | boolean | bigint | Uint8Array): TEth.Hex { if (mix == null) { return '0x'; } if (mix instanceof Uint8Array) { mix = $buffer.toHex(mix); } if (typeof mix === 'number' || typeof mix === 'bigint') { return `0x${mix.toString(16)}`; } if (typeof mix ==='boolean') { return mix ? '0x1' : '0x0'; } if (mix.startsWith('0x')) { return mix as TEth.Hex; } return `0x${mix}`; } export function isEmpty (hex: string) { return hex == null || hex.length === 0 || hex === '0x'; } }