@hyperlane-xyz/sdk
Version:
The official SDK for the Hyperlane Network
126 lines • 5.31 kB
JavaScript
import { zeroAddress } from 'viem';
import { assert, deepEquals, eqAddress, rootLogger, } from '@hyperlane-xyz/utils';
import { HyperlaneModule, } from '../core/AbstractHyperlaneModule.js';
import { normalizeConfig } from '../utils/ism.js';
import { CosmosNativeHookReader } from './CosmosNativeHookReader.js';
import { HookConfigSchema, HookType, } from './types.js';
export class CosmosNativeHookModule extends HyperlaneModule {
metadataManager;
signer;
logger = rootLogger.child({
module: 'CosmosNativeHookModule',
});
reader;
// Adding these to reduce how often we need to grab from ChainMetadataManager.
chain;
chainId;
domainId;
constructor(metadataManager, params, signer) {
params.config = HookConfigSchema.parse(params.config);
super(params);
this.metadataManager = metadataManager;
this.signer = signer;
this.reader = new CosmosNativeHookReader(metadataManager, signer);
this.chain = metadataManager.getChainName(this.args.chain);
this.chainId = metadataManager.getChainId(this.chain);
this.domainId = metadataManager.getDomainId(this.chain);
}
async read() {
return this.reader.deriveHookConfig(this.args.addresses.deployedHook);
}
async update(targetConfig) {
if (targetConfig === zeroAddress) {
return Promise.resolve([]);
}
targetConfig = HookConfigSchema.parse(targetConfig);
// Do not support updating to a custom Hook address
if (typeof targetConfig === 'string') {
throw new Error('Invalid targetConfig: Updating to a custom Hook address is not supported. Please provide a valid Hook configuration.');
}
this.args.config = targetConfig;
// We need to normalize the current and target configs to compare.
const normalizedCurrentConfig = normalizeConfig(await this.read());
const normalizedTargetConfig = normalizeConfig(targetConfig);
if (deepEquals(normalizedCurrentConfig, normalizedTargetConfig)) {
return [];
}
this.args.addresses.deployedHook = await this.deploy({
config: normalizedTargetConfig,
});
return [];
}
static async create({ chain, config, addresses, multiProvider, signer, }) {
const module = new CosmosNativeHookModule(multiProvider, {
addresses,
chain,
config,
}, signer);
module.args.addresses.deployedHook = await module.deploy({ config });
return module;
}
async deploy({ config }) {
config = HookConfigSchema.parse(config);
if (typeof config === 'string') {
return config;
}
const hookType = config.type;
this.logger.info(`Deploying ${hookType} to ${this.chain}`);
switch (hookType) {
case HookType.INTERCHAIN_GAS_PAYMASTER:
return this.deployIgpHook({ config });
case HookType.MERKLE_TREE:
return this.deployMerkleTreeHook();
case HookType.MAILBOX_DEFAULT:
return this.deployNoopHook();
default:
throw new Error(`Hook type ${hookType} is not supported on Cosmos`);
}
}
async deployIgpHook({ config, }) {
this.logger.debug('Deploying IGP as hook...');
const { nativeToken } = this.metadataManager.getChainMetadata(this.chain);
assert(nativeToken?.denom, `found no native token for chain ${this.chain}`);
const { response: igp } = await this.signer.createIgp({
denom: nativeToken.denom,
});
for (const [remote, c] of Object.entries(config.oracleConfig)) {
const remoteDomain = this.metadataManager.tryGetDomainId(remote);
if (remoteDomain === null) {
this.logger.warn(`Skipping gas oracle ${this.chain} -> ${remote}.`);
continue;
}
await this.signer.setDestinationGasConfig({
igp_id: igp.id,
destination_gas_config: {
remote_domain: remoteDomain,
gas_overhead: config.overhead[remote].toString(),
gas_oracle: {
token_exchange_rate: c.tokenExchangeRate,
gas_price: c.gasPrice,
},
},
});
}
if (!eqAddress(this.signer.account.address, config.owner)) {
await this.signer.setIgpOwner({
igp_id: igp.id,
new_owner: config.owner,
renounce_ownership: !config.owner, // if owner is empty we renounce the ownership
});
}
return igp.id;
}
async deployMerkleTreeHook() {
this.logger.debug('Deploying Merkle Tree Hook...');
const { response: merkleTree } = await this.signer.createMerkleTreeHook({
mailbox_id: this.args.addresses.mailbox,
});
return merkleTree.id;
}
async deployNoopHook() {
this.logger.debug('Deploying Noop Hook...');
const { response: noopResponse } = await this.signer.createNoopHook({});
return noopResponse.id;
}
}
//# sourceMappingURL=CosmosNativeHookModule.js.map