|
|
|
@ -20,6 +20,7 @@ import { |
|
|
|
|
assert, |
|
|
|
|
concurrentMap, |
|
|
|
|
eqAddress, |
|
|
|
|
getLogLevel, |
|
|
|
|
rootLogger, |
|
|
|
|
} from '@hyperlane-xyz/utils'; |
|
|
|
|
|
|
|
|
@ -45,7 +46,9 @@ import { |
|
|
|
|
export type DerivedHookConfig = WithAddress<Exclude<HookConfig, Address>>; |
|
|
|
|
|
|
|
|
|
export interface HookReader { |
|
|
|
|
deriveHookConfig(address: Address): Promise<WithAddress<HookConfig>>; |
|
|
|
|
deriveHookConfig( |
|
|
|
|
address: Address, |
|
|
|
|
): Promise<WithAddress<HookConfig> | undefined>; |
|
|
|
|
deriveMerkleTreeConfig( |
|
|
|
|
address: Address, |
|
|
|
|
): Promise<WithAddress<MerkleTreeHookConfig>>; |
|
|
|
@ -84,35 +87,51 @@ export class EvmHookReader implements HookReader { |
|
|
|
|
this.provider = multiProvider.getProvider(chain); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
async deriveHookConfig(address: Address): Promise<DerivedHookConfig> { |
|
|
|
|
const hook = IPostDispatchHook__factory.connect(address, this.provider); |
|
|
|
|
const onchainHookType: OnchainHookType = await hook.hookType(); |
|
|
|
|
this.logger.debug('Deriving HookConfig', { address, onchainHookType }); |
|
|
|
|
|
|
|
|
|
switch (onchainHookType) { |
|
|
|
|
case OnchainHookType.ROUTING: |
|
|
|
|
return this.deriveDomainRoutingConfig(address); |
|
|
|
|
case OnchainHookType.AGGREGATION: |
|
|
|
|
return this.deriveAggregationConfig(address); |
|
|
|
|
case OnchainHookType.MERKLE_TREE: |
|
|
|
|
return this.deriveMerkleTreeConfig(address); |
|
|
|
|
case OnchainHookType.INTERCHAIN_GAS_PAYMASTER: |
|
|
|
|
return this.deriveIgpConfig(address); |
|
|
|
|
case OnchainHookType.FALLBACK_ROUTING: |
|
|
|
|
return this.deriveFallbackRoutingConfig(address); |
|
|
|
|
case OnchainHookType.PAUSABLE: |
|
|
|
|
return this.derivePausableConfig(address); |
|
|
|
|
case OnchainHookType.PROTOCOL_FEE: |
|
|
|
|
return this.deriveProtocolFeeConfig(address); |
|
|
|
|
// ID_AUTH_ISM could be OPStackHook, ERC5164Hook or LayerZeroV2Hook
|
|
|
|
|
// For now assume it's OP_STACK
|
|
|
|
|
case OnchainHookType.ID_AUTH_ISM: |
|
|
|
|
return this.deriveOpStackConfig(address); |
|
|
|
|
default: |
|
|
|
|
throw new Error( |
|
|
|
|
`Unsupported HookType: ${OnchainHookType[onchainHookType]}`, |
|
|
|
|
); |
|
|
|
|
async deriveHookConfig( |
|
|
|
|
address: Address, |
|
|
|
|
): Promise<DerivedHookConfig | undefined> { |
|
|
|
|
let onchainHookType = undefined; |
|
|
|
|
try { |
|
|
|
|
const hook = IPostDispatchHook__factory.connect(address, this.provider); |
|
|
|
|
this.logger.debug('Deriving HookConfig', { address }); |
|
|
|
|
|
|
|
|
|
// Temporarily turn off SmartProvider logging
|
|
|
|
|
// Provider errors are expected because deriving will call methods that may not exist in the Bytecode
|
|
|
|
|
this.setSmartProviderLogLevel('silent'); |
|
|
|
|
onchainHookType = await hook.hookType(); |
|
|
|
|
|
|
|
|
|
switch (onchainHookType) { |
|
|
|
|
case OnchainHookType.ROUTING: |
|
|
|
|
return this.deriveDomainRoutingConfig(address); |
|
|
|
|
case OnchainHookType.AGGREGATION: |
|
|
|
|
return this.deriveAggregationConfig(address); |
|
|
|
|
case OnchainHookType.MERKLE_TREE: |
|
|
|
|
return this.deriveMerkleTreeConfig(address); |
|
|
|
|
case OnchainHookType.INTERCHAIN_GAS_PAYMASTER: |
|
|
|
|
return this.deriveIgpConfig(address); |
|
|
|
|
case OnchainHookType.FALLBACK_ROUTING: |
|
|
|
|
return this.deriveFallbackRoutingConfig(address); |
|
|
|
|
case OnchainHookType.PAUSABLE: |
|
|
|
|
return this.derivePausableConfig(address); |
|
|
|
|
case OnchainHookType.PROTOCOL_FEE: |
|
|
|
|
return this.deriveProtocolFeeConfig(address); |
|
|
|
|
// ID_AUTH_ISM could be OPStackHook, ERC5164Hook or LayerZeroV2Hook
|
|
|
|
|
// For now assume it's OP_STACK
|
|
|
|
|
case OnchainHookType.ID_AUTH_ISM: |
|
|
|
|
return this.deriveOpStackConfig(address); |
|
|
|
|
default: |
|
|
|
|
throw new Error( |
|
|
|
|
`Unsupported HookType: ${OnchainHookType[onchainHookType]}`, |
|
|
|
|
); |
|
|
|
|
} |
|
|
|
|
} catch (e) { |
|
|
|
|
this.logger.debug( |
|
|
|
|
`Failed to derive ${onchainHookType} hook (${address}): ${e}`, |
|
|
|
|
); |
|
|
|
|
} finally { |
|
|
|
|
this.setSmartProviderLogLevel(getLogLevel()); // returns to original level defined by rootLogger
|
|
|
|
|
} |
|
|
|
|
return undefined; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
async deriveMerkleTreeConfig( |
|
|
|
@ -134,10 +153,14 @@ export class EvmHookReader implements HookReader { |
|
|
|
|
assert((await hook.hookType()) === OnchainHookType.AGGREGATION); |
|
|
|
|
|
|
|
|
|
const hooks = await hook.hooks(ethers.constants.AddressZero); |
|
|
|
|
const hookConfigs = await concurrentMap( |
|
|
|
|
const hookConfigs: DerivedHookConfig[] = await concurrentMap( |
|
|
|
|
this.concurrency, |
|
|
|
|
hooks, |
|
|
|
|
async (hook) => this.deriveHookConfig(hook), |
|
|
|
|
async (hook) => { |
|
|
|
|
const hookConfig = await this.deriveHookConfig(hook); |
|
|
|
|
assert(hookConfig, `No hook config found for ${hook}.`); |
|
|
|
|
return hookConfig; |
|
|
|
|
}, |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
return { |
|
|
|
@ -295,6 +318,10 @@ export class EvmHookReader implements HookReader { |
|
|
|
|
|
|
|
|
|
const fallbackHook = await hook.fallbackHook(); |
|
|
|
|
const fallbackHookConfig = await this.deriveHookConfig(fallbackHook); |
|
|
|
|
assert( |
|
|
|
|
fallbackHookConfig, |
|
|
|
|
`No fallback hook config found for ${fallbackHook}.`, |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
return { |
|
|
|
|
owner, |
|
|
|
@ -316,7 +343,9 @@ export class EvmHookReader implements HookReader { |
|
|
|
|
try { |
|
|
|
|
const domainHook = await hook.hooks(domainId); |
|
|
|
|
if (domainHook !== ethers.constants.AddressZero) { |
|
|
|
|
domainHooks[chainName] = await this.deriveHookConfig(domainHook); |
|
|
|
|
const hookConfig = await this.deriveHookConfig(domainHook); |
|
|
|
|
assert(hookConfig, `No hook config found for ${domainHook}.`); |
|
|
|
|
domainHooks[chainName] = hookConfig; |
|
|
|
|
} |
|
|
|
|
} catch (error) { |
|
|
|
|
this.logger.debug( |
|
|
|
@ -345,4 +374,16 @@ export class EvmHookReader implements HookReader { |
|
|
|
|
type: HookType.PAUSABLE, |
|
|
|
|
}; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Conditionally sets the log level for a smart provider. |
|
|
|
|
* |
|
|
|
|
* @param level - The log level to set, e.g. 'debug', 'info', 'warn', 'error'. |
|
|
|
|
*/ |
|
|
|
|
protected setSmartProviderLogLevel(level: string) { |
|
|
|
|
if ('setLogLevel' in this.provider) { |
|
|
|
|
//@ts-ignore
|
|
|
|
|
this.provider.setLogLevel(level); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|