xchange-create
Version:
Create Xchange Project
396 lines (357 loc) • 10.8 kB
text/typescript
import { MutateOptions } from "@tanstack/react-query"
import {
Abi,
AbiParameter,
AbiParametersToPrimitiveTypes,
AbiParameterToPrimitiveType,
ExtractAbiEvent,
ExtractAbiEventNames,
ExtractAbiFunction,
} from "abitype"
import type { ExtractAbiFunctionNames } from "abitype"
import type { Simplify } from "type-fest"
import type { MergeDeepRecord } from "type-fest/source/merge-deep"
import {
Address,
Block,
GetEventArgs,
GetTransactionReceiptReturnType,
GetTransactionReturnType,
Log,
TransactionReceipt,
WriteContractErrorType,
} from "viem"
import {
Config,
UseReadContractParameters,
UseWatchContractEventParameters,
} from "wagmi"
import { WriteContractParameters, WriteContractReturnType } from "wagmi/actions"
import { WriteContractVariables } from "wagmi/query"
import deployedContractsData from "~~/contracts/deployedContracts"
import externalContractsData from "~~/contracts/externalContracts"
import xchangeConfig from "~~/xchange.config"
type AddExternalFlag<T> = {
[ChainId in keyof T]: {
[ContractName in keyof T[ChainId]]: T[ChainId][ContractName] & {
external?: true
}
}
}
const deepMergeContracts = <
L extends Record<PropertyKey, any>,
E extends Record<PropertyKey, any>,
>(
local: L,
external: E
) => {
const result: Record<PropertyKey, any> = {}
const allKeys = Array.from(
new Set([...Object.keys(external), ...Object.keys(local)])
)
for (const key of allKeys) {
if (!external[key]) {
result[key] = local[key]
continue
}
const amendedExternal = Object.fromEntries(
Object.entries(
external[key] as Record<string, Record<string, unknown>>
).map(([contractName, declaration]) => [
contractName,
{ ...declaration, external: true },
])
)
result[key] = { ...local[key], ...amendedExternal }
}
return result as MergeDeepRecord<
AddExternalFlag<L>,
AddExternalFlag<E>,
{ arrayMergeMode: "replace" }
>
}
const contractsData = deepMergeContracts(
deployedContractsData,
externalContractsData
)
export type InheritedFunctions = { readonly [key: string]: string }
export type GenericContract = {
address: Address
abi: Abi
inheritedFunctions?: InheritedFunctions
external?: true
}
export type GenericContractsDeclaration = {
[chainId: number]: {
[contractName: string]: GenericContract
}
}
export const contracts = contractsData as GenericContractsDeclaration | null
type ConfiguredChainId = (typeof xchangeConfig)["targetNetworks"][0]["id"]
type IsContractDeclarationMissing<TYes, TNo> = typeof contractsData extends {
[key in ConfiguredChainId]: any
}
? TNo
: TYes
type ContractsDeclaration = IsContractDeclarationMissing<
GenericContractsDeclaration,
typeof contractsData
>
type Contracts = ContractsDeclaration[ConfiguredChainId]
export type ContractName = keyof Contracts
export type Contract<TContractName extends ContractName> =
Contracts[TContractName]
type InferContractAbi<TContract> = TContract extends { abi: infer TAbi }
? TAbi
: never
export type ContractAbi<TContractName extends ContractName = ContractName> =
InferContractAbi<Contract<TContractName>>
export type AbiFunctionInputs<
TAbi extends Abi,
TFunctionName extends string,
> = ExtractAbiFunction<TAbi, TFunctionName>["inputs"]
export type AbiFunctionArguments<
TAbi extends Abi,
TFunctionName extends string,
> = AbiParametersToPrimitiveTypes<AbiFunctionInputs<TAbi, TFunctionName>>
export type AbiFunctionOutputs<
TAbi extends Abi,
TFunctionName extends string,
> = ExtractAbiFunction<TAbi, TFunctionName>["outputs"]
export type AbiFunctionReturnType<
TAbi extends Abi,
TFunctionName extends string,
> = IsContractDeclarationMissing<
any,
AbiParametersToPrimitiveTypes<
AbiFunctionOutputs<TAbi, TFunctionName>
> extends readonly [any]
? AbiParametersToPrimitiveTypes<AbiFunctionOutputs<TAbi, TFunctionName>>[0]
: AbiParametersToPrimitiveTypes<AbiFunctionOutputs<TAbi, TFunctionName>>
>
export type AbiEventInputs<
TAbi extends Abi,
TEventName extends ExtractAbiEventNames<TAbi>,
> = ExtractAbiEvent<TAbi, TEventName>["inputs"]
export enum ContractCodeStatus {
"LOADING",
"DEPLOYED",
"NOT_FOUND",
}
type AbiStateMutability = "pure" | "view" | "nonpayable" | "payable"
export type ReadAbiStateMutability = "view" | "pure"
export type WriteAbiStateMutability = "nonpayable" | "payable"
export type FunctionNamesWithInputs<
TContractName extends ContractName,
TAbiStateMutibility extends AbiStateMutability = AbiStateMutability,
> = Exclude<
Extract<
ContractAbi<TContractName>[number],
{
type: "function"
stateMutability: TAbiStateMutibility
}
>,
{
inputs: readonly []
}
>["name"]
type Expand<T> = T extends object
? T extends infer O
? { [K in keyof O]: O[K] }
: never
: T
type UnionToIntersection<U> = Expand<
(U extends any ? (k: U) => void : never) extends (k: infer I) => void
? I
: never
>
type OptionalTupple<T> = T extends readonly [infer H, ...infer R]
? readonly [H | undefined, ...OptionalTupple<R>]
: T
type UseArgsParam<
TContractName extends ContractName,
TFunctionName extends ExtractAbiFunctionNames<ContractAbi<TContractName>>,
> =
TFunctionName extends FunctionNamesWithInputs<TContractName>
? {
args: OptionalTupple<
UnionToIntersection<
AbiFunctionArguments<ContractAbi<TContractName>, TFunctionName>
>
>
value?: ExtractAbiFunction<
ContractAbi<TContractName>,
TFunctionName
>["stateMutability"] extends "payable"
? bigint | undefined
: undefined
}
: {
args?: never
}
export type UseReadConfig<
TContractName extends ContractName,
TFunctionName extends ExtractAbiFunctionNames<
ContractAbi<TContractName>,
ReadAbiStateMutability
>,
> = {
contractName: TContractName
watch?: boolean
} & IsContractDeclarationMissing<
Partial<UseReadContractParameters>,
{
functionName: TFunctionName
} & UseArgsParam<TContractName, TFunctionName> &
Omit<
UseReadContractParameters,
"chainId" | "abi" | "address" | "functionName" | "args"
>
>
export type XchangeWriteContractVariables<
TContractName extends ContractName,
TFunctionName extends ExtractAbiFunctionNames<
ContractAbi<TContractName>,
WriteAbiStateMutability
>,
> = IsContractDeclarationMissing<
Partial<WriteContractParameters>,
{
functionName: TFunctionName
} & UseArgsParam<TContractName, TFunctionName> &
Omit<
WriteContractParameters,
"chainId" | "abi" | "address" | "functionName" | "args"
>
>
type WriteVariables = WriteContractVariables<Abi, string, any[], Config, number>
export type TransactorFuncOptions = {
onBlockConfirmation?: (txnReceipt: TransactionReceipt) => void
blockConfirmations?: number
}
export type WriteContractOptions = MutateOptions<
WriteContractReturnType,
WriteContractErrorType,
WriteVariables,
unknown
> &
TransactorFuncOptions
export type UseEventConfig<
TContractName extends ContractName,
TEventName extends ExtractAbiEventNames<ContractAbi<TContractName>>,
TEvent extends ExtractAbiEvent<
ContractAbi<TContractName>,
TEventName
> = ExtractAbiEvent<ContractAbi<TContractName>, TEventName>,
> = {
contractName: TContractName
} & IsContractDeclarationMissing<
Omit<UseWatchContractEventParameters, "onLogs" | "address" | "abi"> & {
onLogs: (
logs: Simplify<
Omit<Log<bigint, number, any>, "args" | "eventName"> & {
args: Record<string, unknown>
eventName: string
}
>[]
) => void
},
Omit<
UseWatchContractEventParameters<ContractAbi<TContractName>>,
"onLogs" | "address" | "abi"
> & {
onLogs: (
logs: Simplify<
Omit<
Log<bigint, number, false, TEvent, false, [TEvent], TEventName>,
"args"
> & {
args: AbiParametersToPrimitiveTypes<TEvent["inputs"]> &
GetEventArgs<
ContractAbi<TContractName>,
TEventName,
{
IndexedOnly: false
}
>
}
>[]
) => void
}
>
type IndexedEventInputs<
TContractName extends ContractName,
TEventName extends ExtractAbiEventNames<ContractAbi<TContractName>>,
> = Extract<
AbiEventInputs<ContractAbi<TContractName>, TEventName>[number],
{ indexed: true }
>
export type EventFilters<
TContractName extends ContractName,
TEventName extends ExtractAbiEventNames<ContractAbi<TContractName>>,
> = IsContractDeclarationMissing<
any,
IndexedEventInputs<TContractName, TEventName> extends never
? never
: {
[Key in IsContractDeclarationMissing<
any,
IndexedEventInputs<TContractName, TEventName>["name"]
>]?: AbiParameterToPrimitiveType<
Extract<IndexedEventInputs<TContractName, TEventName>, { name: Key }>
>
}
>
export type UseEventHistoryConfig<
TContractName extends ContractName,
TEventName extends ExtractAbiEventNames<ContractAbi<TContractName>>,
TBlockData extends boolean = false,
TTransactionData extends boolean = false,
TReceiptData extends boolean = false,
> = {
contractName: TContractName
eventName: IsContractDeclarationMissing<string, TEventName>
fromBlock: bigint
filters?: EventFilters<TContractName, TEventName>
blockData?: TBlockData
transactionData?: TTransactionData
receiptData?: TReceiptData
watch?: boolean
enabled?: boolean
}
export type UseEventHistoryData<
TContractName extends ContractName,
TEventName extends ExtractAbiEventNames<ContractAbi<TContractName>>,
TBlockData extends boolean = false,
TTransactionData extends boolean = false,
TReceiptData extends boolean = false,
TEvent extends ExtractAbiEvent<
ContractAbi<TContractName>,
TEventName
> = ExtractAbiEvent<ContractAbi<TContractName>, TEventName>,
> =
| IsContractDeclarationMissing<
any[],
{
log: Log<bigint, number, false, TEvent, false, [TEvent], TEventName>
args: AbiParametersToPrimitiveTypes<TEvent["inputs"]> &
GetEventArgs<
ContractAbi<TContractName>,
TEventName,
{
IndexedOnly: false
}
>
block: TBlockData extends true ? Block<bigint, true> : null
receipt: TReceiptData extends true ? GetTransactionReturnType : null
transaction: TTransactionData extends true
? GetTransactionReceiptReturnType
: null
}[]
>
| undefined
export type AbiParameterTuple = Extract<
AbiParameter,
{ type: "tuple" | `tuple[${string}]` }
>