import { type BytesToHexErrorType, bytesToHex, type Hex, type StringToHexErrorType, stringToHex, } from 'viem' import { type ErrorType, UnknownContentTypeError } from '../../errors/utils.js' import type { Prettify } from '../../types/index.js' import { deflateToHex } from '../deflate.js' export type AbiEncodeAs = 'json' | 'zlib' | 'cbor' | 'uri' type AbiContentType = 1 | 2 | 4 | 8 const abiEncodeMap = { json: 1, zlib: 2, cbor: 4, uri: 8, } as const type AbiEncodeMap = typeof abiEncodeMap type GetAbiContentType = AbiEncodeMap[encodeAs] export type EncodeAbiParameters = encodeAs extends 'uri' ? { encodeAs: encodeAs data: string | null } : { encodeAs: encodeAs data: Record | null } export type EncodedAbi = { contentType: contentType encodedData: Hex } export type EncodeAbiReturnType = EncodedAbi // ================================ // Content Type To Encode As // ================================ export type ContentTypeToEncodeAsErrorType = UnknownContentTypeError /** * Converts a content type to an encode as * * @throws {ContentTypeToEncodeAsErrorType} * @param contentType - The content type to convert */ export const contentTypeToEncodeAs = ( contentType: AbiContentType, ): AbiEncodeAs => { switch (contentType) { case 1: return 'json' case 2: return 'zlib' case 4: return 'cbor' case 8: return 'uri' default: throw new UnknownContentTypeError({ contentType }) } } // ================================ // Encode As To Content Type // ================================ export type EncodeAsToContentTypeErrorType = UnknownContentTypeError export const encodeAsToContentType = ( encodeAs: AbiEncodeAs, ): AbiContentType => { const contentType = abiEncodeMap[encodeAs] if (contentType === undefined) { throw new UnknownContentTypeError({ contentType: encodeAs }) } return contentType } // ================================ // Encode Abi // ================================ export type EncodeAbiErrorType = | UnknownContentTypeError | StringToHexErrorType | BytesToHexErrorType | ErrorType export const encodeAbi = async < encodeAs extends AbiEncodeAs, contentType extends GetAbiContentType, >({ encodeAs, data, }: EncodeAbiParameters): Promise< Prettify> > => { let contentType: AbiContentType let encodedData: Hex = '0x' switch (encodeAs) { case 'json': contentType = 1 // may throw StringToHexErrorType if (data) encodedData = stringToHex(JSON.stringify(data)) break case 'zlib': { contentType = 2 if (data) { encodedData = await deflateToHex(data) } break } case 'cbor': { contentType = 4 if (data) { const { encode } = await import('cborg') // may throw BytesToHexErrorType encodedData = bytesToHex(encode(data)) } break } default: { contentType = 8 if (data) { // may throw StringToHexErrorType encodedData = stringToHex(data as string) } break } } return { contentType: contentType as contentType, encodedData } }