UNPKG

@hyperlane-xyz/sdk

Version:

The official SDK for the Hyperlane Network

247 lines 9.93 kB
import { z } from 'zod'; import { isNullish, rootLogger, } from '@hyperlane-xyz/utils'; import { ProtocolAgnositicGasOracleConfigWithTypicalCostSchema } from '../gas/oracle/types.js'; import { ZHash } from '../metadata/customZodTypes.js'; import { OwnableSchema, PausableSchema, } from '../types.js'; // As found in IPostDispatchHook.sol export var OnchainHookType; (function (OnchainHookType) { OnchainHookType[OnchainHookType["UNUSED"] = 0] = "UNUSED"; OnchainHookType[OnchainHookType["ROUTING"] = 1] = "ROUTING"; OnchainHookType[OnchainHookType["AGGREGATION"] = 2] = "AGGREGATION"; OnchainHookType[OnchainHookType["MERKLE_TREE"] = 3] = "MERKLE_TREE"; OnchainHookType[OnchainHookType["INTERCHAIN_GAS_PAYMASTER"] = 4] = "INTERCHAIN_GAS_PAYMASTER"; OnchainHookType[OnchainHookType["FALLBACK_ROUTING"] = 5] = "FALLBACK_ROUTING"; OnchainHookType[OnchainHookType["ID_AUTH_ISM"] = 6] = "ID_AUTH_ISM"; OnchainHookType[OnchainHookType["PAUSABLE"] = 7] = "PAUSABLE"; OnchainHookType[OnchainHookType["PROTOCOL_FEE"] = 8] = "PROTOCOL_FEE"; OnchainHookType[OnchainHookType["DEPRECATED"] = 9] = "DEPRECATED"; OnchainHookType[OnchainHookType["RATE_LIMITED"] = 10] = "RATE_LIMITED"; OnchainHookType[OnchainHookType["ARB_L2_TO_L1"] = 11] = "ARB_L2_TO_L1"; OnchainHookType[OnchainHookType["OP_L2_TO_L1"] = 12] = "OP_L2_TO_L1"; OnchainHookType[OnchainHookType["MAILBOX_DEFAULT_HOOK"] = 13] = "MAILBOX_DEFAULT_HOOK"; OnchainHookType[OnchainHookType["AMOUNT_ROUTING"] = 14] = "AMOUNT_ROUTING"; OnchainHookType[OnchainHookType["CCTP"] = 15] = "CCTP"; OnchainHookType[OnchainHookType["TIMELOCK_ROUTING"] = 16] = "TIMELOCK_ROUTING"; OnchainHookType[OnchainHookType["PREDICATE_ROUTER_WRAPPER"] = 17] = "PREDICATE_ROUTER_WRAPPER"; })(OnchainHookType || (OnchainHookType = {})); export const HookType = { /** * Retained for backwards compatibility with pre-deployed hooks that don't fit * a named type. Excluded from `DeployableHookType` — cannot be deployed via * `HyperlaneHookDeployer`. New code should use a specific named hook type. */ CUSTOM: 'custom', MERKLE_TREE: 'merkleTreeHook', INTERCHAIN_GAS_PAYMASTER: 'interchainGasPaymaster', AGGREGATION: 'aggregationHook', PROTOCOL_FEE: 'protocolFee', OP_STACK: 'opStackHook', ROUTING: 'domainRoutingHook', FALLBACK_ROUTING: 'fallbackRoutingHook', AMOUNT_ROUTING: 'amountRoutingHook', PAUSABLE: 'pausableHook', ARB_L2_TO_L1: 'arbL2ToL1Hook', MAILBOX_DEFAULT: 'defaultHook', CCIP: 'ccipHook', /** * References a pre-deployed CCTP hook by address. Excluded from * `DeployableHookType` — not deployed via `HyperlaneHookDeployer`; the * `EvmHookModule.deploy` path just connects to `config.address`. */ CCTP: 'cctpHook', /** * Rate-limits outbound token volume on the origin chain at dispatch time. * Warp-route only. Not valid for core required/default hooks. */ RATE_LIMITED: 'rateLimitedHook', UNKNOWN: 'unknownHook', PREDICATE: 'predicateHook', }; export const HookTypeToContractNameMap = { [HookType.MERKLE_TREE]: 'merkleTreeHook', [HookType.INTERCHAIN_GAS_PAYMASTER]: 'interchainGasPaymaster', [HookType.AGGREGATION]: 'staticAggregationHook', [HookType.PROTOCOL_FEE]: 'protocolFee', [HookType.OP_STACK]: 'opStackHook', [HookType.ROUTING]: 'domainRoutingHook', [HookType.FALLBACK_ROUTING]: 'fallbackDomainRoutingHook', [HookType.AMOUNT_ROUTING]: 'amountRoutingHook', [HookType.PAUSABLE]: 'pausableHook', [HookType.ARB_L2_TO_L1]: 'arbL2ToL1Hook', [HookType.MAILBOX_DEFAULT]: 'defaultHook', [HookType.CCIP]: 'ccipHook', [HookType.RATE_LIMITED]: 'rateLimitedHook', }; // Hook types that can be updated in-place export const MUTABLE_HOOK_TYPE = [ HookType.INTERCHAIN_GAS_PAYMASTER, HookType.PROTOCOL_FEE, HookType.ROUTING, HookType.FALLBACK_ROUTING, HookType.PAUSABLE, HookType.RATE_LIMITED, ]; export const ProtocolFeeSchema = OwnableSchema.extend({ type: z.literal(HookType.PROTOCOL_FEE), beneficiary: z.string(), maxProtocolFee: z.string(), protocolFee: z.string(), }); export const MerkleTreeSchema = z.object({ type: z.literal(HookType.MERKLE_TREE), }); export const PredicateHookSchema = z.object({ type: z.literal(HookType.PREDICATE), address: z.string(), }); export const PausableHookSchema = PausableSchema.extend({ type: z.literal(HookType.PAUSABLE), }); export const MailboxDefaultHookSchema = z.object({ type: z.literal(HookType.MAILBOX_DEFAULT), }); export const OpStackHookSchema = OwnableSchema.extend({ type: z.literal(HookType.OP_STACK), nativeBridge: z.string(), destinationChain: z.string(), }); export const ArbL2ToL1HookSchema = z.object({ type: z.literal(HookType.ARB_L2_TO_L1), arbSys: z .string() .describe('precompile for sending messages to L1, interface here: https://github.com/OffchainLabs/nitro-contracts/blob/90037b996509312ef1addb3f9352457b8a99d6a6/src/precompiles/ArbSys.sol#L12'), bridge: z .string() .optional() .describe('address of the bridge contract on L1, optional only needed for non @arbitrum/sdk chains'), destinationChain: z.string(), childHook: z.lazy(() => HookConfigSchema), }); export const IgpSchema = OwnableSchema.extend({ type: z.literal(HookType.INTERCHAIN_GAS_PAYMASTER), beneficiary: z.string(), oracleKey: z.string(), overhead: z.record(z.number()), oracleConfig: z.record(ProtocolAgnositicGasOracleConfigWithTypicalCostSchema), quoteSigners: z.array(z.string()).optional(), contractVersion: z.string().optional(), }); export const DomainRoutingHookConfigSchema = z.lazy(() => OwnableSchema.extend({ type: z.literal(HookType.ROUTING), domains: z.record(HookConfigSchema), })); export const FallbackRoutingHookConfigSchema = z.lazy(() => OwnableSchema.extend({ type: z.literal(HookType.FALLBACK_ROUTING), domains: z.record(HookConfigSchema), fallback: HookConfigSchema, })); export const AmountRoutingHookConfigSchema = z.lazy(() => z.object({ type: z.literal(HookType.AMOUNT_ROUTING), threshold: z.number(), lowerHook: HookConfigSchema, upperHook: HookConfigSchema, })); export const AggregationHookConfigSchema = z.lazy(() => z.object({ type: z.literal(HookType.AGGREGATION), hooks: z.array(HookConfigSchema), })); export const CCIPHookSchema = z.object({ type: z.literal(HookType.CCIP), destinationChain: z.string(), }); export const CctpHookSchema = z.object({ type: z.literal(HookType.CCTP), address: ZHash, }); export const UnknownHookSchema = z .object({ type: z.literal(HookType.UNKNOWN), }) .passthrough(); export const RateLimitedHookSchema = OwnableSchema.extend({ type: z.literal(HookType.RATE_LIMITED), maxCapacity: z .string() .regex(/^\d+$/, 'maxCapacity must be a base-10 integer string'), }) .refine((val) => BigInt(val.maxCapacity) >= 86400n, { message: 'maxCapacity must be at least 86400', path: ['maxCapacity'], }) .transform((val) => { const capacity = BigInt(val.maxCapacity); if (capacity % 86400n !== 0n) { const rounded = ((capacity / 86400n) * 86400n).toString(); rootLogger.warn(`RateLimitedHook maxCapacity ${val.maxCapacity} is not divisible by 86400; rounding down to ${rounded}`); return { ...val, maxCapacity: rounded }; } return val; }); const KnownHookTypes = Object.values(HookType).filter((t) => t !== HookType.UNKNOWN); /** * Recursively normalizes unknown hook type values to HookType.UNKNOWN. * Use this before parsing with HookConfigSchema when configs may contain * hook types not yet known to this SDK version. * * Note: String address configs (e.g., "0x...") are passed through unchanged * since they represent deployed hook addresses, not hook type configs. */ export function normalizeUnknownHookTypes(config) { // Handle nullish values and primitives (including string addresses) if (isNullish(config) || typeof config !== 'object') { return config; } if (Array.isArray(config)) { return config.map(normalizeUnknownHookTypes); } // At this point, config must be a non-null object (not array, not primitive) const obj = config; const normalized = {}; for (const [key, value] of Object.entries(obj)) { if (key === 'type' && typeof value === 'string') { normalized[key] = KnownHookTypes.includes(value) ? value : HookType.UNKNOWN; } else if (typeof value === 'object' && !isNullish(value)) { normalized[key] = normalizeUnknownHookTypes(value); } else { normalized[key] = value; } } return normalized; } export const HookConfigSchema = z.union([ ZHash, ProtocolFeeSchema, PausableHookSchema, OpStackHookSchema, MerkleTreeSchema, IgpSchema, DomainRoutingHookConfigSchema, FallbackRoutingHookConfigSchema, AmountRoutingHookConfigSchema, AggregationHookConfigSchema, ArbL2ToL1HookSchema, MailboxDefaultHookSchema, CCIPHookSchema, CctpHookSchema, RateLimitedHookSchema, UnknownHookSchema, PredicateHookSchema, ]); /** * Forward-compatible hook config schema that normalizes unknown hook types. * Use this instead of HookConfigSchema when parsing configs that may contain * hook types added in newer registry versions. */ export const SafeParseHookConfigSchema = z.preprocess(normalizeUnknownHookTypes, HookConfigSchema); // TODO: deprecate in favor of CoreConfigSchema export const HooksConfigSchema = z.object({ default: HookConfigSchema, required: HookConfigSchema, }); export const HooksConfigMapSchema = z.record(HooksConfigSchema); //# sourceMappingURL=types.js.map