UNPKG

@findeth/abi

Version:

A tiny Solidity ABI encoder and decoder

132 lines (116 loc) 3.11 kB
import { iterate } from './iterator'; import { address, array, bool, bytes, fixedBytes, fn, number, string, tuple } from './parsers'; import { concat, 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, functions } = types.reduce(({ staticBuffer, dynamicBuffer, functions }, type, index) => { const parser = getParser(type); const value = values[index]; if (!isDynamicParser(parser, type)) { return { staticBuffer: parser.encode({ buffer: staticBuffer, value, type }), dynamicBuffer, functions }; } const offset = dynamicBuffer.length; const staticOffset = staticBuffer.length; const newStaticBuffer = concat([staticBuffer, new Uint8Array(32).fill(0)]); const newDynamicBuffer = parser.encode({ buffer: dynamicBuffer, value, type }); const fn = oldBuffer => { return concat([oldBuffer.subarray(0, staticOffset), toBuffer(oldBuffer.length + offset), oldBuffer.subarray(staticOffset + 32)]); }; return { staticBuffer: newStaticBuffer, dynamicBuffer: newDynamicBuffer, functions: [...functions, fn] }; }, { staticBuffer: new Uint8Array(), dynamicBuffer: new Uint8Array(), functions: [] }); const updatedBuffer = functions.reduce((target, update) => update(target), 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