import type { Logger } from 'pino'; import { type ChainName, type MultiProvider, type WarpCore } from '@hyperlane-xyz/sdk'; import { ProtocolType } from '@hyperlane-xyz/utils'; import type { ExternalBridgeRegistry } from '../interfaces/IExternalBridge.js'; import type { IInventoryRebalancer, InventoryExecutionResult, RebalancerType } from '../interfaces/IRebalancer.js'; import type { InventoryRoute } from '../interfaces/IStrategy.js'; import type { IActionTracker } from '../tracking/IActionTracker.js'; /** * Configuration for the InventoryRebalancer. */ export interface InventorySignerConfig { /** Signer address for this protocol */ address: string; /** Private key for signing (optional - absent in monitor-only mode) */ key?: string; } export interface InventoryRebalancerConfig { /** Signer config per protocol (address + optional key) */ inventorySigners: Partial>; /** Chains configured for inventory-based rebalancing (for validation) */ inventoryChains: ChainName[]; } /** * Executes inventory-based rebalances for chains that don't support MovableCollateralRouter. * * IMPORTANT: transferRemote ADDS collateral to the ORIGIN chain (where it's called FROM). * So for a strategy route "base (surplus) → arbitrum (deficit)", we must: * 1. Ensure inventory is available on the DESTINATION (deficit) chain - arbitrum * 2. Call transferRemote FROM arbitrum TO base * 3. This ADDS collateral to arbitrum (filling deficit) and releases from base (has surplus) * * The flow is: * 1. Check if inventory is available on the destination (deficit) chain * 2. If available, execute transferRemote from destination to origin (swapped direction) * 3. If not available, bridge inventory to destination via LiFi, then execute transferRemote * * Actions created: * - `inventory_movement`: LiFi bridge to move inventory to deficit chain * - `inventory_deposit`: transferRemote to deposit collateral on deficit chain */ export declare class InventoryRebalancer implements IInventoryRebalancer { readonly rebalancerType: RebalancerType; private readonly logger; private readonly config; private readonly actionTracker; private readonly externalBridgeRegistry; private readonly warpCore; private readonly multiProvider; /** * Internal balance storage for inventory tracking. * Updated via setInventoryBalances() before each rebalance cycle. */ private inventoryBalances; /** * Tracks inventory consumed during the current execution cycle. * Cleared at the start of each execute() call. * Used to prevent over-execution when multiple routes withdraw from the same chain. */ private consumedInventory; constructor(config: InventoryRebalancerConfig, actionTracker: IActionTracker, externalBridgeRegistry: Partial, warpCore: WarpCore, multiProvider: MultiProvider, logger: Logger); /** * Get bridge instance by type from registry. * Throws if bridge type not found. */ private getExternalBridge; private getNativeTokenAddress; /** * Validate that tokens on inventory chains are collateral-backed. * Only checks tokens for chains configured with inventory-based rebalancing. * Throws an error if any synthetic tokens are found on inventory chains. */ private validateCollateralBackedTokens; /** * Get the token for a specific chain from WarpCore. */ private getTokenForChain; private getProtocolForChain; private getInventorySignerAddress; /** * Set inventory balances from external source. * Called before each rebalance cycle to update internal state. */ setInventoryBalances(balances: Record): void; /** * Get available inventory for a chain. * Returns 0n for unknown chains. */ private getAvailableInventory; /** * Get all inventory balances. */ private getBalances; /** * Calculate total inventory across all chains, excluding specified chains. */ private getTotalInventory; private formatLocalAmount; /** * Get the effective available inventory for a chain, accounting for * inventory already consumed during this execution cycle. * * This prevents over-execution when multiple routes withdraw from the same chain. * * @param chain - The chain to check inventory for * @returns Effective available inventory (cached - consumed) */ private getEffectiveAvailableInventory; /** * Execute inventory-based rebalances for the given routes. * * Single-intent architecture: * 1. Check for existing in_progress intent * 2. If exists, continue existing intent (ignores new routes) * 3. If not, take only the FIRST route and create a single intent */ rebalance(routes: InventoryRoute[]): Promise; /** * Get the single active inventory intent (if any). * Returns null if no in_progress inventory intent exists. */ private getActiveInventoryIntent; /** * Continue execution of an existing partial intent. * Uses the pre-computed remaining amount from PartialInventoryIntent. */ private continueIntent; /** * Execute a single inventory route. * * Strategy provides: origin (surplus) → destination (deficit) * "Move collateral FROM origin TO destination" * * IMPORTANT: transferRemote ADDS collateral to the chain it's called FROM. * So to fill the deficit on destination, we must: * - Call transferRemote FROM destination TO origin (SWAPPED direction) * - This ADDS to destination (deficit filled!) and RELEASES from origin (has surplus) * * Execution flow: * 1. Check inventory on DESTINATION (deficit chain) - need funds there to call transferRemote * 2. If low, LiFi bridge TO destination * 3. Call transferRemote FROM destination TO origin (swapped) */ private executeRoute; /** * Execute a transferRemote to deposit collateral. * * IMPORTANT: The route passed here has SWAPPED direction from the strategy route. * - route.origin = the deficit chain (where transferRemote is called FROM) * - route.destination = the surplus chain (where Hyperlane message goes TO) * * transferRemote mechanics: * - Calls _transferFromSender() which ADDS collateral to route.origin * - Sends Hyperlane message to route.destination to RELEASE collateral * * @param route - The transfer route (swapped direction) * @param intent - The rebalance intent being executed */ private executeTransferRemote; private sendAndConfirmInventoryTx; private buildSignerAccountConfig; protected extractDispatchedMessageId(origin: ChainName, txHash: string): Promise; private getTransactionReceipt; /** * Select all source chains with available inventory for bridging. * Returns sources sorted by available amount (highest first). */ private selectAllSourceChains; /** * Calculate the bridge capacity from a source chain in destination-local units. * Uses LiFi quotes to conservatively estimate the destination output available * from the source chain's current local inventory. * * For native-token sources, gas is reserved from the source inventory and the * output capacity is re-quoted from the remaining source input. */ private calculateBridgeCapacity; /** * Execute inventory movement from source chain to target chain via LiFi bridge. * * Quote mode is chosen during planning: * - `reverse`: request an exact target-chain output when the source has headroom * - `forward`: spend the source cap directly when source inventory is the limiter * * @param sourceChain - Chain to move inventory from * @param targetChain - Chain to move inventory to (origin chain for rebalancing) * @param targetOutputAmount - Destination-local amount to receive * @param maxSourceInput - Maximum source-local amount available for this plan * @param quoteMode - Whether to execute this bridge plan as exact-input or exact-output * @param intent - Rebalance intent for tracking * @param externalBridgeType - External bridge type to use * @returns Result with success status and optional txHash/error */ private executeInventoryMovement; } //# sourceMappingURL=InventoryRebalancer.d.ts.map