Socket
Socket
Sign inDemoInstall

@findeth/abi

Package Overview
Dependencies
Maintainers
1
Versions
14
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@findeth/abi - npm Package Compare versions

Comparing version 0.6.1 to 0.7.0

lib/cjs/iterator.js

6

lib/cjs/abi.js

@@ -8,6 +8,6 @@ "use strict";

var _array = require("./parsers/array");
var _packer = require("./packer");
const encode = (types, values) => {
return (0, _array.pack)(new Uint8Array(0), values, types);
return (0, _packer.pack)(types, values, new Uint8Array());
};

@@ -18,3 +18,3 @@

const decode = (types, buffer) => {
return (0, _array.unpack)(buffer, types);
return (0, _packer.unpack)(types, buffer);
};

@@ -21,0 +21,0 @@

@@ -6,23 +6,25 @@ "use strict";

});
exports.decodeAddress = exports.encodeAddress = void 0;
exports.address = void 0;
var _utils = require("../utils");
const encodeAddress = (buffer, value) => {
if (value.length !== 42) {
throw new Error('Invalid address length');
}
const address = {
isDynamic: false,
const addressBuffer = (0, _utils.fromHex)((0, _utils.stripPrefix)(value).padStart(64, '0'));
return (0, _utils.concat)([buffer, addressBuffer]);
};
encode({
buffer,
value
}) {
const addressBuffer = (0, _utils.fromHex)((0, _utils.stripPrefix)(value).padStart(64, '0'));
return (0, _utils.concat)([buffer, addressBuffer]);
},
exports.encodeAddress = encodeAddress;
decode({
value
}) {
return `0x${(0, _utils.toHex)(value.slice(12, 32))}`;
}
const decodeAddress = value => {
const addressBuffer = value.subarray(-20);
return `0x${(0, _utils.toHex)(addressBuffer)}`;
};
exports.decodeAddress = decodeAddress;
exports.address = address;
//# sourceMappingURL=address.js.map

@@ -6,210 +6,49 @@ "use strict";

});
exports.unpack = exports.pack = exports.getParser = exports.decodeArray = exports.encodeArray = exports.getType = exports.isArray = void 0;
exports.array = exports.getArrayType = void 0;
var _packer = require("../packer");
var _utils = require("../utils");
var _address = require("./address");
var _boolean = require("./boolean");
var _bytes = require("./bytes");
var _fixedBytes = require("./fixed-bytes");
var _number = require("./number");
var _string = require("./string");
var _tuple = require("./tuple");
const ARRAY_REGEX = /^(.*)\[]$/;
const isArray = type => {
return ARRAY_REGEX.test(type);
};
const getArrayType = type => {
const match = type.match(ARRAY_REGEX);
exports.isArray = isArray;
const getType = type => {
return type.match(ARRAY_REGEX)[1];
};
exports.getType = getType;
const encodeArray = (buffer, values, type) => {
if (!isArray(type)) {
throw new Error('Invalid type: type is not array');
if (match) {
return match[1];
}
const actualType = getType(type);
const length = (0, _utils.toBuffer)(values.length);
const arrayBuffer = (0, _utils.concat)([buffer, length]);
return pack(arrayBuffer, values, new Array(values.length).fill(actualType));
throw new Error('Type is not an array type');
};
exports.encodeArray = encodeArray;
exports.getArrayType = getArrayType;
const array = {
isDynamic: true,
const decodeArray = (value, buffer, type) => {
if (!isArray(type)) {
throw new Error('Invalid type: type is not array');
}
isType(type) {
return ARRAY_REGEX.test(type);
},
const actualType = getType(type);
const pointer = Number((0, _utils.toNumber)(value));
const length = Number((0, _utils.toNumber)(buffer.subarray(pointer, pointer + 32)));
const arrayPointer = pointer + 32;
const arrayBuffer = buffer.subarray(arrayPointer);
return unpack(arrayBuffer, new Array(length).fill(actualType));
};
exports.decodeArray = decodeArray;
const parsers = {
address: {
dynamic: false,
encode: _address.encodeAddress,
decode: _address.decodeAddress
encode({
type,
buffer,
value
}) {
const arrayType = getArrayType(type);
const arrayLength = (0, _utils.toBuffer)(value.length);
return (0, _packer.pack)(new Array(value.length).fill(arrayType), value, (0, _utils.concat)([buffer, arrayLength]));
},
array: {
dynamic: true,
encode: encodeArray,
decode: decodeArray
},
bool: {
dynamic: false,
encode: _boolean.encodeBoolean,
decode: _boolean.decodeBoolean
},
bytes: {
dynamic: true,
encode: _bytes.encodeBytes,
decode: _bytes.decodeBytes
},
fixedBytes: {
dynamic: false,
encode: _fixedBytes.encodeFixedBytes,
decode: _fixedBytes.decodeFixedBytes
},
number: {
dynamic: false,
encode: _number.encodeNumber,
decode: _number.decodeNumber
},
string: {
dynamic: true,
encode: _string.encodeString,
decode: _string.decodeString
},
tuple: {
dynamic: false,
encode: _tuple.encodeTuple,
decode: _tuple.decodeTuple
}
};
const getParser = type => {
if (parsers[type]) {
return parsers[type];
decode({
type,
value
}) {
const arrayType = getArrayType(type);
const arrayLength = Number((0, _utils.toNumber)(value.subarray(0, 32)));
return (0, _packer.unpack)(new Array(arrayLength).fill(arrayType), value.subarray(32));
}
if ((0, _fixedBytes.isFixedBytes)(type)) {
return parsers.fixedBytes;
}
if ((0, _number.isNumber)(type)) {
return parsers.number;
}
if (isArray(type)) {
return parsers.array;
}
if ((0, _tuple.isTuple)(type)) {
return parsers.tuple;
}
throw new Error(`type "${type}" is not supported`);
};
exports.getParser = getParser;
const pack = (buffer, values, types) => {
const {
staticBuffer: packedStaticBuffer,
dynamicBuffer: packedDynamicBuffer,
updateFunctions: packedUpdateFunctions
} = types.reduce(({
staticBuffer,
dynamicBuffer,
updateFunctions
}, type, index) => {
const parser = getParser(type);
const value = values[index];
if (parser.dynamic) {
const offset = dynamicBuffer.length;
const staticOffset = staticBuffer.length;
const newStaticBuffer = (0, _utils.concat)([staticBuffer, new Uint8Array(32).fill(0)]);
const newDynamicBuffer = parser.encode(dynamicBuffer, value, type);
const update = oldBuffer => {
return (0, _utils.concat)([oldBuffer.subarray(0, staticOffset), (0, _utils.toBuffer)(oldBuffer.length + offset), oldBuffer.subarray(staticOffset + 32)]);
};
return {
staticBuffer: newStaticBuffer,
dynamicBuffer: newDynamicBuffer,
updateFunctions: [...updateFunctions, update]
};
}
const newBuffer = parser.encode(staticBuffer, value, type);
return {
staticBuffer: newBuffer,
dynamicBuffer,
updateFunctions
};
}, {
staticBuffer: new Uint8Array(0),
dynamicBuffer: new Uint8Array(0),
updateFunctions: []
});
const updatedStaticBuffer = packedUpdateFunctions.reduce((target, update) => update(target), packedStaticBuffer);
return (0, _utils.concat)([buffer, updatedStaticBuffer, packedDynamicBuffer]);
};
exports.pack = pack;
const unpack = (buffer, types) => {
let pointer = 0;
return types.map(type => {
if (pointer >= buffer.length) {
throw new Error('input data has an invalid length');
}
const parser = getParser(type);
if ((0, _tuple.isTuple)(type)) {
const types = (0, _tuple.getTypes)(type);
if ((0, _tuple.isDynamicTuple)(types)) {
const value = buffer.subarray(pointer, pointer + 32);
const valuePointer = Number((0, _utils.toNumber)(value));
const actualValue = buffer.subarray(valuePointer);
pointer += 32;
return parser.decode(actualValue, buffer, type);
}
const tupleLength = types.length * 32;
const value = buffer.subarray(pointer, pointer + tupleLength);
pointer += tupleLength;
return parser.decode(value, buffer, type);
}
const value = buffer.subarray(pointer, pointer + 32);
pointer += 32;
return parser.decode(value, buffer, type);
});
};
exports.unpack = unpack;
exports.array = array;
//# sourceMappingURL=array.js.map

@@ -6,21 +6,28 @@ "use strict";

});
exports.decodeBytes = exports.encodeBytes = void 0;
exports.bytes = void 0;
var _utils = require("../utils");
const encodeBytes = (buffer, value) => {
const bufferValue = (0, _utils.toBuffer)(value);
const paddedSize = Math.ceil(bufferValue.byteLength / 32) * 32;
return (0, _utils.concat)([buffer, (0, _utils.toBuffer)(bufferValue.byteLength), (0, _utils.addPadding)(bufferValue, paddedSize)]);
};
const bytes = {
isDynamic: true,
exports.encodeBytes = encodeBytes;
encode({
buffer,
value
}) {
const bufferValue = (0, _utils.toBuffer)(value);
const paddedSize = Math.ceil(bufferValue.byteLength / 32) * 32;
return (0, _utils.concat)([buffer, (0, _utils.toBuffer)(bufferValue.byteLength), (0, _utils.addPadding)(bufferValue, paddedSize)]);
},
const decodeBytes = (value, buffer) => {
const pointer = Number((0, _utils.toNumber)(value.subarray(0, 32)));
const length = Number((0, _utils.toNumber)(buffer.subarray(pointer, pointer + 32)));
return buffer.subarray(pointer + 32, pointer + 32 + Number(length));
decode({
value
}) {
const buffer = value.slice(0, 32);
const length = Number((0, _utils.toNumber)(buffer));
return value.subarray(32, 32 + length);
}
};
exports.decodeBytes = decodeBytes;
exports.bytes = bytes;
//# sourceMappingURL=bytes.js.map

@@ -6,3 +6,3 @@ "use strict";

});
exports.decodeFixedBytes = exports.encodeFixedBytes = exports.getByteLength = exports.isFixedBytes = void 0;
exports.fixedBytes = exports.getByteLength = void 0;

@@ -13,8 +13,2 @@ var _utils = require("../utils");

const isFixedBytes = type => {
return BYTES_REGEX.test(type);
};
exports.isFixedBytes = isFixedBytes;
const getByteLength = type => {

@@ -39,22 +33,34 @@ var _type$match;

exports.getByteLength = getByteLength;
const fixedBytes = {
isDynamic: false,
const encodeFixedBytes = (buffer, value, type) => {
const length = getByteLength(type);
const bufferValue = (0, _utils.toBuffer)(value);
isType(type) {
return BYTES_REGEX.test(type);
},
if (bufferValue.length > length) {
throw new Error(`Buffer is too long, expected ${length}, got ${bufferValue.length}`);
}
encode({
type,
buffer,
value
}) {
const length = getByteLength(type);
const bufferValue = (0, _utils.toBuffer)(value);
return (0, _utils.concat)([buffer, (0, _utils.addPadding)(bufferValue)]);
};
if (bufferValue.length !== length) {
throw new Error(`Buffer has invalid length, expected ${length}, got ${bufferValue.length}`);
}
exports.encodeFixedBytes = encodeFixedBytes;
return (0, _utils.concat)([buffer, (0, _utils.addPadding)(bufferValue)]);
},
const decodeFixedBytes = (value, _, type) => {
const length = getByteLength(type);
return value.subarray(0, length);
decode({
type,
value
}) {
const length = getByteLength(type);
return value.slice(0, length);
}
};
exports.decodeFixedBytes = decodeFixedBytes;
exports.fixedBytes = fixedBytes;
//# sourceMappingURL=fixed-bytes.js.map

@@ -6,17 +6,43 @@ "use strict";

});
exports.decodeFunction = exports.encodeFunction = void 0;
exports.fn = exports.getFunction = void 0;
var _utils = require("../utils");
var _fixedBytes = require("./fixed-bytes");
const encodeFunction = (buffer, value) => {
return (0, _fixedBytes.encodeFixedBytes)(buffer, value, 'bytes24');
const getFunction = input => {
if (typeof input === 'string') {
return (0, _utils.fromHex)(input);
}
return (0, _utils.concat)([(0, _utils.fromHex)(input.address), (0, _utils.fromHex)(input.selector)]);
};
exports.encodeFunction = encodeFunction;
exports.getFunction = getFunction;
const fn = {
isDynamic: false,
const decodeFunction = (value, buffer) => {
return (0, _fixedBytes.decodeFixedBytes)(value, buffer, 'bytes24');
encode({
buffer,
value
}) {
const fn = getFunction(value);
return _fixedBytes.fixedBytes.encode({
type: 'bytes24',
buffer,
value: fn
});
},
decode({
value
}) {
return {
address: `0x${(0, _utils.toHex)(value.slice(0, 20))}`,
selector: (0, _utils.toHex)(value.slice(20, 24))
};
}
};
exports.decodeFunction = decodeFunction;
exports.fn = fn;
//# sourceMappingURL=function.js.map

@@ -6,3 +6,3 @@ "use strict";

});
exports.decodeNumber = exports.encodeNumber = exports.inRange = exports.getBitLength = exports.isNumber = void 0;
exports.number = exports.asNumber = exports.isSigned = void 0;

@@ -14,34 +14,7 @@ var _utils = require("../utils");

const isSigned = type => {
return type.startsWith('i');
return !type.startsWith('u');
};
const isNumber = type => {
return NUMBER_REGEX.test(type);
};
exports.isSigned = isSigned;
exports.isNumber = isNumber;
const getBitLength = type => {
var _type$match$, _type$match;
const rawBits = (_type$match$ = (_type$match = type.match(NUMBER_REGEX)) === null || _type$match === void 0 ? void 0 : _type$match[1]) !== null && _type$match$ !== void 0 ? _type$match$ : '256';
return Number(rawBits);
};
exports.getBitLength = getBitLength;
const inRange = (value, type) => {
const bits = BigInt(getBitLength(type));
if (isSigned(type)) {
const maxSignedValue = 2n ** (bits - 1n) - 1n;
return value >= -maxSignedValue - 1n && value <= maxSignedValue;
}
const maxValue = 2n ** bits - 1n;
return value >= 0n && value <= maxValue;
};
exports.inRange = inRange;
const asNumber = value => {

@@ -55,27 +28,39 @@ if (typeof value === 'bigint') {

const encodeNumber = (buffer, value, type) => {
const numberValue = asNumber(value);
exports.asNumber = asNumber;
const number = {
isDynamic: false,
if (!inRange(numberValue, type)) {
throw new Error(`Cannot encode number: value is out of range for type ${type}`);
}
isType(type) {
return NUMBER_REGEX.test(type);
},
if (isSigned(type)) {
return (0, _utils.concat)([buffer, (0, _utils.toTwosComplement)(numberValue, 32)]);
}
encode({
type,
buffer,
value
}) {
const number = asNumber(value);
return (0, _utils.concat)([buffer, (0, _utils.toBuffer)(numberValue)]);
};
if (isSigned(type)) {
return (0, _utils.concat)([buffer, (0, _utils.toTwosComplement)(number, 32)]);
}
exports.encodeNumber = encodeNumber;
return (0, _utils.concat)([buffer, (0, _utils.toBuffer)(number)]);
},
const decodeNumber = (value, _, type) => {
if (isSigned(type)) {
return (0, _utils.fromTwosComplement)(value);
decode({
type,
value
}) {
const buffer = value.slice(0, 32);
if (isSigned(type)) {
return (0, _utils.fromTwosComplement)(buffer);
}
return (0, _utils.toNumber)(buffer);
}
return (0, _utils.toNumber)(value);
};
exports.decodeNumber = decodeNumber;
exports.number = number;
//# sourceMappingURL=number.js.map

@@ -6,3 +6,3 @@ "use strict";

});
exports.decodeString = exports.encodeString = void 0;
exports.string = void 0;

@@ -13,14 +13,22 @@ var _utils = require("../utils");

const encodeString = (buffer, value) => {
const bufferValue = (0, _utils.fromUtf8)(value);
return (0, _bytes.encodeBytes)(buffer, bufferValue, 'bytes');
};
const string = {
isDynamic: true,
exports.encodeString = encodeString;
encode({
buffer,
value
}) {
return _bytes.bytes.encode({
type: 'bytes',
buffer,
value: (0, _utils.fromUtf8)(value)
});
},
const decodeString = (value, buffer) => {
return (0, _utils.toUtf8)((0, _bytes.decodeBytes)(value, buffer, 'string'));
decode(args) {
return (0, _utils.toUtf8)(_bytes.bytes.decode(args));
}
};
exports.decodeString = decodeString;
exports.string = string;
//# sourceMappingURL=string.js.map

@@ -6,47 +6,52 @@ "use strict";

});
exports.decodeTuple = exports.encodeTuple = exports.isDynamicTuple = exports.getTypes = exports.isTuple = void 0;
exports.tuple = exports.getTupleElements = void 0;
var _array = require("./array");
var _packer = require("../packer");
const TUPLE_REGEX = /^\((.*)\)$/;
const isTuple = type => {
return TUPLE_REGEX.test(type);
};
exports.isTuple = isTuple;
const getTypes = type => {
const getTupleElements = type => {
return type.slice(1, -1).split(',').map(type => type.trim());
};
exports.getTypes = getTypes;
exports.getTupleElements = getTupleElements;
const tuple = {
isDynamic(type) {
const elements = getTupleElements(type);
return elements.some(element => {
const parser = (0, _packer.getParser)(element);
return (0, _packer.isDynamicParser)(parser, element);
});
},
const isDynamicTuple = types => {
return types.map(_array.getParser).some(parser => parser.dynamic);
};
isType(type) {
return TUPLE_REGEX.test(type);
},
exports.isDynamicTuple = isDynamicTuple;
encode({
type,
buffer,
value
}) {
const elements = getTupleElements(type);
return (0, _packer.pack)(elements, value, buffer);
},
const encodeTuple = (buffer, values, type) => {
if (!isTuple(type)) {
throw new Error('Invalid type: type is not tuple');
}
decode({
type,
value,
skip
}) {
const elements = getTupleElements(type);
const length = elements.length * 32 - 32;
const types = getTypes(type);
return (0, _array.pack)(buffer, values, types);
};
if (!(0, _packer.isDynamicParser)(this, type)) {
skip(length);
}
exports.encodeTuple = encodeTuple;
const decodeTuple = (value, _, type) => {
if (!isTuple(type)) {
throw new Error('Invalid type: type is not tuple');
return (0, _packer.unpack)(elements, value);
}
const types = getTypes(type);
return (0, _array.unpack)(value, types);
};
exports.decodeTuple = decodeTuple;
exports.tuple = tuple;
//# sourceMappingURL=tuple.js.map

@@ -1,8 +0,8 @@

import { pack, unpack } from './parsers/array';
import { pack, unpack } from './packer';
export const encode = (types, values) => {
return pack(new Uint8Array(0), values, types);
return pack(types, values, new Uint8Array());
};
export const decode = (types, buffer) => {
return unpack(buffer, types);
return unpack(types, buffer);
};
//# sourceMappingURL=abi.js.map
import { concat, fromHex, stripPrefix, toHex } from '../utils';
export const encodeAddress = (buffer, value) => {
if (value.length !== 42) {
throw new Error('Invalid address length');
export const address = {
isDynamic: false,
encode({
buffer,
value
}) {
const addressBuffer = fromHex(stripPrefix(value).padStart(64, '0'));
return concat([buffer, addressBuffer]);
},
decode({
value
}) {
return `0x${toHex(value.slice(12, 32))}`;
}
const addressBuffer = fromHex(stripPrefix(value).padStart(64, '0'));
return concat([buffer, addressBuffer]);
};
export const decodeAddress = value => {
const addressBuffer = value.subarray(-20);
return `0x${toHex(addressBuffer)}`;
};
//# sourceMappingURL=address.js.map

@@ -0,178 +1,40 @@

import { pack, unpack } from '../packer';
import { concat, toBuffer, toNumber } from '../utils';
import { decodeAddress, encodeAddress } from './address';
import { decodeBoolean, encodeBoolean } from './boolean';
import { decodeBytes, encodeBytes } from './bytes';
import { decodeFixedBytes, encodeFixedBytes, isFixedBytes } from './fixed-bytes';
import { decodeNumber, encodeNumber, isNumber } from './number';
import { decodeString, encodeString } from './string';
import { decodeTuple, encodeTuple, getTypes, isDynamicTuple, isTuple } from './tuple';
const ARRAY_REGEX = /^(.*)\[]$/;
export const isArray = type => {
return ARRAY_REGEX.test(type);
};
export const getType = type => {
return type.match(ARRAY_REGEX)[1];
};
export const encodeArray = (buffer, values, type) => {
if (!isArray(type)) {
throw new Error('Invalid type: type is not array');
export const getArrayType = type => {
const match = type.match(ARRAY_REGEX);
if (match) {
return match[1];
}
const actualType = getType(type);
const length = toBuffer(values.length);
const arrayBuffer = concat([buffer, length]);
return pack(arrayBuffer, values, new Array(values.length).fill(actualType));
throw new Error('Type is not an array type');
};
export const decodeArray = (value, buffer, type) => {
if (!isArray(type)) {
throw new Error('Invalid type: type is not array');
}
export const array = {
isDynamic: true,
const actualType = getType(type);
const pointer = Number(toNumber(value));
const length = Number(toNumber(buffer.subarray(pointer, pointer + 32)));
const arrayPointer = pointer + 32;
const arrayBuffer = buffer.subarray(arrayPointer);
return unpack(arrayBuffer, new Array(length).fill(actualType));
};
const parsers = {
address: {
dynamic: false,
encode: encodeAddress,
decode: decodeAddress
isType(type) {
return ARRAY_REGEX.test(type);
},
array: {
dynamic: true,
encode: encodeArray,
decode: decodeArray
encode({
type,
buffer,
value
}) {
const arrayType = getArrayType(type);
const arrayLength = toBuffer(value.length);
return pack(new Array(value.length).fill(arrayType), value, concat([buffer, arrayLength]));
},
bool: {
dynamic: false,
encode: encodeBoolean,
decode: decodeBoolean
},
bytes: {
dynamic: true,
encode: encodeBytes,
decode: decodeBytes
},
fixedBytes: {
dynamic: false,
encode: encodeFixedBytes,
decode: decodeFixedBytes
},
number: {
dynamic: false,
encode: encodeNumber,
decode: decodeNumber
},
string: {
dynamic: true,
encode: encodeString,
decode: decodeString
},
tuple: {
dynamic: false,
encode: encodeTuple,
decode: decodeTuple
}
};
export const getParser = type => {
if (parsers[type]) {
return parsers[type];
}
if (isFixedBytes(type)) {
return parsers.fixedBytes;
decode({
type,
value
}) {
const arrayType = getArrayType(type);
const arrayLength = Number(toNumber(value.subarray(0, 32)));
return unpack(new Array(arrayLength).fill(arrayType), value.subarray(32));
}
if (isNumber(type)) {
return parsers.number;
}
if (isArray(type)) {
return parsers.array;
}
if (isTuple(type)) {
return parsers.tuple;
}
throw new Error(`type "${type}" is not supported`);
};
export const pack = (buffer, values, types) => {
const {
staticBuffer: packedStaticBuffer,
dynamicBuffer: packedDynamicBuffer,
updateFunctions: packedUpdateFunctions
} = types.reduce(({
staticBuffer,
dynamicBuffer,
updateFunctions
}, type, index) => {
const parser = getParser(type);
const value = values[index];
if (parser.dynamic) {
const offset = dynamicBuffer.length;
const staticOffset = staticBuffer.length;
const newStaticBuffer = concat([staticBuffer, new Uint8Array(32).fill(0)]);
const newDynamicBuffer = parser.encode(dynamicBuffer, value, type);
const update = oldBuffer => {
return concat([oldBuffer.subarray(0, staticOffset), toBuffer(oldBuffer.length + offset), oldBuffer.subarray(staticOffset + 32)]);
};
return {
staticBuffer: newStaticBuffer,
dynamicBuffer: newDynamicBuffer,
updateFunctions: [...updateFunctions, update]
};
}
const newBuffer = parser.encode(staticBuffer, value, type);
return {
staticBuffer: newBuffer,
dynamicBuffer,
updateFunctions
};
}, {
staticBuffer: new Uint8Array(0),
dynamicBuffer: new Uint8Array(0),
updateFunctions: []
});
const updatedStaticBuffer = packedUpdateFunctions.reduce((target, update) => update(target), packedStaticBuffer);
return concat([buffer, updatedStaticBuffer, packedDynamicBuffer]);
};
export const unpack = (buffer, types) => {
let pointer = 0;
return types.map(type => {
if (pointer >= buffer.length) {
throw new Error('input data has an invalid length');
}
const parser = getParser(type);
if (isTuple(type)) {
const types = getTypes(type);
if (isDynamicTuple(types)) {
const value = buffer.subarray(pointer, pointer + 32);
const valuePointer = Number(toNumber(value));
const actualValue = buffer.subarray(valuePointer);
pointer += 32;
return parser.decode(actualValue, buffer, type);
}
const tupleLength = types.length * 32;
const value = buffer.subarray(pointer, pointer + tupleLength);
pointer += tupleLength;
return parser.decode(value, buffer, type);
}
const value = buffer.subarray(pointer, pointer + 32);
pointer += 32;
return parser.decode(value, buffer, type);
});
};
//# sourceMappingURL=array.js.map
import { addPadding, concat, toBuffer, toNumber } from '../utils';
export const encodeBytes = (buffer, value) => {
const bufferValue = toBuffer(value);
const paddedSize = Math.ceil(bufferValue.byteLength / 32) * 32;
return concat([buffer, toBuffer(bufferValue.byteLength), addPadding(bufferValue, paddedSize)]);
export const bytes = {
isDynamic: true,
encode({
buffer,
value
}) {
const bufferValue = toBuffer(value);
const paddedSize = Math.ceil(bufferValue.byteLength / 32) * 32;
return concat([buffer, toBuffer(bufferValue.byteLength), addPadding(bufferValue, paddedSize)]);
},
decode({
value
}) {
const buffer = value.slice(0, 32);
const length = Number(toNumber(buffer));
return value.subarray(32, 32 + length);
}
};
export const decodeBytes = (value, buffer) => {
const pointer = Number(toNumber(value.subarray(0, 32)));
const length = Number(toNumber(buffer.subarray(pointer, pointer + 32)));
return buffer.subarray(pointer + 32, pointer + 32 + Number(length));
};
//# sourceMappingURL=bytes.js.map
import { addPadding, concat, toBuffer } from '../utils';
const BYTES_REGEX = /^bytes([0-9]{1,2})$/;
export const isFixedBytes = type => {
return BYTES_REGEX.test(type);
};
export const getByteLength = type => {

@@ -23,16 +20,33 @@ var _type$match;

};
export const encodeFixedBytes = (buffer, value, type) => {
const length = getByteLength(type);
const bufferValue = toBuffer(value);
export const fixedBytes = {
isDynamic: false,
if (bufferValue.length > length) {
throw new Error(`Buffer is too long, expected ${length}, got ${bufferValue.length}`);
isType(type) {
return BYTES_REGEX.test(type);
},
encode({
type,
buffer,
value
}) {
const length = getByteLength(type);
const bufferValue = toBuffer(value);
if (bufferValue.length !== length) {
throw new Error(`Buffer has invalid length, expected ${length}, got ${bufferValue.length}`);
}
return concat([buffer, addPadding(bufferValue)]);
},
decode({
type,
value
}) {
const length = getByteLength(type);
return value.slice(0, length);
}
return concat([buffer, addPadding(bufferValue)]);
};
export const decodeFixedBytes = (value, _, type) => {
const length = getByteLength(type);
return value.subarray(0, length);
};
//# sourceMappingURL=fixed-bytes.js.map

@@ -1,8 +0,35 @@

import { decodeFixedBytes, encodeFixedBytes } from './fixed-bytes';
export const encodeFunction = (buffer, value) => {
return encodeFixedBytes(buffer, value, 'bytes24');
import { concat, fromHex, toHex } from '../utils';
import { fixedBytes } from './fixed-bytes';
export const getFunction = input => {
if (typeof input === 'string') {
return fromHex(input);
}
return concat([fromHex(input.address), fromHex(input.selector)]);
};
export const decodeFunction = (value, buffer) => {
return decodeFixedBytes(value, buffer, 'bytes24');
export const fn = {
isDynamic: false,
encode({
buffer,
value
}) {
const fn = getFunction(value);
return fixedBytes.encode({
type: 'bytes24',
buffer,
value: fn
});
},
decode({
value
}) {
return {
address: `0x${toHex(value.slice(0, 20))}`,
selector: toHex(value.slice(20, 24))
};
}
};
//# sourceMappingURL=function.js.map

@@ -1,30 +0,7 @@

import { concat, toBuffer, toNumber, fromTwosComplement, toTwosComplement } from '../utils';
import { concat, fromTwosComplement, toBuffer, toNumber, toTwosComplement } from '../utils';
const NUMBER_REGEX = /^u?int([0-9]*)?$/;
const isSigned = type => {
return type.startsWith('i');
export const isSigned = type => {
return !type.startsWith('u');
};
export const isNumber = type => {
return NUMBER_REGEX.test(type);
};
export const getBitLength = type => {
var _type$match$, _type$match;
const rawBits = (_type$match$ = (_type$match = type.match(NUMBER_REGEX)) === null || _type$match === void 0 ? void 0 : _type$match[1]) !== null && _type$match$ !== void 0 ? _type$match$ : '256';
return Number(rawBits);
};
export const inRange = (value, type) => {
const bits = BigInt(getBitLength(type));
if (isSigned(type)) {
const maxSignedValue = 2n ** (bits - 1n) - 1n;
return value >= -maxSignedValue - 1n && value <= maxSignedValue;
}
const maxValue = 2n ** bits - 1n;
return value >= 0n && value <= maxValue;
};
const asNumber = value => {
export const asNumber = value => {
if (typeof value === 'bigint') {

@@ -36,23 +13,37 @@ return value;

};
export const number = {
isDynamic: false,
export const encodeNumber = (buffer, value, type) => {
const numberValue = asNumber(value);
isType(type) {
return NUMBER_REGEX.test(type);
},
if (!inRange(numberValue, type)) {
throw new Error(`Cannot encode number: value is out of range for type ${type}`);
}
encode({
type,
buffer,
value
}) {
const number = asNumber(value);
if (isSigned(type)) {
return concat([buffer, toTwosComplement(numberValue, 32)]);
}
if (isSigned(type)) {
return concat([buffer, toTwosComplement(number, 32)]);
}
return concat([buffer, toBuffer(numberValue)]);
};
export const decodeNumber = (value, _, type) => {
if (isSigned(type)) {
return fromTwosComplement(value);
return concat([buffer, toBuffer(number)]);
},
decode({
type,
value
}) {
const buffer = value.slice(0, 32);
if (isSigned(type)) {
return fromTwosComplement(buffer);
}
return toNumber(buffer);
}
return toNumber(value);
};
//# sourceMappingURL=number.js.map
import { fromUtf8, toUtf8 } from '../utils';
import { decodeBytes, encodeBytes } from './bytes';
export const encodeString = (buffer, value) => {
const bufferValue = fromUtf8(value);
return encodeBytes(buffer, bufferValue, 'bytes');
import { bytes } from './bytes';
export const string = {
isDynamic: true,
encode({
buffer,
value
}) {
return bytes.encode({
type: 'bytes',
buffer,
value: fromUtf8(value)
});
},
decode(args) {
return toUtf8(bytes.decode(args));
}
};
export const decodeString = (value, buffer) => {
return toUtf8(decodeBytes(value, buffer, 'string'));
};
//# sourceMappingURL=string.js.map

@@ -1,28 +0,44 @@

import { getParser, pack, unpack } from './array';
import { getParser, isDynamicParser, pack, unpack } from '../packer';
const TUPLE_REGEX = /^\((.*)\)$/;
export const isTuple = type => {
return TUPLE_REGEX.test(type);
};
export const getTypes = type => {
export const getTupleElements = type => {
return type.slice(1, -1).split(',').map(type => type.trim());
};
export const isDynamicTuple = types => {
return types.map(getParser).some(parser => parser.dynamic);
};
export const encodeTuple = (buffer, values, type) => {
if (!isTuple(type)) {
throw new Error('Invalid type: type is not tuple');
}
export const tuple = {
isDynamic(type) {
const elements = getTupleElements(type);
return elements.some(element => {
const parser = getParser(element);
return isDynamicParser(parser, element);
});
},
const types = getTypes(type);
return pack(buffer, values, types);
};
export const decodeTuple = (value, _, type) => {
if (!isTuple(type)) {
throw new Error('Invalid type: type is not tuple');
isType(type) {
return TUPLE_REGEX.test(type);
},
encode({
type,
buffer,
value
}) {
const elements = getTupleElements(type);
return pack(elements, value, buffer);
},
decode({
type,
value,
skip
}) {
const elements = getTupleElements(type);
const length = elements.length * 32 - 32;
if (!isDynamicParser(this, type)) {
skip(length);
}
return unpack(elements, value);
}
const types = getTypes(type);
return unpack(value, types);
};
//# sourceMappingURL=tuple.js.map
{
"name": "@findeth/abi",
"version": "0.6.1",
"version": "0.7.0",
"description": "A tiny Solidity ABI encoder and decoder",

@@ -5,0 +5,0 @@ "author": "Maarten Zuidhoorn <maarten@zuidhoorn.com>",

# `@findeth/abi`
![Version](https://img.shields.io/npm/v/@findeth/abi) ![License](https://img.shields.io/github/license/FindETH/abi) [![Travis CI](https://travis-ci.com/FindETH/abi.svg?branch=master)](https://travis-ci.com/FindETH/abi) [![codecov](https://codecov.io/gh/FindETH/abi/branch/master/graph/badge.svg)](https://codecov.io/gh/FindETH/abi)
![Version](https://img.shields.io/npm/v/@findeth/abi) ![License](https://img.shields.io/github/license/FindETH/abi) [![GitHub CI](https://github.com/FindETH/abi/workflows/CI/badge.svg)](https://github.com/FindETH/abi/actions) [![codecov](https://codecov.io/gh/FindETH/abi/branch/master/graph/badge.svg)](https://codecov.io/gh/FindETH/abi)
`@findeth/abi` is a zero-dependencies ABI encoder and decoder library for FindETH. It supports both Node.js and web browsers. **This library is experimental**, and may not work with all contract interfaces. It is used in the FindETH applications, that can be found here:
`@findeth/abi` is a zero-dependencies ABI encoder and decoder library used by FindETH. **This library is experimental**, and likely does not work with all contract interfaces. It is used in the desktop, web and CLI applications, that can be found here:
- [Desktop](https://github.com/FindETH/desktop)
- [Web](https://github.com/FindETH/web)
- [CLI](https://github.com/FindETH/cli)
**Note**: This is a work-in-progress version of FindETH, and is **not** production-ready. For the current version of FindETH, please refer to [this repository](https://github.com/Mrtenz/FindETH/tree/master).
Currently, most types (except fixed-point numbers (`fixed<M>x<N>`), and fixed-length arrays `type<M>`) are supported.
**Note**: This is a work-in-progress version of FindETH, and is **not** production-ready. For the current version of FindETH, please refer to [this repository](https://github.com/Mrtenz/FindETH/tree/master). The public API _may_ change in minor releases below 1.0.0 (though this is unlikely).
---

@@ -28,8 +27,34 @@

**Note**: If you are using TypeScript, `@findeth/abi` requires TypeScript 4.1 or newer.
**Note**: If you are using TypeScript, `@findeth/abi` requires TypeScript 4.1 or newer. This is used for automatically inferring the types of the input and output, based on the specified `types`.
## Getting Started
TODO
You can use the `encode` and `decode` functions to encode and decode ABI respectively.
### Encode
The encode function takes an array of ABI types (e.g., `["string", "uint256"]`) and an array of values to encode. For example:
```ts
import { encode, toHex } from "@findeth/abi";
const buffer = encode(["string", "uint256"], ["foo bar", 12345]);
console.log(toHex(buffer));
// 000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000030390000000000000000000000000000000000000000000000000000000000000007666f6f2062617200000000000000000000000000000000000000000000000000
```
### Decode
The decode function takes an array of ABI types, and a buffer (`Uint8Array`) to decode. Note that Node.js `Buffer`s are compatible with `Uint8Array`, but in order to maintain full compatibility with web browsers (without the need for polyfills), this library does not use `Buffer`. Example:
```ts
import { decode, fromHex } from "@findeth/abi";
const value = fromHex("000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000030390000000000000000000000000000000000000000000000000000000000000007666f6f2062617200000000000000000000000000000000000000000000000000");
console.log(decode(["string", "uint256"], value));
// ["foo bar", 12345n]
```
## Development

@@ -46,3 +71,3 @@

```
$ yarn run lint
$ yarn test
```

@@ -54,3 +79,3 @@

```
$ yarn run build
$ yarn build
```

@@ -5,32 +5,23 @@ import { decode, encode } from './abi';

describe('encode', () => {
it('encodes simple values', () => {
expect(toHex(encode(['uint256', 'uint256'], [12345n, 12345n]))).toBe(
'00000000000000000000000000000000000000000000000000000000000030390000000000000000000000000000000000000000000000000000000000003039'
it('encodes static values', () => {
expect(toHex(encode(['uint256', 'address'], [12345n, '0x4bbeEB066eD09B7AEd07bF39EEe0460DFa261520']))).toBe(
'00000000000000000000000000000000000000000000000000000000000030390000000000000000000000004bbeeb066ed09b7aed07bf39eee0460dfa261520'
);
});
it('encodes array values', () => {
expect(toHex(encode(['uint256', 'uint256[]', 'uint256'], [12345n, [67890n, 67890n], 12345n]))).toBe(
'000000000000000000000000000000000000000000000000000000000000303900000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000003039000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000109320000000000000000000000000000000000000000000000000000000000010932'
it('encodes static array values', () => {
expect(toHex(encode(['(uint256, address)[]'], [[[12345n, '0x4bbeEB066eD09B7AEd07bF39EEe0460DFa261520']]]))).toBe(
'0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000030390000000000000000000000004bbeeb066ed09b7aed07bf39eee0460dfa261520'
);
expect(toHex(encode(['string', 'string', 'string'], ['foo', 'bar', 'baz']))).toBe(
'000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000003666f6f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000036261720000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000362617a0000000000000000000000000000000000000000000000000000000000'
);
});
it('encodes tuple values', () => {
expect(toHex(encode(['uint256', '(uint256, uint256)', 'uint256'], [123n, [456n, 789n], 123n]))).toBe(
'000000000000000000000000000000000000000000000000000000000000007b00000000000000000000000000000000000000000000000000000000000001c80000000000000000000000000000000000000000000000000000000000000315000000000000000000000000000000000000000000000000000000000000007b'
);
});
it('encodes tuple array values', () => {
it('encodes dynamic array values', () => {
expect(
toHex(
encode(
['(uint256, uint256)[]'],
['(string, string)[]'],
[
[
[12n, 34n],
[56n, 78n]
['foo bar', 'baz qux'],
['quux quuz', 'corge grault']
]

@@ -41,83 +32,43 @@ ]

).toBe(
'00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000038000000000000000000000000000000000000000000000000000000000000004e'
'0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000007666f6f2062617200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000762617a207175780000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000971757578207175757a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c636f72676520677261756c740000000000000000000000000000000000000000'
);
});
it('encodes nested values', () => {
expect(
toHex(
encode(
['uint256', 'uint256[][]', 'uint256'],
[
12345n,
[
[54321n, 12345n],
[67890n, 98760n]
],
12345n
]
)
)
).toBe(
'0000000000000000000000000000000000000000000000000000000000003039000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000030390000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000d43100000000000000000000000000000000000000000000000000000000000030390000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000001093200000000000000000000000000000000000000000000000000000000000181c8'
it('encodes dynamic tuple values', () => {
expect(toHex(encode(['(string, uint256, string)'], [['foo bar', 12n, 'baz qux']]))).toBe(
'00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000007666f6f2062617200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000762617a2071757800000000000000000000000000000000000000000000000000'
);
});
it('encodes bytes values', () => {
const bytes = fromHex('123456789abcdef123456789abcdef123456789abcde');
expect(toHex(encode(['bytes'], [bytes]))).toBe(
'00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000016123456789abcdef123456789abcdef123456789abcde00000000000000000000'
);
});
it('encodes string values', () => {
const string = 'foo bar baz qux quux corge';
expect(toHex(encode(['string'], [string]))).toBe(
'0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001a666f6f206261722062617a20717578207175757820636f726765000000000000'
);
});
});
describe('decode', () => {
it('decodes a token transfer', () => {
const buffer = fromHex(
'0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000000000000000000000000000000000000000003039'
);
expect(decode(['address', 'uint256'], buffer)).toStrictEqual([
'0x6b175474e89094c44da98b954eedeac495271d0f',
12345n
]);
});
it('decodes array values', () => {
const buffer = fromHex(
'000000000000000000000000000000000000000000000000000000000000303900000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000003039000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000109320000000000000000000000000000000000000000000000000000000000010932'
);
expect(decode(['uint256', 'uint256[]', 'uint256'], buffer)).toStrictEqual([12345n, [67890n, 67890n], 12345n]);
it('decodes static values', () => {
expect(
decode(
['string[]'],
['uint256', 'address'],
fromHex(
'00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000003666f6f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000036261720000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000362617a0000000000000000000000000000000000000000000000000000000000'
'00000000000000000000000000000000000000000000000000000000000030390000000000000000000000004bbeeb066ed09b7aed07bf39eee0460dfa261520'
)
)
).toStrictEqual([['foo', 'bar', 'baz']]);
).toStrictEqual([12345n, '0x4bbeeb066ed09b7aed07bf39eee0460dfa261520']);
});
it('decodes tuple values', () => {
const buffer = fromHex(
'000000000000000000000000000000000000000000000000000000000000007b00000000000000000000000000000000000000000000000000000000000001c80000000000000000000000000000000000000000000000000000000000000315000000000000000000000000000000000000000000000000000000000000007b'
it('decodes static array values', () => {
const value = fromHex(
'0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000030390000000000000000000000004bbeeb066ed09b7aed07bf39eee0460dfa261520'
);
expect(decode(['uint256', '(uint256, uint256)', 'uint256'], buffer)).toStrictEqual([123n, [456n, 789n], 123n]);
expect(decode(['(uint256, address)[]'], value)).toStrictEqual([
[[12345n, '0x4bbeeb066ed09b7aed07bf39eee0460dfa261520']]
]);
});
it('decodes tuple array values', () => {
const buffer = fromHex(
'00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000038000000000000000000000000000000000000000000000000000000000000004e'
it('decodes dynamic array values', () => {
const value = fromHex(
'0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000007666f6f2062617200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000762617a207175780000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000971757578207175757a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c636f72676520677261756c740000000000000000000000000000000000000000'
);
expect(decode(['(uint256, uint256)[]'], buffer)).toStrictEqual([
expect(decode(['(string, string)[]'], value)).toStrictEqual([
[
[12n, 34n],
[56n, 78n]
['foo bar', 'baz qux'],
['quux quuz', 'corge grault']
]

@@ -127,8 +78,8 @@ ]);

it('decodes bytes values', () => {
const buffer = fromHex(
'00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000016123456789abcdef123456789abcdef123456789abcde00000000000000000000'
it('decodes dynamic tuple values', () => {
const value = fromHex(
'00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000007666f6f2062617200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000762617a2071757800000000000000000000000000000000000000000000000000'
);
expect(toHex(decode(['bytes'], buffer)[0])).toBe('123456789abcdef123456789abcdef123456789abcde');
expect(decode(['(string, uint256, string)'], value)).toStrictEqual([['foo bar', 12n, 'baz qux']]);
});
});

@@ -1,6 +0,10 @@

import { pack, unpack } from './parsers/array';
import { Type, TypeMapper, Narrow, InputTypeMap } from './types';
import { pack, unpack } from './packer';
import { InputTypeMap, Narrow, Type, TypeMapper } from './types';
/**
* Encode the data with the provided types.
*
* @param types The types to encode.
* @param values The values to encode. This array must have the same length as the types array.
* @return The ABI encoded buffer.
*/

@@ -11,10 +15,14 @@ export const encode = <T extends Array<Type | string>>(

): Uint8Array => {
return pack(new Uint8Array(0), values, types);
return pack(types, values, new Uint8Array());
};
/**
* Decode the data with the provided types.
* Decode an ABI encoded buffer with the specified types.
*
* @param types The types to decode the buffer with.
* @param buffer The buffer to decode.
* @return The decoded values as array.
*/
export const decode = <T extends Array<Type | string>>(types: Narrow<T>, buffer: Uint8Array): TypeMapper<T> => {
return unpack(buffer, types) as TypeMapper<T>;
return unpack(types, buffer) as TypeMapper<T>;
};
import { fromHex, toHex } from '../utils';
import { decodeAddress, encodeAddress } from './address';
import { address } from './address';
describe('encodeAddress', () => {
it('encodes an address', () => {
expect(toHex(encodeAddress(new Uint8Array(0), '0x4bbeEB066eD09B7AEd07bF39EEe0460DFa261520', 'address'))).toBe(
'0000000000000000000000004bbeeb066ed09b7aed07bf39eee0460dfa261520'
);
describe('address', () => {
describe('encode', () => {
it('encodes an address', () => {
expect(
toHex(
address.encode({
type: 'address',
buffer: new Uint8Array(),
value: '0x4bbeeb066ed09b7aed07bf39eee0460dfa261520'
})
)
).toBe('0000000000000000000000004bbeeb066ed09b7aed07bf39eee0460dfa261520');
});
});
});
describe('decodeAddress', () => {
it('encodes an address', () => {
const buffer = fromHex('0000000000000000000000004bbeeb066ed09b7aed07bf39eee0460dfa261520');
expect(decodeAddress(buffer, buffer, 'address')).toBe('0x4bbeeb066ed09b7aed07bf39eee0460dfa261520');
describe('decode', () => {
it('decodes an encoded address', () => {
const value = fromHex('0000000000000000000000004bbeeb066ed09b7aed07bf39eee0460dfa261520');
expect(address.decode({ type: 'address', value, skip: jest.fn() })).toBe(
'0x4bbeeb066ed09b7aed07bf39eee0460dfa261520'
);
});
});
});

@@ -1,17 +0,16 @@

import { DecodeFunction, EncodeFunction } from '../types';
import { DecodeArgs, Parser } from '../types';
import { concat, fromHex, stripPrefix, toHex } from '../utils';
export const encodeAddress: EncodeFunction<string> = (buffer: Uint8Array, value: string): Uint8Array => {
if (value.length !== 42) {
throw new Error('Invalid address length');
}
export const address: Parser<string> = {
isDynamic: false,
const addressBuffer = fromHex(stripPrefix(value).padStart(64, '0'));
encode({ buffer, value }): Uint8Array {
const addressBuffer = fromHex(stripPrefix(value).padStart(64, '0'));
return concat([buffer, addressBuffer]);
};
return concat([buffer, addressBuffer]);
},
export const decodeAddress: DecodeFunction<string> = (value: Uint8Array): string => {
const addressBuffer = value.subarray(-20);
return `0x${toHex(addressBuffer)}`;
decode({ value }: DecodeArgs): string {
return `0x${toHex(value.slice(12, 32))}`;
}
};
import { fromHex, toHex } from '../utils';
import { decodeArray, encodeArray, getType, isArray } from './array';
import { array, getArrayType } from './array';
describe('isArray', () => {
it('checks if a type is an array type', () => {
expect(isArray('string[]')).toBe(true);
expect(isArray('uint256[]')).toBe(true);
expect(isArray('string[][]')).toBe(true);
// TODO
// expect(isArray('string[5]')).toBe(true);
expect(isArray('string')).toBe(false);
expect(isArray('uint256')).toBe(false);
expect(isArray('uint256[')).toBe(false);
describe('getArrayType', () => {
it('returns the type of the array', () => {
expect(getArrayType('uint256[]')).toBe('uint256');
expect(getArrayType('uint256[][]')).toBe('uint256[]');
expect(getArrayType('(uint256)[]')).toBe('(uint256)');
expect(getArrayType('(uint256[])[]')).toBe('(uint256[])');
});
});
describe('getType', () => {
it('returns the type of an array', () => {
expect(getType('string[]')).toStrictEqual('string');
expect(getType('uint256[]')).toStrictEqual('uint256');
expect(getType('string[][]')).toStrictEqual('string[]');
expect(getType('(foo,bar)[]')).toStrictEqual('(foo,bar)');
it('throws if a type is not an array type', () => {
expect(() => getArrayType('uint256')).toThrow();
expect(() => getArrayType('(uint256)')).toThrow();
});
});
describe('encodeArray', () => {
it('encodes an array with single type', () => {
expect(toHex(encodeArray(new Uint8Array(0), ['foo', 'bar', 'baz'], 'string[]'))).toBe(
'0000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000003666f6f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000036261720000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000362617a0000000000000000000000000000000000000000000000000000000000'
);
expect(toHex(encodeArray(new Uint8Array(0), [1n, 2n, 3n], 'uint256[]'))).toBe(
'0000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003'
);
});
describe('array', () => {
describe('isType', () => {
it('checks if a type is a tuple type', () => {
expect(array.isType?.('uint256[]')).toBe(true);
expect(array.isType?.('uint256[][]')).toBe(true);
it('throws if a type is not an array type', () => {
expect(() => encodeArray(new Uint8Array(0), ['foo', 'bar', 'baz'], 'string')).toThrow();
expect(array.isType?.('uint256')).toBe(false);
expect(array.isType?.('(uint256)')).toBe(false);
});
});
});
describe('decodeArray', () => {
it('decodes an array', () => {
const value = fromHex('0000000000000000000000000000000000000000000000000000000000000020');
const buffer = fromHex(
'00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000003666f6f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000036261720000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000362617a0000000000000000000000000000000000000000000000000000000000'
);
describe('encode', () => {
it('encodes an array', () => {
expect(toHex(array.encode({ type: 'uint256[]', value: [12n, 34n, 56n, 78n], buffer: new Uint8Array() }))).toBe(
'0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000038000000000000000000000000000000000000000000000000000000000000004e'
);
});
expect(decodeArray(value, buffer, 'string[]')).toStrictEqual(['foo', 'bar', 'baz']);
it('encodes a nested array', () => {
expect(
toHex(
array.encode({
type: 'uint256[][]',
value: [
[12n, 34n],
[56n, 78n]
],
buffer: new Uint8Array()
})
)
).toBe(
'0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000038000000000000000000000000000000000000000000000000000000000000004e'
);
});
});
it('throws if a type is not an array type', () => {
const buffer = fromHex(
'0000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000003666f6f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000036261720000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000362617a0000000000000000000000000000000000000000000000000000000000'
);
expect(() => decodeArray(new Uint8Array(0), buffer, 'string')).toThrow();
describe('decode', () => {
it('decodes an encoded array', () => {
const value = fromHex(
'0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000038000000000000000000000000000000000000000000000000000000000000004e'
);
expect(array.decode({ type: 'uint256[]', value, skip: jest.fn() })).toStrictEqual([12n, 34n, 56n, 78n]);
});
it('decodes an encoded nested array', () => {
const value = fromHex(
'0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000038000000000000000000000000000000000000000000000000000000000000004e'
);
expect(array.decode({ type: 'uint256[][]', value, skip: jest.fn() })).toStrictEqual([
[12n, 34n],
[56n, 78n]
]);
});
});
});

@@ -1,255 +0,49 @@

import { DecodeFunction, EncodeFunction } from '../types';
import { pack, unpack } from '../packer';
import { DecodeArgs, Parser } from '../types';
import { concat, toBuffer, toNumber } from '../utils';
import { decodeAddress, encodeAddress } from './address';
import { decodeBoolean, encodeBoolean } from './boolean';
import { decodeBytes, encodeBytes } from './bytes';
import { decodeFixedBytes, encodeFixedBytes, isFixedBytes } from './fixed-bytes';
import { decodeNumber, encodeNumber, isNumber } from './number';
import { decodeString, encodeString } from './string';
import { decodeTuple, encodeTuple, getTypes, isDynamicTuple, isTuple } from './tuple';
// TODO: Add support for fixed length arrays
const ARRAY_REGEX = /^(.*)\[]$/;
/**
* Check if a type is an array type.
* Get the type of the array.
*
* @param {string} type
* @return {boolean}
* @param type The type to get the array type for.
* @return The array type.
*/
export const isArray = (type: string): boolean => {
return ARRAY_REGEX.test(type);
};
/**
* Get the "inner" type for an array type. E.g. `getType("uint256[]")` -> ["uint256"].
*
* @param {string} type
* @return {string}
*/
export const getType = (type: string): string => {
return type.match(ARRAY_REGEX)![1];
};
export const encodeArray: EncodeFunction<unknown[]> = (
buffer: Uint8Array,
values: unknown[],
type: string
): Uint8Array => {
if (!isArray(type)) {
throw new Error('Invalid type: type is not array');
export const getArrayType = (type: string): string => {
const match = type.match(ARRAY_REGEX);
if (match) {
return match[1];
}
const actualType = getType(type);
const length = toBuffer(values.length);
const arrayBuffer = concat([buffer, length]);
return pack(arrayBuffer, values, new Array(values.length).fill(actualType));
throw new Error('Type is not an array type');
};
export const decodeArray: DecodeFunction<unknown[]> = (
value: Uint8Array,
buffer: Uint8Array,
type: string
): unknown[] => {
if (!isArray(type)) {
throw new Error('Invalid type: type is not array');
}
export const array: Parser<unknown[]> = {
isDynamic: true,
const actualType = getType(type);
const pointer = Number(toNumber(value));
const length = Number(toNumber(buffer.subarray(pointer, pointer + 32)));
/**
* Check if a type is an array type.
*
* @param type The type to check.
* @return Whether the type is a array type.
*/
isType(type: string): boolean {
return ARRAY_REGEX.test(type);
},
const arrayPointer = pointer + 32;
const arrayBuffer = buffer.subarray(arrayPointer);
encode({ type, buffer, value }): Uint8Array {
const arrayType = getArrayType(type);
const arrayLength = toBuffer(value.length);
return unpack(arrayBuffer, new Array(length).fill(actualType));
};
/**
* All available parsers.
*/
const parsers = {
address: {
dynamic: false,
encode: encodeAddress,
decode: decodeAddress
return pack(new Array(value.length).fill(arrayType), value, concat([buffer, arrayLength]));
},
array: {
dynamic: true,
encode: encodeArray,
decode: decodeArray
},
bool: {
dynamic: false,
encode: encodeBoolean,
decode: decodeBoolean
},
bytes: {
dynamic: true,
encode: encodeBytes,
decode: decodeBytes
},
fixedBytes: {
dynamic: false,
encode: encodeFixedBytes,
decode: decodeFixedBytes
},
number: {
dynamic: false,
encode: encodeNumber,
decode: decodeNumber
},
string: {
dynamic: true,
encode: encodeString,
decode: decodeString
},
tuple: {
dynamic: false,
encode: encodeTuple,
decode: decodeTuple
}
};
export type ParserType = keyof typeof parsers;
decode({ type, value }: DecodeArgs): unknown[] {
const arrayType = getArrayType(type);
const arrayLength = Number(toNumber(value.subarray(0, 32)));
/**
* Get a parser for a type. Throws an error if the parser could not be found.
*
* @param {string} type
* @return {Parser}
*/
export const getParser = (type: string) => {
if (parsers[type as ParserType]) {
return parsers[type as ParserType];
return unpack(new Array(arrayLength).fill(arrayType), value.subarray(32));
}
// TODO: Figure out type issues
// bytes[n]
if (isFixedBytes(type)) {
return parsers.fixedBytes;
}
// u?int[n], bool
if (isNumber(type)) {
return parsers.number;
}
// type[]
if (isArray(type)) {
return parsers.array;
}
// (type)
if (isTuple(type)) {
return parsers.tuple;
}
throw new Error(`type "${type}" is not supported`);
};
export type UpdateFunction = (buffer: Uint8Array) => Uint8Array;
interface PackState {
staticBuffer: Uint8Array;
dynamicBuffer: Uint8Array;
updateFunctions: UpdateFunction[];
}
/**
* Pack multiple values into a single Buffer, based on the provided types. Returns a new buffer with the
* packed values.
*
* Based on the implementation of Ethers.js:
* https://github.com/ethers-io/ethers.js/blob/fa87417e9416d99a37d9a2668a1e54feb7e342fc/packages/abi/src.ts/coders/array.ts
*
* @param {Buffer} buffer
* @param {any[]} values
* @param {string[]} types
* @return {Buffer}
*/
export const pack = (buffer: Uint8Array, values: unknown[], types: string[]): Uint8Array => {
const {
staticBuffer: packedStaticBuffer,
dynamicBuffer: packedDynamicBuffer,
updateFunctions: packedUpdateFunctions
} = types.reduce<PackState>(
({ staticBuffer, dynamicBuffer, updateFunctions }, type, index) => {
const parser = getParser(type);
// TODO: Solve type issue
const value = values[index] as any;
if (parser.dynamic) {
const offset = dynamicBuffer.length;
const staticOffset = staticBuffer.length;
const newStaticBuffer = concat([staticBuffer, new Uint8Array(32).fill(0)]);
const newDynamicBuffer = parser.encode(dynamicBuffer, value, type);
const update = (oldBuffer: Uint8Array): Uint8Array => {
return concat([
oldBuffer.subarray(0, staticOffset),
toBuffer(oldBuffer.length + offset),
oldBuffer.subarray(staticOffset + 32)
]);
};
return {
staticBuffer: newStaticBuffer,
dynamicBuffer: newDynamicBuffer,
updateFunctions: [...updateFunctions, update]
};
}
const newBuffer = parser.encode(staticBuffer, value, type);
return { staticBuffer: newBuffer, dynamicBuffer, updateFunctions };
},
{ staticBuffer: new Uint8Array(0), dynamicBuffer: new Uint8Array(0), updateFunctions: [] }
);
const updatedStaticBuffer = packedUpdateFunctions.reduce<Uint8Array>(
(target, update) => update(target),
packedStaticBuffer
);
return concat([buffer, updatedStaticBuffer, packedDynamicBuffer]);
};
export const unpack = (buffer: Uint8Array, types: string[]): unknown[] => {
let pointer = 0;
return types.map((type) => {
if (pointer >= buffer.length) {
throw new Error('input data has an invalid length');
}
const parser = getParser(type);
if (isTuple(type)) {
const types = getTypes(type);
// TODO: Make this more generic
if (isDynamicTuple(types)) {
const value = buffer.subarray(pointer, pointer + 32);
const valuePointer = Number(toNumber(value));
const actualValue = buffer.subarray(valuePointer);
pointer += 32;
return parser.decode(actualValue, buffer, type);
}
const tupleLength = types.length * 32;
const value = buffer.subarray(pointer, pointer + tupleLength);
pointer += tupleLength;
return parser.decode(value, buffer, type);
}
const value = buffer.subarray(pointer, pointer + 32);
pointer += 32;
return parser.decode(value, buffer, type);
});
};

@@ -1,20 +0,21 @@

import { fromHex, fromUtf8, toHex, toUtf8 } from '../utils';
import { decodeBytes, encodeBytes } from './bytes';
import { fromHex, toHex } from '../utils';
import { bytes } from './bytes';
describe('encodeBytes', () => {
it('encodes a byte string to a buffer', () => {
const bytes = toHex(fromUtf8('Lorem ipsum dolor sit amet, consectetur adipiscing elit'));
expect(toHex(encodeBytes(new Uint8Array(0), bytes, 'bytes'))).toBe(
'00000000000000000000000000000000000000000000000000000000000000374c6f72656d20697073756d20646f6c6f722073697420616d65742c20636f6e73656374657475722061646970697363696e6720656c6974000000000000000000'
);
describe('bytes', () => {
describe('encode', () => {
it('encodes bytes', () => {
expect(toHex(bytes.encode({ type: 'bytes', value: 'ab', buffer: new Uint8Array() }))).toBe(
'0000000000000000000000000000000000000000000000000000000000000001ab00000000000000000000000000000000000000000000000000000000000000'
);
});
});
});
describe('decodeBytes', () => {
it('decodes a string from a buffer', () => {
const value = fromHex(
'000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000374c6f72656d20697073756d20646f6c6f722073697420616d65742c20636f6e73656374657475722061646970697363696e6720656c6974000000000000000000'
);
expect(toUtf8(decodeBytes(value, value, 'bytes'))).toBe('Lorem ipsum dolor sit amet, consectetur adipiscing elit');
describe('decode', () => {
it('decodes encoded bytes', () => {
const value = fromHex(
'0000000000000000000000000000000000000000000000000000000000000001ab00000000000000000000000000000000000000000000000000000000000000'
);
expect(toHex(bytes.decode({ type: 'bytes', value, skip: jest.fn() }))).toStrictEqual('ab');
});
});
});

@@ -1,16 +0,20 @@

import { BytesInput, DecodeFunction, EncodeFunction } from '../types';
import { BytesLike, DecodeArgs, Parser } from '../types';
import { addPadding, concat, toBuffer, toNumber } from '../utils';
export const encodeBytes: EncodeFunction<BytesInput> = (buffer: Uint8Array, value: BytesInput): Uint8Array => {
const bufferValue = toBuffer(value);
const paddedSize = Math.ceil(bufferValue.byteLength / 32) * 32;
export const bytes: Parser<BytesLike, Uint8Array> = {
isDynamic: true,
return concat([buffer, toBuffer(bufferValue.byteLength), addPadding(bufferValue, paddedSize)]);
};
encode({ buffer, value }): Uint8Array {
const bufferValue = toBuffer(value);
const paddedSize = Math.ceil(bufferValue.byteLength / 32) * 32;
export const decodeBytes: DecodeFunction<Uint8Array> = (value: Uint8Array, buffer: Uint8Array): Uint8Array => {
const pointer = Number(toNumber(value.subarray(0, 32)));
const length = Number(toNumber(buffer.subarray(pointer, pointer + 32)));
return concat([buffer, toBuffer(bufferValue.byteLength), addPadding(bufferValue, paddedSize)]);
},
return buffer.subarray(pointer + 32, pointer + 32 + Number(length));
decode({ value }: DecodeArgs): Uint8Array {
const buffer = value.slice(0, 32);
const length = Number(toNumber(buffer));
return value.subarray(32, 32 + length);
}
};
import { fromHex, toHex } from '../utils';
import { decodeFixedBytes, encodeFixedBytes } from './fixed-bytes';
import { fixedBytes, getByteLength } from './fixed-bytes';
describe('encodeFixedBytes', () => {
it('encodes a fixed byte array to a buffer', () => {
expect(toHex(encodeFixedBytes(new Uint8Array(0), '0xf00f00', 'bytes32'))).toBe(
'f00f000000000000000000000000000000000000000000000000000000000000'
);
describe('getByteLength', () => {
it('returns the byte length for a type', () => {
expect(getByteLength('bytes32')).toBe(32);
expect(getByteLength('bytes16')).toBe(16);
expect(getByteLength('bytes1')).toBe(1);
});
it('throws if the value is too long', () => {
expect(() => encodeFixedBytes(new Uint8Array(0), '0xf00f00', 'bytes1')).toThrow();
it('throws an error if the length is invalid', () => {
expect(() => getByteLength('bytes64')).toThrow();
expect(() => getByteLength('bytes0')).toThrow();
expect(() => getByteLength('bytes')).toThrow();
});
});
describe('decodeFixedBytes', () => {
it('decodes a fixed byte array from a buffer', () => {
const buffer = fromHex('f00f000000000000000000000000000000000000000000000000000000000000');
expect(toHex(decodeFixedBytes(buffer, new Uint8Array(0), 'bytes1'))).toBe('f0');
expect(toHex(decodeFixedBytes(buffer, new Uint8Array(0), 'bytes16'))).toBe('f00f0000000000000000000000000000');
expect(toHex(decodeFixedBytes(buffer, new Uint8Array(0), 'bytes32'))).toBe(
'f00f000000000000000000000000000000000000000000000000000000000000'
);
describe('fixed-bytes', () => {
describe('isType', () => {
it('checks if a type is a fixed bytes type', () => {
expect(fixedBytes.isType?.('bytes32')).toBe(true);
expect(fixedBytes.isType?.('bytes16')).toBe(true);
expect(fixedBytes.isType?.('bytes1')).toBe(true);
expect(fixedBytes.isType?.('bytes')).toBe(false);
expect(fixedBytes.isType?.('bytes32[]')).toBe(false);
expect(fixedBytes.isType?.('(bytes32)')).toBe(false);
});
});
describe('encode', () => {
it('encodes fixed bytes', () => {
expect(
toHex(
fixedBytes.encode({
type: 'bytes32',
value: 'abcdef1234567890000000000000000000000000000000000000000000000000',
buffer: new Uint8Array()
})
)
).toBe('abcdef1234567890000000000000000000000000000000000000000000000000');
});
it('throws if the length is invalid', () => {
expect(() =>
fixedBytes.encode({ type: 'bytes32', value: 'abcdef123456789', buffer: new Uint8Array() })
).toThrow();
});
});
describe('decode', () => {
it('decodes encoded fixed bytes', () => {
const value = fromHex('abcdef1234567890000000000000000000000000000000000000000000000000');
expect(toHex(fixedBytes.decode({ type: 'bytes32', value, skip: jest.fn() }))).toBe(
'abcdef1234567890000000000000000000000000000000000000000000000000'
);
});
});
});

@@ -1,2 +0,2 @@

import { BytesInput, DecodeFunction, EncodeFunction } from '../types';
import { BytesLike, DecodeArgs, Parser } from '../types';
import { addPadding, concat, toBuffer } from '../utils';

@@ -6,6 +6,2 @@

export const isFixedBytes = (type: string): boolean => {
return BYTES_REGEX.test(type);
};
/**

@@ -15,4 +11,4 @@ * Get the length of the specified type. If a length is not specified, or if the length is out of range (0 < n <= 32),

*
* @param {string} type
* @return {number | undefined}
* @param type The type to get the length for.
* @return The byte length of the type.
*/

@@ -34,25 +30,30 @@ export const getByteLength = (type: string): number => {

export const encodeFixedBytes: EncodeFunction<BytesInput> = (
buffer: Uint8Array,
value: BytesInput,
type: string
): Uint8Array => {
const length = getByteLength(type);
const bufferValue = toBuffer(value);
export const fixedBytes: Parser<BytesLike, Uint8Array> = {
isDynamic: false,
if (bufferValue.length > length) {
throw new Error(`Buffer is too long, expected ${length}, got ${bufferValue.length}`);
}
/**
* Check if a type is a fixed bytes type.
*
* @param type The type to check.
* @return Whether the type is a fixed bytes type.
*/
isType(type: string): boolean {
return BYTES_REGEX.test(type);
},
return concat([buffer, addPadding(bufferValue)]);
};
encode({ type, buffer, value }): Uint8Array {
const length = getByteLength(type);
const bufferValue = toBuffer(value);
export const decodeFixedBytes: DecodeFunction<Uint8Array> = (
value: Uint8Array,
_: Uint8Array,
type: string
): Uint8Array => {
const length = getByteLength(type);
if (bufferValue.length !== length) {
throw new Error(`Buffer has invalid length, expected ${length}, got ${bufferValue.length}`);
}
return value.subarray(0, length);
return concat([buffer, addPadding(bufferValue)]);
},
decode({ type, value }: DecodeArgs): Uint8Array {
const length = getByteLength(type);
return value.slice(0, length);
}
};
import { fromHex, toHex } from '../utils';
import { decodeFunction, encodeFunction } from './function';
import { fn, getFunction } from './function';
describe('encodeFunction', () => {
it('encodes a function', () => {
describe('getFunction', () => {
it('returns an encoded function for a function-like input', () => {
expect(
toHex(encodeFunction(new Uint8Array(0), 'ec3f4f80aa317fe2f345fb30ad0745746fd3a44855721d61', 'function'))
).toBe('ec3f4f80aa317fe2f345fb30ad0745746fd3a44855721d610000000000000000');
toHex(
getFunction({
address: '0x6b175474e89094c44da98b954eedeac495271d0f',
selector: '70a08231'
})
)
).toBe('6b175474e89094c44da98b954eedeac495271d0f70a08231');
expect(toHex(getFunction('6b175474e89094c44da98b954eedeac495271d0f70a08231'))).toBe(
'6b175474e89094c44da98b954eedeac495271d0f70a08231'
);
});
});
describe('decodeFunction', () => {
it('encodes a function', () => {
const buffer = fromHex('ec3f4f80aa317fe2f345fb30ad0745746fd3a44855721d610000000000000000');
expect(toHex(decodeFunction(buffer, buffer, 'function'))).toBe('ec3f4f80aa317fe2f345fb30ad0745746fd3a44855721d61');
describe('function', () => {
describe('encode', () => {
it('encodes a function', () => {
expect(
toHex(
fn.encode({
type: 'function',
value: '6b175474e89094c44da98b954eedeac495271d0f70a08231',
buffer: new Uint8Array()
})
)
).toBe('6b175474e89094c44da98b954eedeac495271d0f70a082310000000000000000');
expect(
toHex(
fn.encode({
type: 'function',
value: {
address: '0x6b175474e89094c44da98b954eedeac495271d0f',
selector: '70a08231'
},
buffer: new Uint8Array()
})
)
).toBe('6b175474e89094c44da98b954eedeac495271d0f70a082310000000000000000');
});
});
describe('decode', () => {
it('decodes an encoded function', () => {
const value = fromHex('6b175474e89094c44da98b954eedeac495271d0f70a082310000000000000000');
expect(fn.decode({ type: 'function', value, skip: jest.fn() })).toStrictEqual({
address: '0x6b175474e89094c44da98b954eedeac495271d0f',
selector: '70a08231'
});
});
});
});

@@ -1,24 +0,33 @@

import { DecodeFunction, EncodeFunction, BytesInput } from '../types';
import { decodeFixedBytes, encodeFixedBytes } from './fixed-bytes';
import { DecodeArgs, EncodeArgs, FunctionLike, Parser, SolidityFunction } from '../types';
import { concat, fromHex, toHex } from '../utils';
import { fixedBytes } from './fixed-bytes';
/**
* Encode a function type to a Buffer. This is equivalent to the `bytes24` type.
* Get the encoded function as buffer. It consists of the address (20 bytes) and function selector (4 bytes).
*
* @param {Uint8Array} buffer
* @param {string | Uint8Array} value
* @return {Uint8Array}
* @param input The function-like input.
* @return The function as buffer.
*/
export const encodeFunction: EncodeFunction<BytesInput> = (buffer: Uint8Array, value: BytesInput): Uint8Array => {
return encodeFixedBytes(buffer, value, 'bytes24');
export const getFunction = (input: FunctionLike): Uint8Array => {
if (typeof input === 'string') {
return fromHex(input);
}
return concat([fromHex(input.address), fromHex(input.selector)]);
};
/**
* Decode a function type from a Buffer. This is equivalent to the `bytes24` type.
*
* @param {Uint8Array} buffer
* @param {string | Uint8Array} value
* @return {Uint8Array}
*/
export const decodeFunction: DecodeFunction<Uint8Array> = (value: Uint8Array, buffer: Uint8Array): Uint8Array => {
return decodeFixedBytes(value, buffer, 'bytes24');
export const fn: Parser<FunctionLike, SolidityFunction> = {
isDynamic: false,
encode({ buffer, value }: EncodeArgs<FunctionLike>): Uint8Array {
const fn = getFunction(value);
return fixedBytes.encode({ type: 'bytes24', buffer, value: fn });
},
decode({ value }: DecodeArgs): SolidityFunction {
return {
address: `0x${toHex(value.slice(0, 20))}`,
selector: toHex(value.slice(20, 24))
};
}
};

@@ -1,40 +0,83 @@

import { toHex } from '../utils';
import { encodeNumber } from './number';
import { fromHex, toHex } from '../utils';
import { asNumber, isSigned, number } from './number';
describe('encodeNumber', () => {
it('encodes a number', () => {
expect(toHex(encodeNumber(new Uint8Array(0), 12345, 'uint256'))).toBe(
'0000000000000000000000000000000000000000000000000000000000003039'
);
expect(toHex(encodeNumber(new Uint8Array(0), 12345, 'int256'))).toBe(
'0000000000000000000000000000000000000000000000000000000000003039'
);
expect(toHex(encodeNumber(new Uint8Array(0), -12345, 'int256'))).toBe(
'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcfc7'
);
describe('isSigned', () => {
it('checks if a number type is signed', () => {
expect(isSigned('int')).toBe(true);
expect(isSigned('int256')).toBe(true);
expect(isSigned('int123')).toBe(true);
expect(isSigned('uint')).toBe(false);
expect(isSigned('uint256')).toBe(false);
expect(isSigned('uint123')).toBe(false);
});
});
it('encodes a bigint', () => {
expect(toHex(encodeNumber(new Uint8Array(0), 12345n, 'uint256'))).toBe(
'0000000000000000000000000000000000000000000000000000000000003039'
);
expect(toHex(encodeNumber(new Uint8Array(0), 12345n, 'int256'))).toBe(
'0000000000000000000000000000000000000000000000000000000000003039'
);
expect(toHex(encodeNumber(new Uint8Array(0), -12345n, 'int256'))).toBe(
'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcfc7'
);
describe('asNumber', () => {
it('returns a bigint for a number-like input', () => {
expect(asNumber(123)).toBe(123n);
expect(asNumber('123')).toBe(123n);
expect(asNumber('0x123')).toBe(291n);
});
});
it('encodes a string', () => {
expect(toHex(encodeNumber(new Uint8Array(0), '12345', 'uint256'))).toBe(
'0000000000000000000000000000000000000000000000000000000000003039'
);
expect(toHex(encodeNumber(new Uint8Array(0), '12345', 'int256'))).toBe(
'0000000000000000000000000000000000000000000000000000000000003039'
);
expect(toHex(encodeNumber(new Uint8Array(0), '-12345', 'int256'))).toBe(
'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcfc7'
);
describe('number', () => {
describe('isType', () => {
it('checks if a type is a number type', () => {
expect(number.isType?.('uint256')).toBe(true);
expect(number.isType?.('uint128')).toBe(true);
expect(number.isType?.('uint')).toBe(true);
expect(number.isType?.('int256')).toBe(true);
expect(number.isType?.('int128')).toBe(true);
expect(number.isType?.('int')).toBe(true);
expect(number.isType?.('string')).toBe(false);
expect(number.isType?.('(uint256)')).toBe(false);
expect(number.isType?.('uint256[]')).toBe(false);
});
});
describe('encode', () => {
it('encodes a unsigned number', () => {
expect(toHex(number.encode({ type: 'uint256', value: 314159n, buffer: new Uint8Array() }))).toBe(
'000000000000000000000000000000000000000000000000000000000004cb2f'
);
expect(toHex(number.encode({ type: 'uint256', value: 314159, buffer: new Uint8Array() }))).toBe(
'000000000000000000000000000000000000000000000000000000000004cb2f'
);
expect(toHex(number.encode({ type: 'uint256', value: '314159', buffer: new Uint8Array() }))).toBe(
'000000000000000000000000000000000000000000000000000000000004cb2f'
);
expect(toHex(number.encode({ type: 'uint256', value: '0x314159', buffer: new Uint8Array() }))).toBe(
'0000000000000000000000000000000000000000000000000000000000314159'
);
});
it('encodes a signed number', () => {
expect(toHex(number.encode({ type: 'int256', value: -314159n, buffer: new Uint8Array() }))).toBe(
'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb34d1'
);
expect(toHex(number.encode({ type: 'int256', value: -314159, buffer: new Uint8Array() }))).toBe(
'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb34d1'
);
expect(toHex(number.encode({ type: 'int256', value: '-314159', buffer: new Uint8Array() }))).toBe(
'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb34d1'
);
});
});
describe('decode', () => {
it('decodes an encoded unsigned number', () => {
const value = fromHex('000000000000000000000000000000000000000000000000000000000004cb2f');
expect(number.decode({ type: 'uint256', value, skip: jest.fn() })).toBe(314159n);
});
it('decodes an encoded signed number', () => {
const value = fromHex('000000000000000000000000000000000000000000000000000000000004cb2f');
expect(number.decode({ type: 'int256', value, skip: jest.fn() })).toBe(314159n);
const negativeValue = fromHex('fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb34d1');
expect(number.decode({ type: 'int256', value: negativeValue, skip: jest.fn() })).toBe(-314159n);
});
});
});

@@ -1,32 +0,23 @@

import { NumberInput, DecodeFunction, EncodeFunction } from '../types';
import { concat, toBuffer, toNumber, fromTwosComplement, toTwosComplement } from '../utils';
import { DecodeArgs, NumberLike, Parser } from '../types';
import { concat, fromTwosComplement, toBuffer, toNumber, toTwosComplement } from '../utils';
const NUMBER_REGEX = /^u?int([0-9]*)?$/;
const isSigned = (type: string): boolean => {
return type.startsWith('i');
/**
* Check if a number type is signed.
*
* @param type The type to check.
* @return Whether the type is signed.
*/
export const isSigned = (type: string): boolean => {
return !type.startsWith('u');
};
export const isNumber = (type: string): boolean => {
return NUMBER_REGEX.test(type);
};
export const getBitLength = (type: string): number => {
const rawBits = type.match(NUMBER_REGEX)?.[1] ?? '256';
return Number(rawBits);
};
export const inRange = (value: bigint, type: string): boolean => {
const bits = BigInt(getBitLength(type));
if (isSigned(type)) {
const maxSignedValue = 2n ** (bits - 1n) - 1n;
return value >= -maxSignedValue - 1n && value <= maxSignedValue;
}
const maxValue = 2n ** bits - 1n;
return value >= 0n && value <= maxValue;
};
const asNumber = (value: NumberInput): bigint => {
/**
* Get a number-like value as bigint.
*
* @param value The number-like value to parse.
* @return The value parsed as bigint.
*/
export const asNumber = (value: NumberLike): bigint => {
if (typeof value === 'bigint') {

@@ -39,26 +30,32 @@ return value;

export const encodeNumber: EncodeFunction<NumberInput> = (
buffer: Uint8Array,
value: NumberInput,
type: string
): Uint8Array => {
const numberValue = asNumber(value);
export const number: Parser<NumberLike, bigint> = {
isDynamic: false,
if (!inRange(numberValue, type)) {
throw new Error(`Cannot encode number: value is out of range for type ${type}`);
}
/**
* Check if a type is a number type.
*
* @return Whether the type is a number type.
*/
isType(type: string): boolean {
return NUMBER_REGEX.test(type);
},
if (isSigned(type)) {
return concat([buffer, toTwosComplement(numberValue, 32)]);
}
encode({ type, buffer, value }): Uint8Array {
const number = asNumber(value);
return concat([buffer, toBuffer(numberValue)]);
};
if (isSigned(type)) {
return concat([buffer, toTwosComplement(number, 32)]);
}
export const decodeNumber: DecodeFunction<bigint> = (value: Uint8Array, _, type: string): bigint => {
if (isSigned(type)) {
return fromTwosComplement(value);
return concat([buffer, toBuffer(number)]);
},
decode({ type, value }: DecodeArgs): bigint {
const buffer = value.slice(0, 32);
if (isSigned(type)) {
return fromTwosComplement(buffer);
}
return toNumber(buffer);
}
return toNumber(value);
};

@@ -1,12 +0,21 @@

import { toHex } from '../utils';
import { encodeString } from './string';
import { fromHex, toHex } from '../utils';
import { string } from './string';
describe('encodeString', () => {
it('encodes a string to a buffer', () => {
expect(
toHex(encodeString(new Uint8Array(0), 'Lorem ipsum dolor sit amet, consectetur adipiscing elit', 'bytes'))
).toBe(
'00000000000000000000000000000000000000000000000000000000000000374c6f72656d20697073756d20646f6c6f722073697420616d65742c20636f6e73656374657475722061646970697363696e6720656c6974000000000000000000'
);
describe('string', () => {
describe('encode', () => {
it('encodes a string', () => {
expect(toHex(string.encode({ type: 'string', value: 'foo bar baz qux', buffer: new Uint8Array() }))).toBe(
'000000000000000000000000000000000000000000000000000000000000000f666f6f206261722062617a207175780000000000000000000000000000000000'
);
});
});
describe('decode', () => {
it('decodes an encoded string', () => {
const value = fromHex(
'000000000000000000000000000000000000000000000000000000000000000f666f6f206261722062617a207175780000000000000000000000000000000000'
);
expect(string.decode({ type: 'string', value, skip: jest.fn() })).toBe('foo bar baz qux');
});
});
});

@@ -1,12 +0,15 @@

import { DecodeFunction, EncodeFunction } from '../types';
import { DecodeArgs, Parser } from '../types';
import { fromUtf8, toUtf8 } from '../utils';
import { decodeBytes, encodeBytes } from './bytes';
import { bytes } from './bytes';
export const encodeString: EncodeFunction<string> = (buffer: Uint8Array, value: string): Uint8Array => {
const bufferValue = fromUtf8(value);
return encodeBytes(buffer, bufferValue, 'bytes');
};
export const string: Parser<string> = {
isDynamic: true,
export const decodeString: DecodeFunction<string> = (value: Uint8Array, buffer: Uint8Array): string => {
return toUtf8(decodeBytes(value, buffer, 'string'));
encode({ buffer, value }): Uint8Array {
return bytes.encode({ type: 'bytes', buffer, value: fromUtf8(value) });
},
decode(args: DecodeArgs): string {
return toUtf8(bytes.decode(args));
}
};

@@ -0,27 +1,78 @@

import { DynamicFunction } from '../types';
import { fromHex, toHex } from '../utils';
import { decodeTuple, encodeTuple, getTypes } from './tuple';
import { getTupleElements, tuple } from './tuple';
describe('getTypes', () => {
it('returns the type of a tuple', () => {
expect(getTypes('(foo, bar)')).toStrictEqual(['foo', 'bar']);
expect(getTypes('(foo,bar)')).toStrictEqual(['foo', 'bar']);
describe('getTupleElements', () => {
it('returns the elements of a tuple', () => {
expect(getTupleElements('(foo,bar)')).toStrictEqual(['foo', 'bar']);
expect(getTupleElements('(foo,bar[])')).toStrictEqual(['foo', 'bar[]']);
// TODO: Add support for nested tuples
// expect(getTupleElements('(foo,(bar,baz))')).toStrictEqual(['foo', '(bar,baz))']);
});
});
describe('encodeTuple', () => {
it('encodes a tuple', () => {
expect(toHex(encodeTuple(new Uint8Array(0), ['foo', 'bar'], '(string, string)'))).toBe(
'000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000003666f6f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000036261720000000000000000000000000000000000000000000000000000000000'
);
describe('tuple', () => {
describe('isDynamic', () => {
const isDynamic = tuple.isDynamic as DynamicFunction;
it('checks if one or more elements of the tuple are dynamic', () => {
expect(isDynamic('(uint256, bytes)')).toBe(true);
expect(isDynamic('(uint256, uint256)')).toBe(false);
});
});
});
describe('decodeTuple', () => {
it('decodes a tuple', () => {
const value = fromHex(
'000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000003666f6f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000036261720000000000000000000000000000000000000000000000000000000000'
);
describe('isType', () => {
it('checks if a type is a tuple type', () => {
expect(tuple.isType?.('(uint256)')).toBe(true);
expect(tuple.isType?.('(uint256, uint256)')).toBe(true);
expect(decodeTuple(value, value, '(string, string)')).toStrictEqual(['foo', 'bar']);
expect(tuple.isType?.('uint256')).toBe(false);
expect(tuple.isType?.('(uint256)[]')).toBe(false);
});
});
describe('encode', () => {
it('encodes a static tuple', () => {
expect(toHex(tuple.encode({ type: '(uint256, uint256)', value: [12n, 34n], buffer: new Uint8Array() }))).toBe(
'000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000022'
);
});
it('encodes a dynamic tuple', () => {
expect(toHex(tuple.encode({ type: '(uint256, bytes)', value: [12n, 'ab'], buffer: new Uint8Array() }))).toBe(
'000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000001ab00000000000000000000000000000000000000000000000000000000000000'
);
});
});
describe('decode', () => {
it('decodes an encoded static tuple', () => {
const value = fromHex(
'000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000022'
);
expect(tuple.decode({ type: '(uint256, uint256)', value, skip: jest.fn() })).toStrictEqual([12n, 34n]);
});
it('decodes an encoded dynamic tuple', () => {
const value = fromHex(
'000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000001ab00000000000000000000000000000000000000000000000000000000000000'
);
const result = tuple.decode({ type: '(uint256, bytes)', value, skip: jest.fn() });
expect(result[0]).toBe(12n);
expect(toHex(result[1] as Uint8Array)).toBe('ab');
});
it('calls skip with the tuple length', () => {
const value = fromHex(
'000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000022'
);
const skip = jest.fn();
tuple.decode({ type: '(uint256,uint256)', value, skip });
expect(skip).toHaveBeenCalledWith(32);
});
});
});

@@ -1,3 +0,3 @@

import { DecodeFunction, EncodeFunction } from '../types';
import { getParser, pack, unpack } from './array';
import { getParser, isDynamicParser, pack, unpack } from '../packer';
import { DecodeArgs, Parser } from '../types';

@@ -7,12 +7,8 @@ const TUPLE_REGEX = /^\((.*)\)$/;

/**
* Check if a type is an tuple type.
* Get elements from a tuple type.
*
* @param {string} type
* @return {boolean}
* @param type The tuple type to get the types for.
* @return The elements of the tuple as string array.
*/
export const isTuple = (type: string): boolean => {
return TUPLE_REGEX.test(type);
};
export const getTypes = (type: string): string[] => {
export const getTupleElements = (type: string): string[] => {
return type

@@ -24,26 +20,42 @@ .slice(1, -1)

export const isDynamicTuple = (types: string[]): boolean => {
return types.map(getParser).some((parser) => parser.dynamic);
};
export const tuple: Parser<unknown[]> = {
/**
* Check if the tuple is dynamic. Tuples are dynamic if one or more elements of the tuple are dynamic.
*
* @param type The type to check.
* @return Whether the tuple is dynamic.
*/
isDynamic(type: string): boolean {
const elements = getTupleElements(type);
return elements.some((element) => {
const parser = getParser(element);
return isDynamicParser(parser, element);
});
},
export const encodeTuple: EncodeFunction<unknown[]> = (
buffer: Uint8Array,
values: unknown[],
type: string
): Uint8Array => {
if (!isTuple(type)) {
throw new Error('Invalid type: type is not tuple');
}
/**
* Check if a type is an tuple type.
*
* @param type The type to check.
* @return Whether the type is a tuple type.
*/
isType(type: string): boolean {
return TUPLE_REGEX.test(type);
},
const types = getTypes(type);
return pack(buffer, values, types);
};
encode({ type, buffer, value }): Uint8Array {
const elements = getTupleElements(type);
return pack(elements, value, buffer);
},
export const decodeTuple: DecodeFunction<unknown[]> = (value: Uint8Array, _: Uint8Array, type: string): unknown[] => {
if (!isTuple(type)) {
throw new Error('Invalid type: type is not tuple');
decode({ type, value, skip }: DecodeArgs): unknown[] {
const elements = getTupleElements(type);
const length = elements.length * 32 - 32;
if (!isDynamicParser(this, type)) {
skip(length);
}
return unpack(elements, value);
}
const types = getTypes(type);
return unpack(value, types);
};

@@ -1,3 +0,9 @@

export type BytesInput = string | Uint8Array | number[];
export type NumberInput = bigint | number | string;
export type BooleanInput = boolean | string;
export type BytesLike = string | Uint8Array;
export type BooleanLike = 'true' | 'false' | 'yes' | 'no' | boolean;
export type NumberLike = number | bigint | string;
export type FunctionLike = string | SolidityFunction;
export interface SolidityFunction {
address: string;
selector: string;
}

@@ -1,8 +0,3 @@

import type { decodeAddress, encodeAddress } from '../parsers/address';
import type { decodeBoolean, encodeBoolean } from '../parsers/boolean';
import type { decodeBytes, encodeBytes } from '../parsers/bytes';
import type { decodeFunction, encodeFunction } from '../parsers/function';
import type { decodeNumber, encodeNumber } from '../parsers/number';
import type { decodeString, encodeString } from '../parsers/string';
import type { DecodeFunction, EncodeFunction } from './parser';
import { address, bool, bytes, fn, number, string } from '../parsers';
import { Parser } from './parser';

@@ -25,12 +20,3 @@ // prettier-ignore

*/
export type OutputTypeMap = WithArrayTypes<
GenericTypeMap<
typeof decodeAddress,
typeof decodeBoolean,
typeof decodeBytes,
typeof decodeFunction,
typeof decodeNumber,
typeof decodeString
>
>;
export type OutputTypeMap = WithArrayTypes<MapToOutput<TypeMap>>;

@@ -43,12 +29,3 @@ /**

*/
export type InputTypeMap = WithArrayTypes<
GenericTypeMap<
typeof encodeAddress,
typeof encodeBoolean,
typeof encodeBytes,
typeof encodeFunction,
typeof encodeNumber,
typeof encodeString
>
>;
export type InputTypeMap = WithArrayTypes<MapToInput<TypeMap>>;

@@ -58,20 +35,13 @@ /**

*/
type GenericTypeMap<
AddressFunction,
BooleanFunction,
BytesFunction,
FunctionFunction,
NumberFunction,
StringFunction
> = {
address: ExtractGeneric<AddressFunction>;
bool: ExtractGeneric<BooleanFunction>;
bytes: ExtractGeneric<BytesFunction>;
function: ExtractGeneric<FunctionFunction>;
int: ExtractGeneric<NumberFunction>;
string: ExtractGeneric<StringFunction>;
uint: ExtractGeneric<NumberFunction>;
} & DynamicType<Bytes, ExtractGeneric<BytesFunction>> &
DynamicType<Integer, ExtractGeneric<NumberFunction>> &
DynamicType<UnsignedInteger, ExtractGeneric<NumberFunction>>;
type TypeMap = {
address: ExtractGeneric<typeof address>;
bool: ExtractGeneric<typeof bool>;
bytes: ExtractGeneric<typeof bytes>;
function: ExtractGeneric<typeof fn>;
int: ExtractGeneric<typeof number>;
string: ExtractGeneric<typeof string>;
uint: ExtractGeneric<typeof number>;
} & DynamicType<Bytes, ExtractGeneric<typeof bytes>> &
DynamicType<Integer, ExtractGeneric<typeof number>> &
DynamicType<UnsignedInteger, ExtractGeneric<typeof number>>;

@@ -93,2 +63,16 @@ /**

/**
* Helper type that maps a tuple to the first element.
*/
export type MapToInput<T extends Record<string, [unknown, unknown]>> = {
[K in keyof T]: T[K][0];
};
/**
* Helper type that maps a tuple to the second element.
*/
export type MapToOutput<T extends Record<string, [unknown, unknown]>> = {
[K in keyof T]: T[K][1];
};
/**
* Helper type that adds an array type for each of the specified keys and types.

@@ -102,4 +86,4 @@ */

/**
* Helper type that extracts the input or output from an EncodeFunction or DecodeFunction.
* Helper type that extracts the input or output from a Parser;.
*/
type ExtractGeneric<T> = T extends DecodeFunction<infer O> ? O : T extends EncodeFunction<infer I> ? I : never;
type ExtractGeneric<T> = T extends Parser<infer I, infer O> ? [I, O] : never;

@@ -1,2 +0,45 @@

export type EncodeFunction<T> = (buffer: Uint8Array, value: T, type: string) => Uint8Array;
export type DecodeFunction<T> = (value: Uint8Array, buffer: Uint8Array, type: string) => T;
export type DynamicFunction = (type: string) => boolean;
export interface EncodeArgs<Value> {
/**
* The buffer to encode the value in.
*/
buffer: Uint8Array;
/**
* The type of the value to encode.
*/
type: string;
/**
* The value to encode.
*/
value: Value;
}
export interface DecodeArgs {
/**
* The type of the value to decode.
*/
type: string;
/**
* The value to decode.
*/
value: Uint8Array;
/**
* A function to skip a certain number of bytes for parsing. This is currently only used by static tuple types.
*
* @param length The number of bytes to skip.
*/
skip(length: number): void;
}
export interface Parser<EncodeValue = unknown, DecodeValue = EncodeValue> {
isDynamic: boolean | DynamicFunction;
isType?(type: string): boolean;
encode(value: EncodeArgs<EncodeValue>): Uint8Array;
decode(args: DecodeArgs): DecodeValue;
}

@@ -16,4 +16,2 @@ const BUFFER_WIDTH = 32;

* Returns an instance of `TextEncoder` that works with both Node.js and web browsers.
*
* @return {TextEncoder}
*/

@@ -32,4 +30,2 @@ export const getTextEncoder = (): TextEncoder => {

* Returns an instance of `TextDecoder` that works with both Node.js and web browsers.
*
* @return {TextDecoder}
*/

@@ -49,4 +45,4 @@ export const getTextDecoder = (encoding = 'utf8'): TextDecoder => {

*
* @param {Uint8Array} data
* @return {string}
* @param data The buffer to convert to UTF-8.
* @return The buffer as UTF-8 encoded string.
*/

@@ -60,4 +56,4 @@ export const toUtf8 = (data: Uint8Array): string => {

*
* @param {string} data
* @return {Uint8Array}
* @param data The string to convert to a buffer.
* @return The buffer.
*/

@@ -69,6 +65,6 @@ export const fromUtf8 = (data: string): Uint8Array => {

/**
* Get a Uint8Array as hexadecimal string
* Get a Uint8Array as hexadecimal string.
*
* @param {Uint8Array} data
* @return {string}
* @param data The buffer to convert to a hexadecimal string.
* @return The buffer as hexadecimal string.
*/

@@ -84,4 +80,4 @@ export const toHex = (data: Uint8Array): string => {

*
* @param {string} data
* @return {Uint8Array}
* @param data The hexadecimal string to convert to a buffer.
* @return The buffer.
*/

@@ -105,6 +101,6 @@ export const fromHex = (data: string): Uint8Array => {

/**
* Attempt to parse a value as Uint8Array.
* Attempt to parse a value as Uint8Array. If `data` is a number, this will pad the buffer to 32 bytes.
*
* @param {BinaryLike} data
* @return {Uint8Array}
* @param data The value to parse as Uint8Array.
* @return The resulting Uint8Array.
*/

@@ -125,6 +121,6 @@ export const toBuffer = (data: BinaryLike): Uint8Array => {

/**
* Safe function to merge multiple Uint8Arrays into a single Uint8array.
* Safe function to merge multiple Uint8Arrays into a single Uint8array. This works with buffers of any size.
*
* @param {Uint8Array[]} buffers
* @return {Uint8Array}
* @param buffers The buffers to combine.
* @return The combined buffers.
*/

@@ -145,5 +141,5 @@ export const concat = (buffers: Uint8Array[]): Uint8Array => {

*
* @param {Uint8Array} buffer
* @param {number} [length]
* @return {Uint8Array}
* @param buffer The buffer to add padding to.
* @param [length] The number of bytes to pad the buffer to.
* @return The padded buffer.
*/

@@ -156,5 +152,6 @@ export const addPadding = (buffer: Uint8Array, length = BUFFER_WIDTH): Uint8Array => {

/**
* Get a number from a buffer.
* Get a number from a buffer. Returns zero if the buffer is empty.
*
* @param {Uint8Array} buffer
* @param buffer The buffer to get a number for.
* @return The parsed number.
*/

@@ -161,0 +158,0 @@ export const toNumber = (buffer: Uint8Array): bigint => {

import { toBuffer } from './buffer';
/**
* Get a bigint from a two's complement encoded buffer or hexadecimal string.
*
* @param buffer The buffer to get the number for.
* @return The parsed number.
*/
export const fromTwosComplement = (buffer: string | Uint8Array): bigint => {

@@ -14,2 +20,9 @@ const bufferValue = toBuffer(buffer);

/**
* Get a two's complement encoded buffer from a bigint.
*
* @param value The number to get the buffer for.
* @param length The number of bytes to pad the buffer to.
* @return The two's complement encoded buffer.
*/
export const toTwosComplement = (value: bigint, length: number): Uint8Array => {

@@ -16,0 +29,0 @@ const buffer = new Uint8Array(length);

@@ -1,9 +0,17 @@

import { TypeMapper, Narrow, InputTypeMap } from './types';
import { InputTypeMap, Narrow, TypeMapper } from './types';
/**
* Encode the data with the provided types.
*
* @param types The types to encode.
* @param values The values to encode. This array must have the same length as the types array.
* @return The ABI encoded buffer.
*/
export declare const encode: <T extends string[]>(types: import("./types").Try<T, [], (T extends [] ? [] : never) | (T extends import("./types").Narrowable ? T : never) | { [K in keyof T]: T[K] extends Function ? T[K] : (T[K] extends [] ? [] : never) | (T[K] extends import("./types").Narrowable ? T[K] : never) | { [K_1 in keyof T[K]]: T[K][K_1] extends Function ? T[K][K_1] : (T[K][K_1] extends [] ? [] : never) | (T[K][K_1] extends import("./types").Narrowable ? T[K][K_1] : never) | { [K_2 in keyof T[K][K_1]]: T[K][K_1][K_2] extends Function ? T[K][K_1][K_2] : (T[K][K_1][K_2] extends [] ? [] : never) | (T[K][K_1][K_2] extends import("./types").Narrowable ? T[K][K_1][K_2] : never) | { [K_3 in keyof T[K][K_1][K_2]]: T[K][K_1][K_2][K_3] extends Function ? T[K][K_1][K_2][K_3] : (T[K][K_1][K_2][K_3] extends [] ? [] : never) | (T[K][K_1][K_2][K_3] extends import("./types").Narrowable ? T[K][K_1][K_2][K_3] : never) | { [K_4 in keyof T[K][K_1][K_2][K_3]]: T[K][K_1][K_2][K_3][K_4] extends Function ? T[K][K_1][K_2][K_3][K_4] : (T[K][K_1][K_2][K_3][K_4] extends [] ? [] : never) | (T[K][K_1][K_2][K_3][K_4] extends import("./types").Narrowable ? T[K][K_1][K_2][K_3][K_4] : never) | { [K_5 in keyof T[K][K_1][K_2][K_3][K_4]]: T[K][K_1][K_2][K_3][K_4][K_5] extends Function ? T[K][K_1][K_2][K_3][K_4][K_5] : (T[K][K_1][K_2][K_3][K_4][K_5] extends [] ? [] : never) | (T[K][K_1][K_2][K_3][K_4][K_5] extends import("./types").Narrowable ? T[K][K_1][K_2][K_3][K_4][K_5] : never) | { [K_6 in keyof T[K][K_1][K_2][K_3][K_4][K_5]]: T[K][K_1][K_2][K_3][K_4][K_5][K_6] extends Function ? T[K][K_1][K_2][K_3][K_4][K_5][K_6] : (T[K][K_1][K_2][K_3][K_4][K_5][K_6] extends [] ? [] : never) | (T[K][K_1][K_2][K_3][K_4][K_5][K_6] extends import("./types").Narrowable ? T[K][K_1][K_2][K_3][K_4][K_5][K_6] : never) | { [K_7 in keyof T[K][K_1][K_2][K_3][K_4][K_5][K_6]]: T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7] extends Function ? T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7] : (T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7] extends [] ? [] : never) | (T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7] extends import("./types").Narrowable ? T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7] : never) | { [K_8 in keyof T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7]]: T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8] extends Function ? T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8] : (T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8] extends [] ? [] : never) | (T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8] extends import("./types").Narrowable ? T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8] : never) | { [K_9 in keyof T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8]]: T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8][K_9] extends Function ? T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8][K_9] : (T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8][K_9] extends [] ? [] : never) | (T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8][K_9] extends import("./types").Narrowable ? T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8][K_9] : never) | { [K_10 in keyof T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8][K_9]]: T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8][K_9][K_10] extends Function ? T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8][K_9][K_10] : (T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8][K_9][K_10] extends [] ? [] : never) | (T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8][K_9][K_10] extends import("./types").Narrowable ? T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8][K_9][K_10] : never) | any; }; }; }; }; }; }; }; }; }; }; }>, values: { [K_11 in keyof T]: T[K_11] extends T[number] ? InputTypeMap[T[K_11]] : unknown; }) => Uint8Array;
/**
* Decode the data with the provided types.
* Decode an ABI encoded buffer with the specified types.
*
* @param types The types to decode the buffer with.
* @param buffer The buffer to decode.
* @return The decoded values as array.
*/
export declare const decode: <T extends string[]>(types: import("./types").Try<T, [], (T extends [] ? [] : never) | (T extends import("./types").Narrowable ? T : never) | { [K in keyof T]: T[K] extends Function ? T[K] : (T[K] extends [] ? [] : never) | (T[K] extends import("./types").Narrowable ? T[K] : never) | { [K_1 in keyof T[K]]: T[K][K_1] extends Function ? T[K][K_1] : (T[K][K_1] extends [] ? [] : never) | (T[K][K_1] extends import("./types").Narrowable ? T[K][K_1] : never) | { [K_2 in keyof T[K][K_1]]: T[K][K_1][K_2] extends Function ? T[K][K_1][K_2] : (T[K][K_1][K_2] extends [] ? [] : never) | (T[K][K_1][K_2] extends import("./types").Narrowable ? T[K][K_1][K_2] : never) | { [K_3 in keyof T[K][K_1][K_2]]: T[K][K_1][K_2][K_3] extends Function ? T[K][K_1][K_2][K_3] : (T[K][K_1][K_2][K_3] extends [] ? [] : never) | (T[K][K_1][K_2][K_3] extends import("./types").Narrowable ? T[K][K_1][K_2][K_3] : never) | { [K_4 in keyof T[K][K_1][K_2][K_3]]: T[K][K_1][K_2][K_3][K_4] extends Function ? T[K][K_1][K_2][K_3][K_4] : (T[K][K_1][K_2][K_3][K_4] extends [] ? [] : never) | (T[K][K_1][K_2][K_3][K_4] extends import("./types").Narrowable ? T[K][K_1][K_2][K_3][K_4] : never) | { [K_5 in keyof T[K][K_1][K_2][K_3][K_4]]: T[K][K_1][K_2][K_3][K_4][K_5] extends Function ? T[K][K_1][K_2][K_3][K_4][K_5] : (T[K][K_1][K_2][K_3][K_4][K_5] extends [] ? [] : never) | (T[K][K_1][K_2][K_3][K_4][K_5] extends import("./types").Narrowable ? T[K][K_1][K_2][K_3][K_4][K_5] : never) | { [K_6 in keyof T[K][K_1][K_2][K_3][K_4][K_5]]: T[K][K_1][K_2][K_3][K_4][K_5][K_6] extends Function ? T[K][K_1][K_2][K_3][K_4][K_5][K_6] : (T[K][K_1][K_2][K_3][K_4][K_5][K_6] extends [] ? [] : never) | (T[K][K_1][K_2][K_3][K_4][K_5][K_6] extends import("./types").Narrowable ? T[K][K_1][K_2][K_3][K_4][K_5][K_6] : never) | { [K_7 in keyof T[K][K_1][K_2][K_3][K_4][K_5][K_6]]: T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7] extends Function ? T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7] : (T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7] extends [] ? [] : never) | (T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7] extends import("./types").Narrowable ? T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7] : never) | { [K_8 in keyof T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7]]: T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8] extends Function ? T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8] : (T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8] extends [] ? [] : never) | (T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8] extends import("./types").Narrowable ? T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8] : never) | { [K_9 in keyof T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8]]: T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8][K_9] extends Function ? T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8][K_9] : (T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8][K_9] extends [] ? [] : never) | (T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8][K_9] extends import("./types").Narrowable ? T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8][K_9] : never) | { [K_10 in keyof T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8][K_9]]: T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8][K_9][K_10] extends Function ? T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8][K_9][K_10] : (T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8][K_9][K_10] extends [] ? [] : never) | (T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8][K_9][K_10] extends import("./types").Narrowable ? T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8][K_9][K_10] : never) | any; }; }; }; }; }; }; }; }; }; }; }>, buffer: Uint8Array) => { [K_11 in keyof T]: T[K_11] extends T[number] ? import("./types").OutputTypeMap[T[K_11]] : unknown; };

@@ -1,3 +0,2 @@

import { DecodeFunction, EncodeFunction } from '../types';
export declare const encodeAddress: EncodeFunction<string>;
export declare const decodeAddress: DecodeFunction<string>;
import { Parser } from '../types';
export declare const address: Parser<string>;

@@ -1,106 +0,9 @@

import { DecodeFunction, EncodeFunction } from '../types';
import { Parser } from '../types';
/**
* Check if a type is an array type.
* Get the type of the array.
*
* @param {string} type
* @return {boolean}
* @param type The type to get the array type for.
* @return The array type.
*/
export declare const isArray: (type: string) => boolean;
/**
* Get the "inner" type for an array type. E.g. `getType("uint256[]")` -> ["uint256"].
*
* @param {string} type
* @return {string}
*/
export declare const getType: (type: string) => string;
export declare const encodeArray: EncodeFunction<unknown[]>;
export declare const decodeArray: DecodeFunction<unknown[]>;
/**
* All available parsers.
*/
declare const parsers: {
address: {
dynamic: boolean;
encode: EncodeFunction<string>;
decode: DecodeFunction<string>;
};
array: {
dynamic: boolean;
encode: EncodeFunction<unknown[]>;
decode: DecodeFunction<unknown[]>;
};
bool: {
dynamic: boolean;
encode: EncodeFunction<import("../types").BooleanInput>;
decode: DecodeFunction<boolean>;
};
bytes: {
dynamic: boolean;
encode: EncodeFunction<import("../types").BytesInput>;
decode: DecodeFunction<Uint8Array>;
};
fixedBytes: {
dynamic: boolean;
encode: EncodeFunction<import("../types").BytesInput>;
decode: DecodeFunction<Uint8Array>;
};
number: {
dynamic: boolean;
encode: EncodeFunction<import("../types").NumberInput>;
decode: DecodeFunction<bigint>;
};
string: {
dynamic: boolean;
encode: EncodeFunction<string>;
decode: DecodeFunction<string>;
};
tuple: {
dynamic: boolean;
encode: EncodeFunction<unknown[]>;
decode: DecodeFunction<unknown[]>;
};
};
export declare type ParserType = keyof typeof parsers;
/**
* Get a parser for a type. Throws an error if the parser could not be found.
*
* @param {string} type
* @return {Parser}
*/
export declare const getParser: (type: string) => {
dynamic: boolean;
encode: EncodeFunction<string>;
decode: DecodeFunction<string>;
} | {
dynamic: boolean;
encode: EncodeFunction<unknown[]>;
decode: DecodeFunction<unknown[]>;
} | {
dynamic: boolean;
encode: EncodeFunction<import("../types").BooleanInput>;
decode: DecodeFunction<boolean>;
} | {
dynamic: boolean;
encode: EncodeFunction<import("../types").BytesInput>;
decode: DecodeFunction<Uint8Array>;
} | {
dynamic: boolean;
encode: EncodeFunction<import("../types").NumberInput>;
decode: DecodeFunction<bigint>;
};
export declare type UpdateFunction = (buffer: Uint8Array) => Uint8Array;
/**
* Pack multiple values into a single Buffer, based on the provided types. Returns a new buffer with the
* packed values.
*
* Based on the implementation of Ethers.js:
* https://github.com/ethers-io/ethers.js/blob/fa87417e9416d99a37d9a2668a1e54feb7e342fc/packages/abi/src.ts/coders/array.ts
*
* @param {Buffer} buffer
* @param {any[]} values
* @param {string[]} types
* @return {Buffer}
*/
export declare const pack: (buffer: Uint8Array, values: unknown[], types: string[]) => Uint8Array;
export declare const unpack: (buffer: Uint8Array, types: string[]) => unknown[];
export {};
export declare const getArrayType: (type: string) => string;
export declare const array: Parser<unknown[]>;

@@ -1,3 +0,2 @@

import { BytesInput, DecodeFunction, EncodeFunction } from '../types';
export declare const encodeBytes: EncodeFunction<BytesInput>;
export declare const decodeBytes: DecodeFunction<Uint8Array>;
import { BytesLike, Parser } from '../types';
export declare const bytes: Parser<BytesLike, Uint8Array>;

@@ -1,3 +0,2 @@

import { BytesInput, DecodeFunction, EncodeFunction } from '../types';
export declare const isFixedBytes: (type: string) => boolean;
import { BytesLike, Parser } from '../types';
/**

@@ -7,7 +6,6 @@ * Get the length of the specified type. If a length is not specified, or if the length is out of range (0 < n <= 32),

*
* @param {string} type
* @return {number | undefined}
* @param type The type to get the length for.
* @return The byte length of the type.
*/
export declare const getByteLength: (type: string) => number;
export declare const encodeFixedBytes: EncodeFunction<BytesInput>;
export declare const decodeFixedBytes: DecodeFunction<Uint8Array>;
export declare const fixedBytes: Parser<BytesLike, Uint8Array>;

@@ -1,17 +0,9 @@

import { DecodeFunction, EncodeFunction, BytesInput } from '../types';
import { FunctionLike, Parser, SolidityFunction } from '../types';
/**
* Encode a function type to a Buffer. This is equivalent to the `bytes24` type.
* Get the encoded function as buffer. It consists of the address (20 bytes) and function selector (4 bytes).
*
* @param {Uint8Array} buffer
* @param {string | Uint8Array} value
* @return {Uint8Array}
* @param input The function-like input.
* @return The function as buffer.
*/
export declare const encodeFunction: EncodeFunction<BytesInput>;
/**
* Decode a function type from a Buffer. This is equivalent to the `bytes24` type.
*
* @param {Uint8Array} buffer
* @param {string | Uint8Array} value
* @return {Uint8Array}
*/
export declare const decodeFunction: DecodeFunction<Uint8Array>;
export declare const getFunction: (input: FunctionLike) => Uint8Array;
export declare const fn: Parser<FunctionLike, SolidityFunction>;

@@ -1,6 +0,16 @@

import { NumberInput, DecodeFunction, EncodeFunction } from '../types';
export declare const isNumber: (type: string) => boolean;
export declare const getBitLength: (type: string) => number;
export declare const inRange: (value: bigint, type: string) => boolean;
export declare const encodeNumber: EncodeFunction<NumberInput>;
export declare const decodeNumber: DecodeFunction<bigint>;
import { NumberLike, Parser } from '../types';
/**
* Check if a number type is signed.
*
* @param type The type to check.
* @return Whether the type is signed.
*/
export declare const isSigned: (type: string) => boolean;
/**
* Get a number-like value as bigint.
*
* @param value The number-like value to parse.
* @return The value parsed as bigint.
*/
export declare const asNumber: (value: NumberLike) => bigint;
export declare const number: Parser<NumberLike, bigint>;

@@ -1,3 +0,2 @@

import { DecodeFunction, EncodeFunction } from '../types';
export declare const encodeString: EncodeFunction<string>;
export declare const decodeString: DecodeFunction<string>;
import { Parser } from '../types';
export declare const string: Parser<string>;

@@ -1,12 +0,9 @@

import { DecodeFunction, EncodeFunction } from '../types';
import { Parser } from '../types';
/**
* Check if a type is an tuple type.
* Get elements from a tuple type.
*
* @param {string} type
* @return {boolean}
* @param type The tuple type to get the types for.
* @return The elements of the tuple as string array.
*/
export declare const isTuple: (type: string) => boolean;
export declare const getTypes: (type: string) => string[];
export declare const isDynamicTuple: (types: string[]) => boolean;
export declare const encodeTuple: EncodeFunction<unknown[]>;
export declare const decodeTuple: DecodeFunction<unknown[]>;
export declare const getTupleElements: (type: string) => string[];
export declare const tuple: Parser<unknown[]>;

@@ -1,3 +0,8 @@

export declare type BytesInput = string | Uint8Array | number[];
export declare type NumberInput = bigint | number | string;
export declare type BooleanInput = boolean | string;
export declare type BytesLike = string | Uint8Array;
export declare type BooleanLike = 'true' | 'false' | 'yes' | 'no' | boolean;
export declare type NumberLike = number | bigint | string;
export declare type FunctionLike = string | SolidityFunction;
export interface SolidityFunction {
address: string;
selector: string;
}

@@ -1,8 +0,3 @@

import type { decodeAddress, encodeAddress } from '../parsers/address';
import type { decodeBoolean, encodeBoolean } from '../parsers/boolean';
import type { decodeBytes, encodeBytes } from '../parsers/bytes';
import type { decodeFunction, encodeFunction } from '../parsers/function';
import type { decodeNumber, encodeNumber } from '../parsers/number';
import type { decodeString, encodeString } from '../parsers/string';
import type { DecodeFunction, EncodeFunction } from './parser';
import { address, bool, bytes, fn, number, string } from '../parsers';
import { Parser } from './parser';
declare type ByteLength = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32;

@@ -19,3 +14,3 @@ declare type IntegerLength = 8 | 16 | 24 | 32 | 40 | 48 | 56 | 64 | 72 | 80 | 88 | 96 | 104 | 112 | 120 | 128 | 136 | 144 | 152 | 160 | 168 | 176 | 184 | 192 | 200 | 208 | 216 | 224 | 232 | 240 | 248 | 256;

*/
export declare type OutputTypeMap = WithArrayTypes<GenericTypeMap<typeof decodeAddress, typeof decodeBoolean, typeof decodeBytes, typeof decodeFunction, typeof decodeNumber, typeof decodeString>>;
export declare type OutputTypeMap = WithArrayTypes<MapToOutput<TypeMap>>;
/**

@@ -27,15 +22,15 @@ * An object type with most possible ABI types, and their respective TypeScript type. Note that some dynamic types, like

*/
export declare type InputTypeMap = WithArrayTypes<GenericTypeMap<typeof encodeAddress, typeof encodeBoolean, typeof encodeBytes, typeof encodeFunction, typeof encodeNumber, typeof encodeString>>;
export declare type InputTypeMap = WithArrayTypes<MapToInput<TypeMap>>;
/**
* Generic type map which is used to generate the input and output type map.
*/
declare type GenericTypeMap<AddressFunction, BooleanFunction, BytesFunction, FunctionFunction, NumberFunction, StringFunction> = {
address: ExtractGeneric<AddressFunction>;
bool: ExtractGeneric<BooleanFunction>;
bytes: ExtractGeneric<BytesFunction>;
function: ExtractGeneric<FunctionFunction>;
int: ExtractGeneric<NumberFunction>;
string: ExtractGeneric<StringFunction>;
uint: ExtractGeneric<NumberFunction>;
} & DynamicType<Bytes, ExtractGeneric<BytesFunction>> & DynamicType<Integer, ExtractGeneric<NumberFunction>> & DynamicType<UnsignedInteger, ExtractGeneric<NumberFunction>>;
declare type TypeMap = {
address: ExtractGeneric<typeof address>;
bool: ExtractGeneric<typeof bool>;
bytes: ExtractGeneric<typeof bytes>;
function: ExtractGeneric<typeof fn>;
int: ExtractGeneric<typeof number>;
string: ExtractGeneric<typeof string>;
uint: ExtractGeneric<typeof number>;
} & DynamicType<Bytes, ExtractGeneric<typeof bytes>> & DynamicType<Integer, ExtractGeneric<typeof number>> & DynamicType<UnsignedInteger, ExtractGeneric<typeof number>>;
/**

@@ -54,2 +49,14 @@ * Helper type to generate an object type from a union.

/**
* Helper type that maps a tuple to the first element.
*/
export declare type MapToInput<T extends Record<string, [unknown, unknown]>> = {
[K in keyof T]: T[K][0];
};
/**
* Helper type that maps a tuple to the second element.
*/
export declare type MapToOutput<T extends Record<string, [unknown, unknown]>> = {
[K in keyof T]: T[K][1];
};
/**
* Helper type that adds an array type for each of the specified keys and types.

@@ -61,5 +68,5 @@ */

/**
* Helper type that extracts the input or output from an EncodeFunction or DecodeFunction.
* Helper type that extracts the input or output from a Parser;.
*/
declare type ExtractGeneric<T> = T extends DecodeFunction<infer O> ? O : T extends EncodeFunction<infer I> ? I : never;
declare type ExtractGeneric<T> = T extends Parser<infer I, infer O> ? [I, O] : never;
export {};

@@ -1,2 +0,37 @@

export declare type EncodeFunction<T> = (buffer: Uint8Array, value: T, type: string) => Uint8Array;
export declare type DecodeFunction<T> = (value: Uint8Array, buffer: Uint8Array, type: string) => T;
export declare type DynamicFunction = (type: string) => boolean;
export interface EncodeArgs<Value> {
/**
* The buffer to encode the value in.
*/
buffer: Uint8Array;
/**
* The type of the value to encode.
*/
type: string;
/**
* The value to encode.
*/
value: Value;
}
export interface DecodeArgs {
/**
* The type of the value to decode.
*/
type: string;
/**
* The value to decode.
*/
value: Uint8Array;
/**
* A function to skip a certain number of bytes for parsing. This is currently only used by static tuple types.
*
* @param length The number of bytes to skip.
*/
skip(length: number): void;
}
export interface Parser<EncodeValue = unknown, DecodeValue = EncodeValue> {
isDynamic: boolean | DynamicFunction;
isType?(type: string): boolean;
encode(value: EncodeArgs<EncodeValue>): Uint8Array;
decode(args: DecodeArgs): DecodeValue;
}

@@ -5,4 +5,2 @@ export declare type BinaryLike = string | number | bigint | ArrayBufferLike | number[];

* Returns an instance of `TextEncoder` that works with both Node.js and web browsers.
*
* @return {TextEncoder}
*/

@@ -12,4 +10,2 @@ export declare const getTextEncoder: () => TextEncoder;

* Returns an instance of `TextDecoder` that works with both Node.js and web browsers.
*
* @return {TextDecoder}
*/

@@ -20,4 +16,4 @@ export declare const getTextDecoder: (encoding?: string) => TextDecoder;

*
* @param {Uint8Array} data
* @return {string}
* @param data The buffer to convert to UTF-8.
* @return The buffer as UTF-8 encoded string.
*/

@@ -28,11 +24,11 @@ export declare const toUtf8: (data: Uint8Array) => string;

*
* @param {string} data
* @return {Uint8Array}
* @param data The string to convert to a buffer.
* @return The buffer.
*/
export declare const fromUtf8: (data: string) => Uint8Array;
/**
* Get a Uint8Array as hexadecimal string
* Get a Uint8Array as hexadecimal string.
*
* @param {Uint8Array} data
* @return {string}
* @param data The buffer to convert to a hexadecimal string.
* @return The buffer as hexadecimal string.
*/

@@ -43,18 +39,18 @@ export declare const toHex: (data: Uint8Array) => string;

*
* @param {string} data
* @return {Uint8Array}
* @param data The hexadecimal string to convert to a buffer.
* @return The buffer.
*/
export declare const fromHex: (data: string) => Uint8Array;
/**
* Attempt to parse a value as Uint8Array.
* Attempt to parse a value as Uint8Array. If `data` is a number, this will pad the buffer to 32 bytes.
*
* @param {BinaryLike} data
* @return {Uint8Array}
* @param data The value to parse as Uint8Array.
* @return The resulting Uint8Array.
*/
export declare const toBuffer: (data: BinaryLike) => Uint8Array;
/**
* Safe function to merge multiple Uint8Arrays into a single Uint8array.
* Safe function to merge multiple Uint8Arrays into a single Uint8array. This works with buffers of any size.
*
* @param {Uint8Array[]} buffers
* @return {Uint8Array}
* @param buffers The buffers to combine.
* @return The combined buffers.
*/

@@ -66,12 +62,13 @@ export declare const concat: (buffers: Uint8Array[]) => Uint8Array;

*
* @param {Uint8Array} buffer
* @param {number} [length]
* @return {Uint8Array}
* @param buffer The buffer to add padding to.
* @param [length] The number of bytes to pad the buffer to.
* @return The padded buffer.
*/
export declare const addPadding: (buffer: Uint8Array, length?: number) => Uint8Array;
/**
* Get a number from a buffer.
* Get a number from a buffer. Returns zero if the buffer is empty.
*
* @param {Uint8Array} buffer
* @param buffer The buffer to get a number for.
* @return The parsed number.
*/
export declare const toNumber: (buffer: Uint8Array) => bigint;

@@ -0,2 +1,15 @@

/**
* Get a bigint from a two's complement encoded buffer or hexadecimal string.
*
* @param buffer The buffer to get the number for.
* @return The parsed number.
*/
export declare const fromTwosComplement: (buffer: string | Uint8Array) => bigint;
/**
* Get a two's complement encoded buffer from a bigint.
*
* @param value The number to get the buffer for.
* @param length The number of bytes to pad the buffer to.
* @return The two's complement encoded buffer.
*/
export declare const toTwosComplement: (value: bigint, length: number) => Uint8Array;

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc