/*
This file is part of web3.js.
web3.js is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
web3.js is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with web3.js. If not, see .
*/
import { AbiParameter as ExternalAbiParameter, parseAbiParameter } from 'abitype';
import { AbiError } from 'web3-errors';
import { AbiInput, AbiParameter, AbiStruct } from 'web3-types';
import { isNullish } from 'web3-utils';
import {
isSimplifiedStructFormat,
mapStructNameAndType,
mapStructToCoderFormat,
} from '../utils.js';
export const WORD_SIZE = 32;
export function alloc(size = 0): Uint8Array {
if (globalThis.Buffer?.alloc !== undefined) {
const buf = globalThis.Buffer.alloc(size);
return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);
}
return new Uint8Array(size);
}
/**
* Where possible returns a Uint8Array of the requested size that references
* uninitialized memory. Only use if you are certain you will immediately
* overwrite every value in the returned `Uint8Array`.
*/
export function allocUnsafe(size = 0): Uint8Array {
if (globalThis.Buffer?.allocUnsafe !== undefined) {
const buf = globalThis.Buffer.allocUnsafe(size);
return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);
}
return new Uint8Array(size);
}
export function convertExternalAbiParameter(abiParam: ExternalAbiParameter): AbiParameter {
return {
...abiParam,
name: abiParam.name ?? '',
components: (abiParam as { components: readonly AbiParameter[] }).components?.map(c =>
convertExternalAbiParameter(c),
),
};
}
export function isAbiParameter(param: unknown): param is AbiParameter {
return (
!isNullish(param) &&
typeof param === 'object' &&
!isNullish((param as { type: unknown }).type) &&
typeof (param as { type: unknown }).type === 'string'
);
}
export function toAbiParams(abi: ReadonlyArray): ReadonlyArray {
return abi.map(input => {
if (isAbiParameter(input)) {
return input;
}
if (typeof input === 'string') {
return convertExternalAbiParameter(parseAbiParameter(input.replace(/tuple/, '')));
}
if (isSimplifiedStructFormat(input)) {
const structName = Object.keys(input)[0];
const structInfo = mapStructNameAndType(structName);
structInfo.name = structInfo.name ?? '';
return {
...structInfo,
components: mapStructToCoderFormat(
input[structName as keyof typeof input] as unknown as AbiStruct,
),
};
}
throw new AbiError('Invalid abi');
});
}
export function extractArrayType(param: AbiParameter): { size: number; param: AbiParameter } {
const arrayParenthesisStart = param.type.lastIndexOf('[');
const arrayParamType = param.type.substring(0, arrayParenthesisStart);
const sizeString = param.type.substring(arrayParenthesisStart);
let size = -1;
if (sizeString !== '[]') {
size = Number(sizeString.slice(1, -1));
// eslint-disable-next-line no-restricted-globals
if (isNaN(size)) {
throw new AbiError('Invalid fixed array size', { size: sizeString });
}
}
return {
param: { type: arrayParamType, name: '', components: param.components },
size,
};
}
/**
* Param is dynamic if it's dynamic base type or if some of his children (components, array items)
* is of dynamic type
* @param param
*/
export function isDynamic(param: AbiParameter): boolean {
if (param.type === 'string' || param.type === 'bytes' || param.type.endsWith('[]')) return true;
if (param.type === 'tuple') {
return param.components?.some(isDynamic) ?? false;
}
if (param.type.endsWith(']')) {
return isDynamic(extractArrayType(param).param);
}
return false;
}