UNPKG

@alchemy/aa-core

Version:

viem based SDK that enables interactions with ERC-4337 Smart Accounts. ABIs are based off the definitions generated in @account-abstraction/contracts

174 lines (158 loc) 4.77 kB
import type { Chain } from "viem"; import { toHex } from "viem"; import * as chains from "viem/chains"; import * as alchemyChains from "../chains/index.js"; import type { PromiseOrValue } from "../types.js"; import type { RecordableKeys } from "./types.js"; export const AlchemyChainMap = new Map<number, Chain>( Object.values(alchemyChains).map((c) => [c.id, c]) ); /** * Utility method for converting a chainId to a {@link Chain} object * * @param chainId - the chainId to convert * @returns a {@link Chain} object for the given chainId * @throws if the chainId is not found */ export const getChain = (chainId: number): Chain => { for (const chain of Object.values(chains)) { if (chain.id === chainId) { return AlchemyChainMap.get(chain.id) ?? chain; } } throw new Error("could not find chain"); }; /** * Utility function that allows for piping a series of async functions together * * @param fns - functions to pipe * @returns result of the pipe */ export const asyncPipe = <S, O, F>(...fns: ((s: S, o?: O, f?: F) => Promise<S>)[]) => async (s: S, o?: O, f?: F) => { let result = s; for (const fn of fns) { result = await fn(result, o, f); } return result; }; // based on @ethersproject/properties, but pulled in here to minize the dependency on ethers export type Deferrable<T> = { [K in keyof T]: PromiseOrValue<T[K]>; }; /** * Await all of the properties of a {@link Deferrable} object * * @param object - a {@link Deferrable} object * @returns the object with its properties resolved */ export async function resolveProperties<T>(object: Deferrable<T>): Promise<T> { const promises = Object.keys(object).map((key) => { const value = object[key as keyof Deferrable<T>]; return Promise.resolve(value).then((v) => ({ key: key, value: v })); }); const results = await Promise.all(promises); return filterUndefined<T>( results.reduce((accum, curr) => { accum[curr.key as keyof T] = curr.value; return accum; }, {} as T) ); } /** * Recursively converts all values in an object to hex strings * * @param obj - obj to deep hexlify * @returns object with all of its values hexlified */ export function deepHexlify(obj: any): any { if (typeof obj === "function") { return undefined; } if (obj == null || typeof obj === "string" || typeof obj === "boolean") { return obj; } else if (typeof obj === "bigint") { return toHex(obj); } else if (obj._isBigNumber != null || typeof obj !== "object") { return toHex(obj).replace(/^0x0/, "0x"); } if (Array.isArray(obj)) { return obj.map((member) => deepHexlify(member)); } return Object.keys(obj).reduce( (set, key) => ({ ...set, [key]: deepHexlify(obj[key]), }), {} ); } // borrowed from ethers.js export function defineReadOnly<T, K extends keyof T>( object: T, key: K, value: T[K] ): void { Object.defineProperty(object, key, { enumerable: true, value: value, writable: false, }); } export function filterUndefined<T>(obj: T): T { for (const key in obj) { if (obj[key] == null) { delete obj[key]; } } return obj as T; } export function pick(obj: Record<string, unknown>, keys: string | string[]) { return Object.keys(obj) .filter((k) => keys.includes(k)) .reduce((res, k) => Object.assign(res, { [k]: obj[k] }), {}); } /** * Utility method for checking if the passed in values are all equal (strictly) * * @param params - values to check * @returns a boolean indicating if all values are the same * @throws if no values are passed in */ export const allEqual = (...params: any[]): boolean => { if (params.length === 0) { throw new Error("no values passed in"); } return params.every((v) => v === params[0]); }; /** * Utility method for checking the condition and return the value if condition holds true, undefined if not. * * @param condition - condition to check * @param value - value to return when condition holds true * @returns the value if condition holds true, undefined if not */ export const conditionalReturn = <T>( condition: Promise<boolean>, value: () => Promise<T> ): Promise<T | undefined> => condition.then((t) => (t ? value() : undefined)); export const toRecord = < T extends { [K in RecordableKeys<T>]: string | number | symbol }, K extends RecordableKeys<T>, V >( array: T[], selector: K, fn: (item: T) => V ): Record<T[K], V> => array.reduce((acc, item) => { acc[item[selector]] = fn(item); return acc; }, {} as Record<T[K], V>); export * from "./bigint.js"; export * from "./bytes.js"; export * from "./defaults.js"; export * from "./schema.js"; export type * from "./types.js"; export * from "./userop.js";