ox
Version:
Ethereum Standard Library
142 lines • 5.6 kB
JavaScript
import * as Address from '../Address.js';
import * as Errors from '../Errors.js';
/** @internal */
export function normalizeSignature(signature) {
let active = true;
let current = '';
let level = 0;
let result = '';
let valid = false;
for (let i = 0; i < signature.length; i++) {
const char = signature[i];
// If the character is a separator, we want to reactivate.
if (['(', ')', ','].includes(char))
active = true;
// If the character is a "level" token, we want to increment/decrement.
if (char === '(')
level++;
if (char === ')')
level--;
// If we aren't active, we don't want to mutate the result.
if (!active)
continue;
// If level === 0, we are at the definition level.
if (level === 0) {
if (char === ' ' && ['event', 'function', 'error', ''].includes(result))
result = '';
else {
result += char;
// If we are at the end of the definition, we must be finished.
if (char === ')') {
valid = true;
break;
}
}
continue;
}
// Ignore spaces
if (char === ' ') {
// If the previous character is a separator, and the current section isn't empty, we want to deactivate.
if (signature[i - 1] !== ',' && current !== ',' && current !== ',(') {
current = '';
active = false;
}
continue;
}
result += char;
current += char;
}
if (!valid)
throw new Errors.BaseError('Unable to normalize signature.');
return result;
}
/**
* `(u)int<M>` regex: (un)signed integer type of `M` bits, `0 < M <= 256`,
* `M % 8 == 0`. Hoisted to module scope; the prior literal at the call
* site was recompiled per overload-resolution iteration.
*
* @internal
*/
const integerTypeRegex = /^u?int(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)?$/;
/**
* `bytes<M>` regex: binary type of `M` bytes, `0 < M <= 32`.
*
* @internal
*/
const fixedBytesTypeRegex = /^bytes([1-9]|1[0-9]|2[0-9]|3[0-2])?$/;
/**
* Fixed-length (`<type>[M]`) / dynamic (`<type>[]`) array regex.
*
* @internal
*/
const arrayTypeRegex = /[a-z]+[1-9]{0,3}(\[[0-9]{0,}\])+$/;
/**
* Strips a single trailing `[...]` array suffix from a type.
*
* @internal
*/
const arraySuffixStripRegex = /(\[[0-9]{0,}\])$/;
/** @internal */
export function isArgOfType(arg, abiParameter) {
const argType = typeof arg;
const abiParameterType = abiParameter.type;
switch (abiParameterType) {
case 'address':
return Address.validate(arg, { strict: false });
case 'bool':
return argType === 'boolean';
case 'function':
return argType === 'string';
case 'string':
return argType === 'string';
default: {
if (abiParameterType === 'tuple' && 'components' in abiParameter)
return Object.values(abiParameter.components).every((component, index) => {
return isArgOfType(Object.values(arg)[index], component);
});
if (integerTypeRegex.test(abiParameterType))
return argType === 'number' || argType === 'bigint';
if (fixedBytesTypeRegex.test(abiParameterType))
return argType === 'string' || arg instanceof Uint8Array;
if (arrayTypeRegex.test(abiParameterType)) {
return (Array.isArray(arg) &&
arg.every((x) => isArgOfType(x, {
...abiParameter,
// Pop off `[]` or `[M]` from end of type
type: abiParameterType.replace(arraySuffixStripRegex, ''),
})));
}
return false;
}
}
}
/** @internal */
export function getAmbiguousTypes(sourceParameters, targetParameters, args) {
// Indexed `for` loop instead of `for...in` (which iterates inherited
// enumerable keys and is materially slower on arrays).
for (let parameterIndex = 0; parameterIndex < sourceParameters.length; parameterIndex++) {
const sourceParameter = sourceParameters[parameterIndex];
const targetParameter = targetParameters[parameterIndex];
if (sourceParameter.type === 'tuple' &&
targetParameter.type === 'tuple' &&
'components' in sourceParameter &&
'components' in targetParameter)
return getAmbiguousTypes(sourceParameter.components, targetParameter.components, args[parameterIndex]);
const sourceType = sourceParameter.type;
const targetType = targetParameter.type;
const arg = args[parameterIndex];
let ambiguous = false;
if ((sourceType === 'address' && targetType === 'bytes20') ||
(sourceType === 'bytes20' && targetType === 'address'))
ambiguous = true;
else if ((sourceType === 'address' && targetType === 'string') ||
(sourceType === 'string' && targetType === 'address') ||
(sourceType === 'address' && targetType === 'bytes') ||
(sourceType === 'bytes' && targetType === 'address'))
ambiguous = Address.validate(arg, { strict: false });
if (ambiguous)
return [sourceType, targetType];
}
return;
}
//# sourceMappingURL=abiItem.js.map