@crtxio/abi
Version:
A tiny Solidity ABI encoder and decoder
135 lines (121 loc) • 3.07 kB
JavaScript
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