import type { AbiStateMutability } from '../../abi.js' import type { Error } from '../../types.js' export type ErrorSignature< name extends string = string, parameters extends string = string, > = `error ${name}(${parameters})` export type IsErrorSignature = signature extends ErrorSignature ? IsName : false export type EventSignature< name extends string = string, parameters extends string = string, > = `event ${name}(${parameters})` export type IsEventSignature = signature extends EventSignature ? IsName : false export type FunctionSignature< name extends string = string, tail extends string = string, > = `function ${name}(${tail}` export type IsFunctionSignature = signature extends FunctionSignature ? IsName extends true ? signature extends ValidFunctionSignatures ? true : // Check that `Parameters` is not absorbing other types (e.g. `returns`) signature extends `function ${string}(${infer parameters})` ? parameters extends InvalidFunctionParameters ? false : true : false : false : false export type Scope = 'public' | 'external' // `internal` or `private` functions wouldn't make it to ABI so can ignore type Returns = `returns (${string})` | `returns(${string})` // Almost all valid function signatures, except `function ${string}(${infer parameters})` since `parameters` can absorb returns type ValidFunctionSignatures = | `function ${string}()` // basic | `function ${string}() ${Returns}` | `function ${string}() ${AbiStateMutability}` | `function ${string}() ${Scope}` // combinations | `function ${string}() ${AbiStateMutability} ${Returns}` | `function ${string}() ${Scope} ${Returns}` | `function ${string}() ${Scope} ${AbiStateMutability}` | `function ${string}() ${Scope} ${AbiStateMutability} ${Returns}` // Parameters | `function ${string}(${string}) ${Returns}` | `function ${string}(${string}) ${AbiStateMutability}` | `function ${string}(${string}) ${Scope}` | `function ${string}(${string}) ${AbiStateMutability} ${Returns}` | `function ${string}(${string}) ${Scope} ${Returns}` | `function ${string}(${string}) ${Scope} ${AbiStateMutability}` | `function ${string}(${string}) ${Scope} ${AbiStateMutability} ${Returns}` export type StructSignature< name extends string = string, properties extends string = string, > = `struct ${name} {${properties}}` export type IsStructSignature = signature extends StructSignature ? IsName : false type ConstructorSignature = `constructor(${tail}` export type IsConstructorSignature = signature extends ConstructorSignature ? signature extends ValidConstructorSignatures ? true : false : false type ValidConstructorSignatures = | `constructor(${string})` | `constructor(${string}) payable` export type FallbackSignature< abiStateMutability extends '' | ' payable' = '' | ' payable', > = `fallback() external${abiStateMutability}` export type IsFallbackSignature = signature extends | FallbackSignature<''> | FallbackSignature<' payable'> ? true : false export type ReceiveSignature = 'receive() external payable' // TODO: Maybe use this for signature validation one day // https://twitter.com/devanshj__/status/1610423724708343808 export type IsSignature = | (IsErrorSignature extends true ? true : never) | (IsEventSignature extends true ? true : never) | (IsFunctionSignature extends true ? true : never) | (IsStructSignature extends true ? true : never) | (IsConstructorSignature extends true ? true : never) | (IsFallbackSignature extends true ? true : never) | (type extends ReceiveSignature ? true : never) extends infer condition ? [condition] extends [never] ? false : true : false export type Signature< string1 extends string, string2 extends string | unknown = unknown, > = IsSignature extends true ? string1 : string extends string1 // if exactly `string` (not narrowed), then pass through as valid ? string1 : Error<`Signature "${string1}" is invalid${string2 extends string ? ` at position ${string2}` : ''}.`> export type Signatures = { [key in keyof signatures]: Signature } export type Modifier = 'calldata' | 'indexed' | 'memory' | 'payable' | 'storage' export type FunctionModifier = Extract< Modifier, 'calldata' | 'memory' | 'payable' | 'storage' > export type EventModifier = Extract export type IsName = name extends '' ? false : ValidateName extends name ? true : false export type AssertName = ValidateName extends infer invalidName extends string[] ? `[${invalidName[number]}]` : name export type ValidateName< name extends string, checkCharacters extends boolean = false, > = name extends `${string}${' '}${string}` ? Error<`Identifier "${name}" cannot contain whitespace.`> : IsSolidityKeyword extends true ? Error<`"${name}" is a protected Solidity keyword.`> : name extends `${number}` ? Error<`Identifier "${name}" cannot be a number string.`> : name extends `${number}${string}` ? Error<`Identifier "${name}" cannot start with a number.`> : checkCharacters extends true ? IsValidCharacter extends true ? name : Error<`"${name}" contains invalid character.`> : name export type IsSolidityKeyword = type extends SolidityKeywords ? true : false export type SolidityKeywords = | 'after' | 'alias' | 'anonymous' | 'apply' | 'auto' | 'byte' | 'calldata' | 'case' | 'catch' | 'constant' | 'copyof' | 'default' | 'defined' | 'error' | 'event' | 'external' | 'false' | 'final' | 'function' | 'immutable' | 'implements' | 'in' | 'indexed' | 'inline' | 'internal' | 'let' | 'mapping' | 'match' | 'memory' | 'mutable' | 'null' | 'of' | 'override' | 'partial' | 'private' | 'promise' | 'public' | 'pure' | 'reference' | 'relocatable' | 'return' | 'returns' | 'sizeof' | 'static' | 'storage' | 'struct' | 'super' | 'supports' | 'switch' | 'this' | 'true' | 'try' | 'typedef' | 'typeof' | 'var' | 'view' | 'virtual' | `address${`[${string}]` | ''}` | `bool${`[${string}]` | ''}` | `string${`[${string}]` | ''}` | `tuple${`[${string}]` | ''}` | `bytes${number | ''}${`[${string}]` | ''}` | `${'u' | ''}int${number | ''}${`[${string}]` | ''}` export type IsValidCharacter = character extends `${ValidCharacters}${infer tail}` ? tail extends '' ? true : IsValidCharacter : false // oxfmt-ignore type ValidCharacters = // uppercase letters | 'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'G' | 'H' | 'I' | 'J' | 'K' | 'L' | 'M' | 'N' | 'O' | 'P' | 'Q' | 'R' | 'S' | 'T' | 'U' | 'V' | 'W' | 'X' | 'Y' | 'Z' // lowercase letters | 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | 'g' | 'h' | 'i' | 'j' | 'k' | 'l' | 'm' | 'n' | 'o' | 'p' | 'q' | 'r' | 's' | 't' | 'u' | 'v' | 'w' | 'x' | 'y' | 'z' // numbers | '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' // special characters | '_' | '$' // Template string inference can absorb `returns`: // type Result = `function foo(string) return s (uint256)` extends `function ${string}(${infer Parameters})` ? Parameters : never // // ^? type Result = "string ) return s (uint256" // So we need to validate against `returns` keyword with all combinations of whitespace type InvalidFunctionParameters = | `${string}${MangledReturns} (${string}` | `${string}) ${MangledReturns}${string}` | `${string})${string}${MangledReturns}${string}(${string}` // r_e_t_u_r_n_s type MangledReturns = // Single | `r${string}eturns` | `re${string}turns` | `ret${string}urns` | `retu${string}rns` | `retur${string}ns` | `return${string}s` // Double // `r_e*` | `r${string}e${string}turns` | `r${string}et${string}urns` | `r${string}etu${string}rns` | `r${string}etur${string}ns` | `r${string}eturn${string}s` // `re_t*` | `re${string}t${string}urns` | `re${string}tu${string}rns` | `re${string}tur${string}ns` | `re${string}turn${string}s` // `ret_u*` | `ret${string}u${string}rns` | `ret${string}ur${string}ns` | `ret${string}urn${string}s` // `retu_r*` | `retu${string}r${string}ns` | `retu${string}rn${string}s` // `retur_n*` | `retur${string}n${string}s` // Triple // `r_e_t*` | `r${string}e${string}t${string}urns` | `r${string}e${string}tu${string}rns` | `r${string}e${string}tur${string}ns` | `r${string}e${string}turn${string}s` // `re_t_u*` | `re${string}t${string}u${string}rns` | `re${string}t${string}ur${string}ns` | `re${string}t${string}urn${string}s` // `ret_u_r*` | `ret${string}u${string}r${string}ns` | `ret${string}u${string}rn${string}s` // `retu_r_n*` | `retu${string}r${string}n${string}s` // Quadruple // `r_e_t_u*` | `r${string}e${string}t${string}u${string}rns` | `r${string}e${string}t${string}ur${string}ns` | `r${string}e${string}t${string}urn${string}s` // `re_t_u_r*` | `re${string}t${string}u${string}r${string}ns` | `re${string}t${string}u${string}rn${string}s` // `ret_u_r_n*` | `ret${string}u${string}r${string}n${string}s` // Quintuple // `r_e_t_u_r*` | `r${string}e${string}t${string}u${string}r${string}ns` | `r${string}e${string}t${string}u${string}rn${string}s` // `re_t_u_r_n*` | `re${string}t${string}u${string}r${string}n${string}s` // Sextuple // `r_e_t_u_r_n_s` | `r${string}e${string}t${string}u${string}r${string}n${string}s`