viem
Version:
470 lines (434 loc) • 15 kB
text/typescript
import type {
Abi,
AbiEvent,
AbiFunction,
AbiParameter,
AbiParameterToPrimitiveType,
AbiParametersToPrimitiveTypes,
AbiStateMutability,
Address,
ExtractAbiError,
ExtractAbiErrorNames,
ExtractAbiEvent,
ExtractAbiEventNames,
ExtractAbiFunction,
ExtractAbiFunctionNames,
ResolvedRegister,
} from 'abitype'
import type { Hex, LogTopic } from './misc.js'
import type { TransactionRequest } from './transaction.js'
import type {
Filter,
IsNarrowable,
IsUnion,
MaybeRequired,
NoInfer,
Prettify,
UnionToTuple,
} from './utils.js'
export type ContractFunctionName<
abi extends Abi | readonly unknown[] = Abi,
mutability extends AbiStateMutability = AbiStateMutability,
> = ExtractAbiFunctionNames<
abi extends Abi ? abi : Abi,
mutability
> extends infer functionName extends string
? [functionName] extends [never]
? string
: functionName
: string
export type ContractErrorName<abi extends Abi | readonly unknown[] = Abi> =
ExtractAbiErrorNames<
abi extends Abi ? abi : Abi
> extends infer errorName extends string
? [errorName] extends [never]
? string
: errorName
: string
export type ContractEventName<abi extends Abi | readonly unknown[] = Abi> =
ExtractAbiEventNames<
abi extends Abi ? abi : Abi
> extends infer eventName extends string
? [eventName] extends [never]
? string
: eventName
: string
export type ContractFunctionArgs<
abi extends Abi | readonly unknown[] = Abi,
mutability extends AbiStateMutability = AbiStateMutability,
functionName extends ContractFunctionName<
abi,
mutability
> = ContractFunctionName<abi, mutability>,
> = AbiParametersToPrimitiveTypes<
ExtractAbiFunction<
abi extends Abi ? abi : Abi,
functionName,
mutability
>['inputs'],
'inputs'
> extends infer args
? [args] extends [never]
? readonly unknown[]
: args
: readonly unknown[]
export type ContractConstructorArgs<
abi extends Abi | readonly unknown[] = Abi,
> = AbiParametersToPrimitiveTypes<
Extract<
(abi extends Abi ? abi : Abi)[number],
{ type: 'constructor' }
>['inputs'],
'inputs'
> extends infer args
? [args] extends [never]
? readonly unknown[]
: args
: readonly unknown[]
export type ContractErrorArgs<
abi extends Abi | readonly unknown[] = Abi,
errorName extends ContractErrorName<abi> = ContractErrorName<abi>,
> = AbiParametersToPrimitiveTypes<
ExtractAbiError<abi extends Abi ? abi : Abi, errorName>['inputs'],
'inputs'
> extends infer args
? [args] extends [never]
? readonly unknown[]
: args
: readonly unknown[]
export type ContractEventArgs<
abi extends Abi | readonly unknown[] = Abi,
eventName extends ContractEventName<abi> = ContractEventName<abi>,
> = AbiEventParametersToPrimitiveTypes<
ExtractAbiEvent<abi extends Abi ? abi : Abi, eventName>['inputs']
> extends infer args
? [args] extends [never]
? readonly unknown[] | Record<string, unknown>
: args
: readonly unknown[] | Record<string, unknown>
export type ContractEventArgsFromTopics<
abi extends Abi | readonly unknown[] = Abi,
eventName extends ContractEventName<abi> = ContractEventName<abi>,
strict extends boolean = true,
> = AbiEventParametersToPrimitiveTypes<
ExtractAbiEvent<abi extends Abi ? abi : Abi, eventName>['inputs'],
{ EnableUnion: false; IndexedOnly: false; Required: strict }
> extends infer args
? [args] extends [never]
? readonly unknown[] | Record<string, unknown>
: args
: readonly unknown[] | Record<string, unknown>
export type Widen<type> =
| ([unknown] extends [type] ? unknown : never)
| (type extends Function ? type : never)
| (type extends ResolvedRegister['BigIntType'] ? bigint : never)
| (type extends boolean ? boolean : never)
| (type extends ResolvedRegister['IntType'] ? number : never)
| (type extends string
? type extends ResolvedRegister['AddressType']
? ResolvedRegister['AddressType']
: type extends ResolvedRegister['BytesType']['inputs']
? ResolvedRegister['BytesType']
: string
: never)
| (type extends readonly [] ? readonly [] : never)
| (type extends Record<string, unknown>
? { [K in keyof type]: Widen<type[K]> }
: never)
| (type extends { length: number }
? {
[K in keyof type]: Widen<type[K]>
} extends infer Val extends readonly unknown[]
? readonly [...Val]
: never
: never)
export type UnionWiden<type> = type extends any ? Widen<type> : never
export type ExtractAbiFunctionForArgs<
abi extends Abi,
mutability extends AbiStateMutability,
functionName extends ContractFunctionName<abi, mutability>,
args extends ContractFunctionArgs<abi, mutability, functionName>,
> = ExtractAbiFunction<
abi,
functionName,
mutability
> extends infer abiFunction extends AbiFunction
? IsUnion<abiFunction> extends true // narrow overloads using `args` by converting to tuple and filtering out overloads that don't match
? UnionToTuple<abiFunction> extends infer abiFunctions extends
readonly AbiFunction[]
? // convert back to union (removes `never` tuple entries)
{ [k in keyof abiFunctions]: CheckArgs<abiFunctions[k], args> }[number]
: never
: abiFunction
: never
type CheckArgs<
abiFunction extends AbiFunction,
args,
///
targetArgs extends AbiParametersToPrimitiveTypes<
abiFunction['inputs'],
'inputs'
> = AbiParametersToPrimitiveTypes<abiFunction['inputs'], 'inputs'>,
> = (readonly [] extends args ? readonly [] : args) extends targetArgs // fallback to `readonly []` if `args` has no value (e.g. `args` property not provided)
? abiFunction
: never
export type ContractFunctionParameters<
abi extends Abi | readonly unknown[] = Abi,
mutability extends AbiStateMutability = AbiStateMutability,
functionName extends ContractFunctionName<
abi,
mutability
> = ContractFunctionName<abi, mutability>,
args extends ContractFunctionArgs<
abi,
mutability,
functionName
> = ContractFunctionArgs<abi, mutability, functionName>,
deployless extends boolean = false,
///
allFunctionNames = ContractFunctionName<abi, mutability>,
allArgs = ContractFunctionArgs<abi, mutability, functionName>,
// when `args` is inferred to `readonly []` ("inputs": []) or `never` (`abi` declared as `Abi` or not inferrable), allow `args` to be optional.
// important that both branches return same structural type
> = {
abi: abi
functionName:
| allFunctionNames // show all options
| (functionName extends allFunctionNames ? functionName : never) // infer value
args?: (abi extends Abi ? UnionWiden<args> : never) | allArgs | undefined
} & (readonly [] extends allArgs ? {} : { args: Widen<args> }) &
(deployless extends true
? { address?: undefined; code: Hex }
: { address: Address })
export type ContractFunctionReturnType<
abi extends Abi | readonly unknown[] = Abi,
mutability extends AbiStateMutability = AbiStateMutability,
functionName extends ContractFunctionName<
abi,
mutability
> = ContractFunctionName<abi, mutability>,
args extends ContractFunctionArgs<
abi,
mutability,
functionName
> = ContractFunctionArgs<abi, mutability, functionName>,
> = abi extends Abi
? Abi extends abi
? unknown
: AbiParametersToPrimitiveTypes<
ExtractAbiFunctionForArgs<
abi,
mutability,
functionName,
args
>['outputs']
> extends infer types
? types extends readonly []
? void
: types extends readonly [infer type]
? type
: types
: never
: unknown
export type AbiItem = Abi[number]
export type ExtractAbiItemNames<abi extends Abi> = Extract<
abi[number],
{ name: string }
>['name']
export type ExtractAbiItem<
abi extends Abi,
name extends ExtractAbiItemNames<abi>,
> = Extract<abi[number], { name: name }>
export type AbiItemName<abi extends Abi | readonly unknown[] = Abi> =
abi extends Abi ? ExtractAbiItemNames<abi> : string
export type AbiItemArgs<
abi extends Abi | readonly unknown[] = Abi,
name extends AbiItemName<abi> = AbiItemName<abi>,
> = AbiParametersToPrimitiveTypes<
ExtractAbiItem<abi extends Abi ? abi : Abi, name>['inputs'],
'inputs'
> extends infer args
? [args] extends [never]
? readonly unknown[]
: args
: readonly unknown[]
export type ExtractAbiItemForArgs<
abi extends Abi,
name extends AbiItemName<abi>,
args extends AbiItemArgs<abi, name>,
> = ExtractAbiItem<abi, name> extends infer abiItem extends AbiItem & {
inputs: readonly AbiParameter[]
}
? IsUnion<abiItem> extends true // narrow overloads using `args` by converting to tuple and filtering out overloads that don't match
? UnionToTuple<abiItem> extends infer abiItems extends readonly (AbiItem & {
inputs: readonly AbiParameter[]
})[]
? {
[k in keyof abiItems]: (
readonly [] extends args
? readonly [] // fallback to `readonly []` if `args` has no value (e.g. `args` property not provided)
: args
) extends AbiParametersToPrimitiveTypes<
abiItems[k]['inputs'],
'inputs'
>
? abiItems[k]
: never
}[number] // convert back to union (removes `never` tuple entries: `['foo', never, 'bar'][number]` => `'foo' | 'bar'`)
: never
: abiItem
: never
export type EventDefinition = `${string}(${string})`
export type GetValue<
abi extends Abi | readonly unknown[],
functionName extends string,
valueType = TransactionRequest['value'],
abiFunction extends AbiFunction = abi extends Abi
? ExtractAbiFunction<abi, functionName>
: AbiFunction,
_Narrowable extends boolean = IsNarrowable<abi, Abi>,
> = _Narrowable extends true
? abiFunction['stateMutability'] extends 'payable'
? { value?: NoInfer<valueType> | undefined }
: abiFunction['payable'] extends true
? { value?: NoInfer<valueType> | undefined }
: { value?: undefined }
: { value?: NoInfer<valueType> | undefined }
//////////////////////////////////////////////////////////////////////////////////////////////////
export type MaybeAbiEventName<abiEvent extends AbiEvent | undefined> =
abiEvent extends AbiEvent ? abiEvent['name'] : undefined
export type MaybeExtractEventArgsFromAbi<
abi extends Abi | readonly unknown[] | undefined,
eventName extends string | undefined,
> = abi extends Abi | readonly unknown[]
? eventName extends string
? GetEventArgs<abi, eventName>
: undefined
: undefined
//////////////////////////////////////////////////////////////////////
// ABI item args
export type GetEventArgs<
abi extends Abi | readonly unknown[],
eventName extends string,
config extends EventParameterOptions = DefaultEventParameterOptions,
abiEvent extends AbiEvent & { type: 'event' } = abi extends Abi
? ExtractAbiEvent<abi, eventName>
: AbiEvent & { type: 'event' },
args = AbiEventParametersToPrimitiveTypes<abiEvent['inputs'], config>,
FailedToParseArgs =
| ([args] extends [never] ? true : false)
| (readonly unknown[] extends args ? true : false),
> = true extends FailedToParseArgs
? readonly unknown[] | Record<string, unknown>
: args
//////////////////////////////////////////////////////////////////////
// ABI event types
type EventParameterOptions = {
EnableUnion?: boolean
IndexedOnly?: boolean
Required?: boolean
}
type DefaultEventParameterOptions = {
EnableUnion: true
IndexedOnly: true
Required: false
}
export type AbiEventParametersToPrimitiveTypes<
abiParameters extends readonly AbiParameter[],
//
_options extends EventParameterOptions = DefaultEventParameterOptions,
// Remove non-indexed parameters based on `Options['IndexedOnly']`
> = abiParameters extends readonly []
? readonly []
: Filter<
abiParameters,
_options['IndexedOnly'] extends true ? { indexed: true } : object
> extends infer Filtered extends readonly AbiParameter[]
? _HasUnnamedAbiParameter<Filtered> extends true
? // Has unnamed tuple parameters so return as array
| readonly [
...{
[K in keyof Filtered]: AbiEventParameterToPrimitiveType<
Filtered[K],
_options
>
},
]
// Distribute over tuple to represent optional parameters
| (_options['Required'] extends true
? never
: // Distribute over tuple to represent optional parameters
Filtered extends readonly [
...infer Head extends readonly AbiParameter[],
infer _,
]
? AbiEventParametersToPrimitiveTypes<
readonly [...{ [K in keyof Head]: Omit<Head[K], 'name'> }],
_options
>
: never)
: // All tuple parameters are named so return as object
{
[Parameter in Filtered[number] as Parameter extends {
name: infer Name extends string
}
? Name
: never]?:
| AbiEventParameterToPrimitiveType<Parameter, _options>
| undefined
} extends infer Mapped
? Prettify<
MaybeRequired<
Mapped,
_options['Required'] extends boolean
? _options['Required']
: false
>
>
: never
: never
// TODO: Speed up by returning immediately as soon as named parameter is found.
type _HasUnnamedAbiParameter<abiParameters extends readonly AbiParameter[]> =
abiParameters extends readonly [
infer Head extends AbiParameter,
...infer Tail extends readonly AbiParameter[],
]
? Head extends { name: string }
? Head['name'] extends ''
? true
: _HasUnnamedAbiParameter<Tail>
: true
: false
/**
* @internal
*/
export type LogTopicType<
primitiveType = Hex,
topic extends LogTopic = LogTopic,
> = topic extends Hex
? primitiveType
: topic extends Hex[]
? primitiveType[]
: topic extends null
? null
: never
/**
* @internal
*/
export type AbiEventParameterToPrimitiveType<
abiParameter extends AbiParameter,
//
_options extends EventParameterOptions = DefaultEventParameterOptions,
_type = AbiParameterToPrimitiveType<abiParameter>,
> = _options['EnableUnion'] extends true ? LogTopicType<_type> : _type
type HashedEventTypes = 'bytes' | 'string' | 'tuple' | `${string}[${string}]`
/**
* @internal
*/
export type AbiEventTopicToPrimitiveType<
abiParameter extends AbiParameter,
topic extends LogTopic,
primitiveType = abiParameter['type'] extends HashedEventTypes
? topic
: AbiParameterToPrimitiveType<abiParameter>,
> = LogTopicType<primitiveType, topic>