UNPKG

@crtxio/abi

Version:

A tiny Solidity ABI encoder and decoder

135 lines (121 loc) 3.07 kB
import { iterate } from './iterator'; import { address, array, bool, bytes, fixedBytes, fn, number, string, tuple } from './parsers'; import { concat, set, toBuffer, toNumber } from './utils'; export const getParser = type => { const parsers = { address, array, bool, bytes, fixedBytes, function: fn, number, string, tuple }; if (parsers[type]) { return parsers[type]; } const parser = Object.values(parsers).find(parser => { var _parser$isType; return (_parser$isType = parser.isType) === null || _parser$isType === void 0 ? void 0 : _parser$isType.call(parser, type); }); if (parser) { return parser; } throw new Error(`Type "${type}" is not supported`); }; export const isDynamicParser = (parser, type) => { const isDynamic = parser.isDynamic; if (typeof isDynamic === 'function') { return isDynamic(type); } return isDynamic; }; export const pack = (types, values, buffer = new Uint8Array()) => { if (types.length !== values.length) { throw new Error('The length of the types and values must be equal'); } const { staticBuffer, dynamicBuffer, pointers } = types.reduce(({ staticBuffer, dynamicBuffer, pointers }, type, index) => { const parser = getParser(type); const value = values[index]; if (!isDynamicParser(parser, type)) { return { staticBuffer: parser.encode({ buffer: staticBuffer, value, type }), dynamicBuffer, pointers }; } const newStaticBuffer = concat([staticBuffer, new Uint8Array(32)]); const newDynamicBuffer = parser.encode({ buffer: dynamicBuffer, value, type }); return { staticBuffer: newStaticBuffer, dynamicBuffer: newDynamicBuffer, pointers: [...pointers, { position: staticBuffer.length, pointer: dynamicBuffer.length }] }; }, { staticBuffer: new Uint8Array(), dynamicBuffer: new Uint8Array(), pointers: [] }); const dynamicStart = staticBuffer.length; const updatedBuffer = pointers.reduce((target, { pointer, position }) => { const offset = toBuffer(dynamicStart + pointer); return set(target, offset, position); }, staticBuffer); return concat([buffer, updatedBuffer, dynamicBuffer]); }; export const unpack = (types, buffer) => { const iterator = iterate(buffer); return types.map(type => { const { value: { value, skip }, done } = iterator.next(); if (done) { throw new Error('Element is out of range'); } const parser = getParser(type); const isDynamic = isDynamicParser(parser, type); if (isDynamic) { const pointer = Number(toNumber(value.subarray(0, 32))); const target = buffer.subarray(pointer); return parser.decode({ type, value: target, skip }); } return parser.decode({ type, value, skip }); }); }; //# sourceMappingURL=packer.js.map