diff --git a/.registryrc b/.registryrc index 9f4316497a..19d87576f4 100644 --- a/.registryrc +++ b/.registryrc @@ -1 +1 @@ -3e366eae1d49da4270695b157d7af00bb761156a +82013508db45dcd55b44d2721414d26817686c8f diff --git a/rust/main/config/mainnet_config.json b/rust/main/config/mainnet_config.json index f0ea1a9ddd..6e0da5be3e 100644 --- a/rust/main/config/mainnet_config.json +++ b/rust/main/config/mainnet_config.json @@ -1231,7 +1231,7 @@ "bech32Prefix": "inj", "blockExplorers": [ { - "apiUrl": "https://www.mintscan.io/injective", + "apiUrl": "https://apis.mintscan.io/v1/injective", "family": "other", "name": "Mintscan", "url": "https://www.mintscan.io/injective" @@ -2042,7 +2042,7 @@ "bech32Prefix": "neutron", "blockExplorers": [ { - "apiUrl": "https://www.mintscan.io/neutron", + "apiUrl": "https://apis.mintscan.io/v1/neutron", "family": "other", "name": "Mintscan", "url": "https://www.mintscan.io/neutron" @@ -2180,7 +2180,7 @@ "bech32Prefix": "osmo", "blockExplorers": [ { - "apiUrl": "https://www.mintscan.io/osmosis", + "apiUrl": "https://apis.mintscan.io/v1/osmosis", "family": "other", "name": "Mintscan", "url": "https://www.mintscan.io/osmosis" @@ -4111,7 +4111,7 @@ "bech32Prefix": "stride", "blockExplorers": [ { - "apiUrl": "https://www.mintscan.io/stride", + "apiUrl": "https://apis.mintscan.io/v1/stride", "family": "other", "name": "Mintscan", "url": "https://www.mintscan.io/stride" diff --git a/typescript/infra/config/environments/mainnet3/agent.ts b/typescript/infra/config/environments/mainnet3/agent.ts index 8a2ecd7a1f..892746c63e 100644 --- a/typescript/infra/config/environments/mainnet3/agent.ts +++ b/typescript/infra/config/environments/mainnet3/agent.ts @@ -12,6 +12,7 @@ import { import { MetricAppContext, routerMatchingList, + senderMatchingList, warpRouteMatchingList, } from '../../../src/config/agent/relayer.js'; import { ALL_KEY_ROLES, Role } from '../../../src/roles.js'; @@ -20,14 +21,17 @@ import { getDomainId } from '../../registry.js'; import { environment } from './chains.js'; import { helloWorld } from './helloworld.js'; +import aaveSenderAddresses from './misc-artifacts/aave-sender-addresses.json'; +import merklyEthAddresses from './misc-artifacts/merkly-eth-addresses.json'; +import merklyNftAddresses from './misc-artifacts/merkly-eth-addresses.json'; +import merklyErc20Addresses from './misc-artifacts/merkly-eth-addresses.json'; +import veloMessageModuleAddresses from './misc-artifacts/velo-message-module-addresses.json'; +import veloTokenBridgeAddresses from './misc-artifacts/velo-token-bridge-addresses.json'; import { mainnet3SupportedChainNames, supportedChainNames, } from './supportedChainNames.js'; import { validatorChainConfig } from './validators.js'; -import merklyEthAddresses from './warp/artifacts/merkly-eth-addresses.json'; -import merklyNftAddresses from './warp/artifacts/merkly-eth-addresses.json'; -import merklyErc20Addresses from './warp/artifacts/merkly-eth-addresses.json'; import { WarpRouteIds } from './warp/warpIds.js'; // const releaseCandidateHelloworldMatchingList = routerMatchingList( @@ -375,6 +379,22 @@ const metricAppContextsGetter = (): MetricAppContext[] => { name: 'merkly_nft', matchingList: routerMatchingList(merklyNftAddresses), }, + { + name: 'velo_message_module', + matchingList: routerMatchingList(veloMessageModuleAddresses), + }, + { + name: 'velo_token_bridge', + matchingList: routerMatchingList(veloTokenBridgeAddresses), + }, + { + // https://github.com/bgd-labs/aave-delivery-infrastructure?tab=readme-ov-file#deployed-addresses + // We match on senders because the sender is always the same and + // well documented, while the recipient may be switched out and is + // more poorly documented. + name: 'aave', + matchingList: senderMatchingList(aaveSenderAddresses), + }, ]; }; diff --git a/typescript/infra/config/environments/mainnet3/misc-artifacts/aave-sender-addresses.json b/typescript/infra/config/environments/mainnet3/misc-artifacts/aave-sender-addresses.json new file mode 100644 index 0000000000..21cfa5eccf --- /dev/null +++ b/typescript/infra/config/environments/mainnet3/misc-artifacts/aave-sender-addresses.json @@ -0,0 +1,38 @@ +{ + "ethereum": { + "sender": "0xEd42a7D8559a463722Ca4beD50E0Cc05a386b0e1" + }, + "polygon": { + "sender": "0xF6B99959F0b5e79E1CC7062E12aF632CEb18eF0d" + }, + "avalanche": { + "sender": "0x27FC7D54C893dA63C0AE6d57e1B2B13A70690928" + }, + "arbitrum": { + "sender": "0xCbFB78a3Eeaa611b826E37c80E4126c8787D29f0" + }, + "optimism": { + "sender": "0x48A9FE90bce5EEd790f3F4Ce192d1C0B351fd4Ca" + }, + "bsc": { + "sender": "0x9d33ee6543C9b2C8c183b8fb58fB089266cffA19" + }, + "base": { + "sender": "0x529467C76f234F2bD359d7ecF7c660A2846b04e2" + }, + "metis": { + "sender": "0x6fDaFb26915ABD6065a1E1501a37Ac438D877f70" + }, + "gnosis": { + "sender": "0x8Dc5310fc9D3D7D1Bb3D1F686899c8F082316c9F" + }, + "scroll": { + "sender": "0x03073D3F4769f6b6604d616238fD6c636C99AD0A" + }, + "polygonzkevm": { + "sender": "0xed7e0874526B9BB9E36C7e9472ed7ed324CEeE3B" + }, + "celo": { + "sender": "0x4A5f4b29C0407E5Feb323305e121f563c7bC4d79" + } +} diff --git a/typescript/infra/config/environments/mainnet3/warp/artifacts/merkly-erc20-addresses.json b/typescript/infra/config/environments/mainnet3/misc-artifacts/merkly-erc20-addresses.json similarity index 100% rename from typescript/infra/config/environments/mainnet3/warp/artifacts/merkly-erc20-addresses.json rename to typescript/infra/config/environments/mainnet3/misc-artifacts/merkly-erc20-addresses.json diff --git a/typescript/infra/config/environments/mainnet3/warp/artifacts/merkly-eth-addresses.json b/typescript/infra/config/environments/mainnet3/misc-artifacts/merkly-eth-addresses.json similarity index 100% rename from typescript/infra/config/environments/mainnet3/warp/artifacts/merkly-eth-addresses.json rename to typescript/infra/config/environments/mainnet3/misc-artifacts/merkly-eth-addresses.json diff --git a/typescript/infra/config/environments/mainnet3/warp/artifacts/merkly-nft-addresses.json b/typescript/infra/config/environments/mainnet3/misc-artifacts/merkly-nft-addresses.json similarity index 100% rename from typescript/infra/config/environments/mainnet3/warp/artifacts/merkly-nft-addresses.json rename to typescript/infra/config/environments/mainnet3/misc-artifacts/merkly-nft-addresses.json diff --git a/typescript/infra/config/environments/mainnet3/misc-artifacts/velo-message-module-addresses.json b/typescript/infra/config/environments/mainnet3/misc-artifacts/velo-message-module-addresses.json new file mode 100644 index 0000000000..3b9fc2fecd --- /dev/null +++ b/typescript/infra/config/environments/mainnet3/misc-artifacts/velo-message-module-addresses.json @@ -0,0 +1,8 @@ +{ + "optimism": { + "router": "0xF385603a12Be8b7B885222329c581FDD1C30071D" + }, + "mode": { + "router": "0xF385603a12Be8b7B885222329c581FDD1C30071D" + } +} diff --git a/typescript/infra/config/environments/mainnet3/misc-artifacts/velo-token-bridge-addresses.json b/typescript/infra/config/environments/mainnet3/misc-artifacts/velo-token-bridge-addresses.json new file mode 100644 index 0000000000..1988c9adb4 --- /dev/null +++ b/typescript/infra/config/environments/mainnet3/misc-artifacts/velo-token-bridge-addresses.json @@ -0,0 +1,8 @@ +{ + "optimism": { + "router": "0xA7287a56C01ac8Baaf8e7B662bDB41b10889C7A6" + }, + "mode": { + "router": "0xA7287a56C01ac8Baaf8e7B662bDB41b10889C7A6" + } +} diff --git a/typescript/infra/config/environments/mainnet3/warp/warpIds.ts b/typescript/infra/config/environments/mainnet3/warp/warpIds.ts index a68ed19c8f..605f0a7941 100644 --- a/typescript/infra/config/environments/mainnet3/warp/warpIds.ts +++ b/typescript/infra/config/environments/mainnet3/warp/warpIds.ts @@ -1,6 +1,7 @@ export enum WarpRouteIds { Ancient8EthereumUSDC = 'USDC/ancient8-ethereum', ArbitrumBaseBlastBscEthereumFraxtalLineaModeOptimismSeiTaikoZircuitEZETH = 'EZETH/arbitrum-base-blast-bsc-ethereum-fraxtal-linea-mode-optimism-sei-taiko-zircuit', + ArbitrumBaseEnduranceUSDC = 'USDC/arbitrum-base-endurance', ArbitrumEthereumZircuitAMPHRETH = 'AMPHRETH/arbitrum-ethereum-zircuit', ArbitrumNeutronEclip = 'ECLIP/arbitrum-neutron', ArbitrumNeutronTIA = 'TIA/arbitrum-neutron', diff --git a/typescript/infra/helm/warp-routes/templates/_helpers.tpl b/typescript/infra/helm/warp-routes/templates/_helpers.tpl index bc732a5a37..2a9424b0a9 100644 --- a/typescript/infra/helm/warp-routes/templates/_helpers.tpl +++ b/typescript/infra/helm/warp-routes/templates/_helpers.tpl @@ -69,7 +69,7 @@ The warp-routes container imagePullPolicy: IfNotPresent env: - name: LOG_FORMAT - value: pretty + value: json command: - ./node_modules/.bin/tsx - ./typescript/infra/scripts/warp-routes/monitor/monitor-warp-route-balances.ts diff --git a/typescript/infra/scripts/warp-routes/deploy-warp-monitor.ts b/typescript/infra/scripts/warp-routes/deploy-warp-monitor.ts index bc19f434f3..e7714778ca 100644 --- a/typescript/infra/scripts/warp-routes/deploy-warp-monitor.ts +++ b/typescript/infra/scripts/warp-routes/deploy-warp-monitor.ts @@ -46,11 +46,18 @@ async function getWarpRouteIdsInteractive() { value: id, })); - const selection = await checkbox({ - message: 'Select Warp Route IDs to deploy', - choices, - pageSize: 30, - }); + let selection: WarpRouteIds[] = []; + + while (!selection.length) { + selection = await checkbox({ + message: 'Select Warp Route IDs to deploy', + choices, + pageSize: 30, + }); + if (!selection.length) { + console.log('Please select at least one Warp Route ID'); + } + } return selection; } diff --git a/typescript/infra/scripts/warp-routes/monitor/metrics.ts b/typescript/infra/scripts/warp-routes/monitor/metrics.ts index 7f832b512f..eec6738ab1 100644 --- a/typescript/infra/scripts/warp-routes/monitor/metrics.ts +++ b/typescript/infra/scripts/warp-routes/monitor/metrics.ts @@ -74,17 +74,23 @@ export function updateTokenBalanceMetrics( }; warpRouteTokenBalance.labels(metrics).set(balanceInfo.balance); - logger.info('Wallet balance updated for token', { - labels: metrics, - balance: balanceInfo.balance, - }); + logger.info( + { + labels: metrics, + balance: balanceInfo.balance, + }, + 'Wallet balance updated for token', + ); if (balanceInfo.valueUSD) { warpRouteCollateralValue.labels(metrics).set(balanceInfo.valueUSD); - logger.info('Wallet balance updated for token', { - labels: metrics, - valueUSD: balanceInfo.valueUSD, - }); + logger.info( + { + labels: metrics, + valueUSD: balanceInfo.valueUSD, + }, + 'Wallet value updated for token', + ); } } diff --git a/typescript/infra/scripts/warp-routes/monitor/monitor-warp-route-balances.ts b/typescript/infra/scripts/warp-routes/monitor/monitor-warp-route-balances.ts index f9af0039d3..7a8fdb645a 100644 --- a/typescript/infra/scripts/warp-routes/monitor/monitor-warp-route-balances.ts +++ b/typescript/infra/scripts/warp-routes/monitor/monitor-warp-route-balances.ts @@ -13,7 +13,7 @@ import { TokenStandard, WarpCore, } from '@hyperlane-xyz/sdk'; -import { ProtocolType, objMap, objMerge } from '@hyperlane-xyz/utils'; +import { ProtocolType, objMap, objMerge, sleep } from '@hyperlane-xyz/utils'; import { getWarpCoreConfig } from '../../../config/registry.js'; import { @@ -78,7 +78,7 @@ async function pollAndUpdateWarpRouteMetrics( apiKey: await getCoinGeckoApiKey(), }); - setInterval(async () => { + while (true) { await tryFn(async () => { await Promise.all( warpCore.tokens.map((token) => @@ -86,7 +86,8 @@ async function pollAndUpdateWarpRouteMetrics( ), ); }, 'Updating warp route metrics'); - }, checkFrequency); + await sleep(checkFrequency); + } } // Updates the metrics for a single token in a warp route. @@ -246,9 +247,7 @@ async function getCoinGeckoApiKey(): Promise { return apiKey; } -main() - .then(logger.info) - .catch((err) => { - logger.error('Error in main', err); - process.exit(1); - }); +main().catch((err) => { + logger.error('Error in main:', err); + process.exit(1); +}); diff --git a/typescript/infra/src/config/agent/relayer.ts b/typescript/infra/src/config/agent/relayer.ts index 648ab81aca..a7500ec74a 100644 --- a/typescript/infra/src/config/agent/relayer.ts +++ b/typescript/infra/src/config/agent/relayer.ts @@ -242,6 +242,18 @@ export function routerMatchingList( return matchingList(routers); } +// Create a matching list for the given senders to any destination or recipient +export function senderMatchingList( + senders: ChainMap<{ sender: Address }>, +): MatchingList { + return Object.entries(senders).map(([chain, { sender }]) => ({ + originDomain: getDomainId(chain), + senderAddress: addressToBytes32(sender), + destinationDomain: '*', + recipientAddress: '*', + })); +} + // Create a matching list for the given contract addresses export function matchingList( addressesMap: HyperlaneAddressesMap, diff --git a/typescript/infra/src/warp/helm.ts b/typescript/infra/src/warp/helm.ts index 02b8d9dc99..2b0123c3bb 100644 --- a/typescript/infra/src/warp/helm.ts +++ b/typescript/infra/src/warp/helm.ts @@ -22,7 +22,7 @@ export class WarpRouteMonitorHelmManager extends HelmManager { return { image: { repository: 'gcr.io/abacus-labs-dev/hyperlane-monorepo', - tag: '6cd61f1-20241112-111341', + tag: '7544b99-20241119-162215', }, warpRouteId: this.warpRouteId, fullnameOverride: this.helmReleaseName, diff --git a/typescript/sdk/src/token/Token.ts b/typescript/sdk/src/token/Token.ts index b639159692..0217802e7c 100644 --- a/typescript/sdk/src/token/Token.ts +++ b/typescript/sdk/src/token/Token.ts @@ -40,6 +40,7 @@ import { } from './adapters/CosmosTokenAdapter.js'; import { EvmHypCollateralAdapter, + EvmHypCollateralFiatAdapter, EvmHypNativeAdapter, EvmHypSyntheticAdapter, EvmHypXERC20Adapter, @@ -192,13 +193,16 @@ export class Token implements IToken { }); } else if ( standard === TokenStandard.EvmHypCollateral || - standard === TokenStandard.EvmHypCollateralFiat || standard === TokenStandard.EvmHypOwnerCollateral || standard === TokenStandard.EvmHypRebaseCollateral ) { return new EvmHypCollateralAdapter(chainName, multiProvider, { token: addressOrDenom, }); + } else if (standard === TokenStandard.EvmHypCollateralFiat) { + return new EvmHypCollateralFiatAdapter(chainName, multiProvider, { + token: addressOrDenom, + }); } else if ( standard === TokenStandard.EvmHypSynthetic || standard === TokenStandard.EvmHypSyntheticRebase diff --git a/typescript/sdk/src/token/adapters/EvmTokenAdapter.ts b/typescript/sdk/src/token/adapters/EvmTokenAdapter.ts index 794d5cdff9..cd9910a5a2 100644 --- a/typescript/sdk/src/token/adapters/EvmTokenAdapter.ts +++ b/typescript/sdk/src/token/adapters/EvmTokenAdapter.ts @@ -261,9 +261,7 @@ export class EvmHypCollateralAdapter return this.wrappedTokenAddress!; } - protected async getWrappedTokenAdapter(): Promise< - ITokenAdapter - > { + protected async getWrappedTokenAdapter(): Promise { return new EvmTokenAdapter(this.chainName, this.multiProvider, { token: await this.getWrappedTokenAddress(), }); @@ -304,6 +302,21 @@ export class EvmHypCollateralAdapter } } +export class EvmHypCollateralFiatAdapter + extends EvmHypCollateralAdapter + implements IHypTokenAdapter +{ + /** + * Note this may be inaccurate, as this returns the total supply + * of the fiat token, which may be used by other bridges. + * However this is the best we can do with a simple view call. + */ + override async getBridgedSupply(): Promise { + const wrapped = await this.getWrappedTokenAdapter(); + return wrapped.getTotalSupply(); + } +} + // Interacts with HypXERC20Lockbox contracts export class EvmHypXERC20LockboxAdapter extends EvmHypCollateralAdapter