import { Address, Domain, EvmChainId, ProtocolType } from '@hyperlane-xyz/utils'; import { CCIPContractCache } from '../ccip/utils.js'; import { HyperlaneAddresses } from '../contracts/types.js'; import { HyperlaneModule, HyperlaneModuleParams } from '../core/AbstractHyperlaneModule.js'; import { ProxyFactoryFactories } from '../deploy/contracts.js'; import { ContractVerifier } from '../deploy/verify/ContractVerifier.js'; import { TokenFeeReaderParams } from '../fee/EvmTokenFeeReader.js'; import { MultiProvider } from '../providers/MultiProvider.js'; import { AnnotatedEV5Transaction } from '../providers/ProviderType.js'; import { ChainName, ChainNameOrId } from '../types.js'; import { EvmWarpRouteReader } from './EvmWarpRouteReader.js'; import { DerivedTokenRouterConfig, HypTokenRouterConfig } from './types.js'; type WarpRouteAddresses = HyperlaneAddresses & { deployedTokenRoute: Address; }; export declare const MAX_LEGACY_BRIDGE_APPROVAL_VERSION = "11.3.1"; /** * Whether `approveTokenForBridge` GRANTS a standing max allowance on the given * contract version (legacy impls) rather than REVOKING it (new impls). The * selector is overloaded by implementation version. */ export declare function bridgeApprovalGrantsMaxAllowance(contractVersion: string): boolean; export type WarpUpdateResult = { txs: AnnotatedEV5Transaction[]; feeTxs: AnnotatedEV5Transaction[]; ownershipTxs: AnnotatedEV5Transaction[]; }; /** Per-chain transaction groups used by warp apply. */ export type WarpUpdatePhases = { /** Proxy implementation upgrades. Must precede everything else. */ upgradeTxs: AnnotatedEV5Transaction[]; /** Shared hybrid instance mutations. Must precede its router installation. */ instanceTxs: AnnotatedEV5Transaction[]; /** Installs the router's hook (and any predicate wrapper). */ hookTxs: AnnotatedEV5Transaction[]; /** Installs the router's ISM; runs first only when removing delayed flow. */ ismTxs: AnnotatedEV5Transaction[]; /** Everything else the router owner signs: enrollment, gas, rebalancers, … */ txs: AnnotatedEV5Transaction[]; feeTxs: AnnotatedEV5Transaction[]; ownershipTxs: AnnotatedEV5Transaction[]; /** * The shared hybrid hook/ISM instance this update installs on both surfaces, * when the config declares one. Callers use it for cross-chain counterpart * enrollment before either router surface changes in this chain's batch. */ hybridIsm?: Address; /** An installed delayed-flow router is absent from the target config. */ removesDelayedFlowRouter?: boolean; }; export declare class EvmWarpModule extends HyperlaneModule { protected readonly multiProvider: MultiProvider; protected readonly ccipContractCache?: CCIPContractCache | undefined; protected readonly contractVerifier?: ContractVerifier | undefined; private static readonly deployedTimelockByProvider; protected logger: import("pino").pino.Logger; reader: EvmWarpRouteReader; readonly chainName: ChainName; readonly chainId: EvmChainId; readonly domainId: Domain; constructor(multiProvider: MultiProvider, args: HyperlaneModuleParams, ccipContractCache?: CCIPContractCache | undefined, contractVerifier?: ContractVerifier | undefined); /** * Retrieves the token router configuration for the specified address. * * @param address - The address to derive the token router configuration from. * @returns A promise that resolves to the token router configuration. */ read(): Promise; private timelockMatchesConfig; private cachedTimelockMatchesConfig; private configWithTimelockProxyAdminOwner; private timelockDeploymentCacheKey; private static deployedTimelockByConfig; /** * Plans a Warp Route update as per-chain transaction groups. * * IMPORTANT — irreversible side effects when expectedConfig includes `predicateWrapper`: * The PredicateRouterWrapper contract is deployed on-chain during planning (before this * method returns). If the returned transactions are never submitted, the wrapper is * orphaned. See PredicateWrapperDeployer.deployAndConfigure for details. * * IMPORTANT — irreversible side effects when expectedConfig includes `timelock`: * A TimelockController may be deployed on-chain during planning so the returned ownership * transactions can transfer ProxyAdmin ownership to it. The deployment address is cached * per MultiProvider, revalidated, and reused across retries for the same * chain/ProxyAdmin/timelock config, but a declined or externally persisted * transaction plan can still leave an untracked timelock deployment. * * @param expectedConfig - The configuration for the token router to be updated. * Used by warp apply to assemble one ordered batch for this chain. */ updatePhases(expectedConfig: HypTokenRouterConfig, tokenReaderParams?: Partial): Promise; /** * Main-compatible split: router-owner work, fee-owner work, then ownership. */ updateSplit(expectedConfig: HypTokenRouterConfig, tokenReaderParams?: Partial): Promise; /** Returns a flat, ordered transaction array suitable for one submitter. */ update(expectedConfig: HypTokenRouterConfig, tokenReaderParams?: Partial): Promise; /** * Validates hybrid composition and fee-hook transitions before update * planning reaches any operation that may deploy a contract. */ private planHybridUpdate; /** * Reuses or deploys the one hybrid leaf declared on both config surfaces. * Parent trees only ever receive the returned address, preventing duplicate * bucket state. Instance mutations are returned separately so counterpart * enrollment can precede either router-surface change in this chain's batch. */ private resolveHybridInstance; /** * Create a transaction to update the remote routers for the Warp Route contract. * * @param actualConfig - The on-chain router configuration, including the remoteRouters array. * @param expectedConfig - The expected token router configuration. * @returns A array with a single Ethereum transaction that need to be executed to enroll the routers */ createEnrollRemoteRoutersUpdateTxs(actualConfig: DerivedTokenRouterConfig, expectedConfig: HypTokenRouterConfig): AnnotatedEV5Transaction[]; createUnenrollRemoteRoutersUpdateTxs(actualConfig: DerivedTokenRouterConfig, expectedConfig: HypTokenRouterConfig): AnnotatedEV5Transaction[]; createAddRebalancersUpdateTxs(actualConfig: DerivedTokenRouterConfig, expectedConfig: HypTokenRouterConfig): AnnotatedEV5Transaction[]; createRemoveRebalancersUpdateTxs(actualConfig: DerivedTokenRouterConfig, expectedConfig: HypTokenRouterConfig): AnnotatedEV5Transaction[]; /** * Create transactions to enroll CrossCollateralRouter routers. */ createEnrollCrossCollateralRoutersTxs(actualConfig: DerivedTokenRouterConfig, expectedConfig: HypTokenRouterConfig): AnnotatedEV5Transaction[]; /** * Create transactions to unenroll CrossCollateralRouter routers. */ createUnenrollCrossCollateralRoutersTxs(actualConfig: DerivedTokenRouterConfig, expectedConfig: HypTokenRouterConfig): AnnotatedEV5Transaction[]; private toCanonicalRouterId; /** * Grants standing ERC20 allowances declared in `allowedRebalancingBridges[].approvedTokens`. * * Only legacy (pre-atomic-rebalancing) routers need explicit grants: their * `approveTokenForBridge` sets max allowance. New impls grant an exact temporary * allowance per rebalance and the same selector REVOKES, so emitting grants there * would be wrong. Gated on the on-chain version being legacy, mirroring * `createRevokeStaleBridgeAllowancesTxs`. */ getAllowedBridgesApprovalTxs(actualConfig: DerivedTokenRouterConfig, expectedConfig: HypTokenRouterConfig): Promise; createAddAllowedBridgesUpdateTxs(actualConfig: DerivedTokenRouterConfig, expectedConfig: HypTokenRouterConfig): Promise; createRemoveBridgesTxs(actualConfig: DerivedTokenRouterConfig, expectedConfig: HypTokenRouterConfig): AnnotatedEV5Transaction[]; createAddRebalanceTargetsUpdateTxs(actualConfig: DerivedTokenRouterConfig, expectedConfig: HypTokenRouterConfig): AnnotatedEV5Transaction[]; createRemoveRebalanceTargetsTxs(actualConfig: DerivedTokenRouterConfig, expectedConfig: HypTokenRouterConfig): AnnotatedEV5Transaction[]; createSetRecipientsUpdateTxs(actualConfig: DerivedTokenRouterConfig, expectedConfig: HypTokenRouterConfig): AnnotatedEV5Transaction[]; createRemoveRecipientsTxs(actualConfig: DerivedTokenRouterConfig, expectedConfig: HypTokenRouterConfig): AnnotatedEV5Transaction[]; /** * Revokes legacy standing ERC20 allowances for bridges that remain allowlisted * after an in-place upgrade. * * Pre-atomic-rebalancing routers granted `type(uint256).max` to every enrolled * bridge in `_addBridge` (the collateral token) and, via the legacy * `approvedTokens` grant path, to arbitrary tokens. After upgrading, bridges that * are removed have their allowance revoked on-chain by `_removeBridge`, and * newly-added bridges never received a legacy allowance. Bridges that REMAIN * allowlisted, however, keep those stale max allowances until the next rebalance. * This method emits txs that set the collateral token AND any configured * `approvedTokens` allowances back to zero so an allowlisted bridge has no * out-of-band transferFrom power over the router balance. * * `approveTokenForBridge` only has revoke semantics on the new implementation; * on legacy impls the same selector GRANTS max. Revoke txs are therefore emitted * unless the router is on a legacy impl that is not being upgraded this run, so * they always execute against the new revoke-semantics impl — whether this run * upgrades it in place or it was already upgraded (which keeps cleanup retryable * if an earlier run upgraded but its revoke txs never executed). */ createRevokeStaleBridgeAllowancesTxs(actualConfig: DerivedTokenRouterConfig, expectedConfig: HypTokenRouterConfig, upgradeScheduled: boolean): Promise; createAddRemoteOutputAssetsTxs(actualConfig: DerivedTokenRouterConfig, expectedConfig: HypTokenRouterConfig): AnnotatedEV5Transaction[]; createRemoveRemoteOutputAssetsTxs(actualConfig: DerivedTokenRouterConfig, expectedConfig: HypTokenRouterConfig): AnnotatedEV5Transaction[]; createUpdateEverclearFeeParamsTxs(actualConfig: DerivedTokenRouterConfig, expectedConfig: HypTokenRouterConfig): AnnotatedEV5Transaction[]; createRemoveEverclearFeeParamsTxs(actualConfig: DerivedTokenRouterConfig, expectedConfig: HypTokenRouterConfig): AnnotatedEV5Transaction[]; /** * Create a transaction to update the remote routers for the Warp Route contract. * * @param actualConfig - The on-chain router configuration, including the remoteRouters array. * @param expectedConfig - The expected token router configuration. * @returns A array with a single Ethereum transaction that need to be executed to enroll the routers */ createSetDestinationGasUpdateTxs(actualConfig: DerivedTokenRouterConfig, expectedConfig: HypTokenRouterConfig): AnnotatedEV5Transaction[]; /** * Create transactions to update an existing ISM config, or deploy a new ISM and return a tx to setInterchainSecurityModule * * @param actualConfig - The on-chain router configuration, including the ISM configuration, and address. * @param expectedConfig - The expected token router configuration, including the ISM configuration. * @returns Ethereum transaction that need to be executed to update the ISM configuration. */ createIsmUpdateTxs(actualConfig: DerivedTokenRouterConfig, expectedConfig: HypTokenRouterConfig, opaqueHybridAddress?: Address): Promise; createHookUpdateTxs(actualConfig: DerivedTokenRouterConfig, expectedConfig: HypTokenRouterConfig): Promise; /** * Deploys hook updates and predicate wrapper together so the post-update hook address * is available to deployAndConfigure without a stale on-chain read. */ createHookAndPredicateUpdateTxs(actualConfig: DerivedTokenRouterConfig, expectedConfig: HypTokenRouterConfig, opaqueHybridAddress?: Address): Promise; /** * Searches the current on-chain hook tree for a PredicateRouterWrapper that * matches by registry and policyId. Returns the wrapper address and its current * on-chain owner when found, undefined otherwise. * * Uses unbounded recursion into aggregation hooks (consistent with * EvmTokenAdapter.findPredicateWrapperInHook and EvmWarpRouteReader.findPredicateAddressInHook). */ private findDeployedPredicateWrapper; /** * Recursively searches a hook tree for a matching PredicateRouterWrapper. * Descends into StaticAggregationHook sub-hooks without depth limit. */ private searchPredicateInHook; /** * Checks whether a single hook address is a PredicateRouterWrapper matching * the warp route and expected config. Returns the match or undefined. */ private matchPredicateWrapper; /** * Check if predicate wrapper is already deployed with fully matching config * (registry, policyId, and owner). * * @param actualConfig - The on-chain router configuration. * @param expectedPredicateConfig - The expected predicate wrapper configuration. * @returns True if wrapper is deployed with all fields matching, false otherwise. */ isPredicateWrapperDeployed(actualConfig: DerivedTokenRouterConfig, expectedPredicateConfig: { predicateRegistry: string; policyId: string; owner: string; }): Promise; /** * Create transactions to deploy predicate wrapper and update hook. * * @param actualConfig - The on-chain router configuration. * @param expectedConfig - The expected token router configuration. * @returns transactions to execute and whether a new wrapper is being deployed. * deploysNewWrapper=true means the predicate emits its own setHook(aggregation) * that supersedes any hook update in the same batch. */ createPredicateWrapperUpdateTxs(actualConfig: DerivedTokenRouterConfig, expectedConfig: HypTokenRouterConfig, pendingHookAddress?: Address): Promise<{ transactions: AnnotatedEV5Transaction[]; deploysNewWrapper: boolean; }>; createFeeHookUpdateTxs(actualConfig: DerivedTokenRouterConfig, expectedConfig: HypTokenRouterConfig): AnnotatedEV5Transaction[]; /** * Create transactions to update token fee configuration. * * @param actualConfig - The on-chain router configuration. * @param expectedConfig - The expected token router configuration. * @returns Ethereum transactions that need to be executed to update the token fee. * * @remarks * The returned transactions may include both `setFeeRecipient` (gated by the * token-router owner) and fee-contract config calls (gated by the fee-contract * owner). When routing these to a dedicated `feeSubmitter`, that submitter * must own both the token router and the fee contract. */ createTokenFeeUpdateTxs(actualConfig: DerivedTokenRouterConfig, expectedConfig: HypTokenRouterConfig, tokenReaderParams?: Partial): Promise; /** * Transfer ownership of an existing Warp route with a given config. * * @param actualConfig - The on-chain router configuration. * @param expectedConfig - The expected token router configuration. * @returns Ethereum transaction that need to be executed to update the owner. */ createOwnershipUpdateTxs(actualConfig: DerivedTokenRouterConfig, expectedConfig: HypTokenRouterConfig): AnnotatedEV5Transaction[]; /** * Updates or deploys the ISM using the provided configuration. * * @returns Object with deployedIsm address, and update Transactions */ deployOrUpdateIsm(actualConfig: DerivedTokenRouterConfig, expectedConfig: HypTokenRouterConfig, opaqueHybridAddress?: Address): Promise<{ deployedIsm: Address; updateTransactions: AnnotatedEV5Transaction[]; }>; /** * Creates a transaction to upgrade the Warp Route implementation if the package version is below specified version. * * @param actualConfig - The current on-chain configuration * @param expectedConfig - The expected configuration * @returns An array of transactions to upgrade the implementation if needed */ upgradeWarpRouteImplementationTx(actualConfig: DerivedTokenRouterConfig, expectedConfig: HypTokenRouterConfig): Promise; createSetMaxFeePpmTxs(actualConfig: DerivedTokenRouterConfig, expectedConfig: HypTokenRouterConfig): AnnotatedEV5Transaction[]; /** * Deploys the Warp Route. * * @param chain - The chain to deploy the module on. * @param config - The configuration for the token router. * @param multiProvider - The multi-provider instance to use. * @returns A new instance of the EvmERC20WarpHyperlaneModule. */ static create(params: { chain: ChainNameOrId; config: HypTokenRouterConfig; multiProvider: MultiProvider; ccipContractCache?: CCIPContractCache; contractVerifier?: ContractVerifier; proxyFactoryFactories: HyperlaneAddresses; }): Promise; } export {}; //# sourceMappingURL=EvmWarpModule.d.ts.map