From 9fcd592878c75fd55c760bce04310787cc3d6e81 Mon Sep 17 00:00:00 2001 From: Trevor Porter Date: Fri, 8 Nov 2024 21:19:15 +0000 Subject: [PATCH] feat: refactor warp monitor to use WarpCore config (#4835) ### Description - Removes the warp monitor specific config format and all the handcrafted yamls from infra - Massive refactor to warp monitor to accommodate this -- tried to make it a bit easier to work work by splitting it into a few files. The changes are generally backward compatible with some small exceptions, like now the metrics use the `TokenStandard` instead of `TokenType` (the former is present in the warp core config, the latter isn't, and there's no way atm to map from the former to the latter) - The warp monitor now takes in a warp ID and gets its config from the registry (recall this is the registry version defined in `.registryrc` if running in the monorepo image) - Deploying the warp monitor now lets you do many at a time and select the ones to deploy interactively. This makes it a bit easier to work with the warp IDs - The names of the warp deploys are based on the warp IDs. Because warp IDs can change as new chains are added, this may cause issues in the future - we'll just need to be cautious of removing the old release to avoid accidentally having 2 of them. For now I think this is fine. The helm release names are also capped at 53 chars so they needed to be truncated - Some changes to the SDK to get the necessary data here. Happy to pull some of these into the warp monitor if people feel they're inappropriate for the SDK (like the `getBridgedSupply`) - Added a test to make sure any warp route IDs in infra are found in the registry - Corresponding PR to the registry here https://github.com/hyperlane-xyz/hyperlane-registry/pull/370 ### Drive-by changes ### Related issues ### Backward compatibility ### Testing --- .registryrc | 2 +- .../config/environments/mainnet3/agent.ts | 28 +- .../mainnet3/warp/AMPHRETH-deployments.yaml | 28 - .../mainnet3/warp/EZETH-deployments.yaml | 86 --- .../warp/TIA-eclipse-stride-deployments.yaml | 24 - .../warp/ancient8-USDC-deployments.yaml | 23 - .../warp/{ => artifacts}/addresses.json | 0 .../ancient8-USDC-addresses.json | 0 .../arbitrum-TIA-addresses.json | 0 .../arbitrum-neutron-eclip-addresses.json | 0 .../eclipse-stride-TIA-addresses.json | 0 .../eclipse-stride-stTIA-addresses.json | 0 .../{ => artifacts}/inevm-USDC-addresses.json | 0 .../{ => artifacts}/inevm-USDT-addresses.json | 0 .../injective-inevm-addresses.json | 0 .../{ => artifacts}/manta-TIA-addresses.json | 0 .../merkly-erc20-addresses.json | 0 .../{ => artifacts}/merkly-eth-addresses.json | 0 .../{ => artifacts}/merkly-nft-addresses.json | 0 .../renzo-ezETH-addresses-v1.json | 0 .../renzo-ezETH-addresses-v3.json | 0 .../warp/{ => artifacts}/verification.json | 0 .../viction-ETH-addresses.json | 0 .../viction-USDC-addresses.json | 0 .../viction-USDT-addresses.json | 0 .../warp/bsc-lumia-LUMIA-deployments.yaml | 30 - .../warp/eclipse-ORCA-deployments.yaml | 24 - .../warp/eclipse-SOL-deployments.yaml | 24 - .../warp/eclipse-USDC-deployments.yaml | 35 - .../warp/eclipse-USDT-deployments.yaml | 34 - .../warp/eclipse-WBTC-deployments.yaml | 23 - .../warp/eclipse-WIF-deployments.yaml | 25 - .../warp/eclipse-tETH-deployments.yaml | 24 - .../warp/ethereumUSDC-inevm-deployments.yaml | 23 - .../warp/ethereumUSDT-inevm-deployments.yaml | 23 - .../warp/injective-inevm-deployments.yaml | 23 - .../warp/nautilus-solana-bsc-deployments.yaml | 31 - .../neutron-mantapacific-deployments.yaml | 23 - .../warp/sei-FASTUSD-deployments.yaml | 22 - .../stTIA-eclipse-stride-deployments.yaml | 24 - .../viction-ethereum-ETH-deployments.yaml | 22 - .../viction-ethereum-USDC-deployments.yaml | 23 - .../viction-ethereum-USDT-deployments.yaml | 23 - .../environments/mainnet3/warp/warpIds.ts | 5 +- typescript/infra/config/registry.ts | 9 +- .../helm/warp-routes/templates/_helpers.tpl | 8 +- .../templates/env-var-external-secret.yaml | 4 + .../warp-routes/deploy-warp-monitor.ts | 62 +- .../monitor-warp-routes-balances.ts | 697 ------------------ .../scripts/warp-routes/monitor/metrics.ts | 105 +++ .../monitor/monitor-warp-route-balances.ts | 254 +++++++ .../scripts/warp-routes/monitor/types.ts | 11 + .../scripts/warp-routes/monitor/utils.ts | 11 + typescript/infra/src/warp/helm.ts | 28 +- typescript/infra/test/warpIds.test.ts | 15 + typescript/sdk/src/index.ts | 3 + typescript/sdk/src/token/Token.ts | 11 +- typescript/sdk/src/token/TokenStandard.ts | 4 +- .../token/adapters/CosmWasmTokenAdapter.ts | 18 + .../src/token/adapters/CosmosTokenAdapter.ts | 10 + .../sdk/src/token/adapters/EvmTokenAdapter.ts | 112 ++- .../sdk/src/token/adapters/ITokenAdapter.ts | 5 + .../token/adapters/SealevelTokenAdapter.ts | 29 + 63 files changed, 653 insertions(+), 1395 deletions(-) delete mode 100644 typescript/infra/config/environments/mainnet3/warp/AMPHRETH-deployments.yaml delete mode 100644 typescript/infra/config/environments/mainnet3/warp/EZETH-deployments.yaml delete mode 100644 typescript/infra/config/environments/mainnet3/warp/TIA-eclipse-stride-deployments.yaml delete mode 100644 typescript/infra/config/environments/mainnet3/warp/ancient8-USDC-deployments.yaml rename typescript/infra/config/environments/mainnet3/warp/{ => artifacts}/addresses.json (100%) rename typescript/infra/config/environments/mainnet3/warp/{ => artifacts}/ancient8-USDC-addresses.json (100%) rename typescript/infra/config/environments/mainnet3/warp/{ => artifacts}/arbitrum-TIA-addresses.json (100%) rename typescript/infra/config/environments/mainnet3/warp/{ => artifacts}/arbitrum-neutron-eclip-addresses.json (100%) rename typescript/infra/config/environments/mainnet3/warp/{ => artifacts}/eclipse-stride-TIA-addresses.json (100%) rename typescript/infra/config/environments/mainnet3/warp/{ => artifacts}/eclipse-stride-stTIA-addresses.json (100%) rename typescript/infra/config/environments/mainnet3/warp/{ => artifacts}/inevm-USDC-addresses.json (100%) rename typescript/infra/config/environments/mainnet3/warp/{ => artifacts}/inevm-USDT-addresses.json (100%) rename typescript/infra/config/environments/mainnet3/warp/{ => artifacts}/injective-inevm-addresses.json (100%) rename typescript/infra/config/environments/mainnet3/warp/{ => artifacts}/manta-TIA-addresses.json (100%) rename typescript/infra/config/environments/mainnet3/warp/{ => artifacts}/merkly-erc20-addresses.json (100%) rename typescript/infra/config/environments/mainnet3/warp/{ => artifacts}/merkly-eth-addresses.json (100%) rename typescript/infra/config/environments/mainnet3/warp/{ => artifacts}/merkly-nft-addresses.json (100%) rename typescript/infra/config/environments/mainnet3/warp/{ => artifacts}/renzo-ezETH-addresses-v1.json (100%) rename typescript/infra/config/environments/mainnet3/warp/{ => artifacts}/renzo-ezETH-addresses-v3.json (100%) rename typescript/infra/config/environments/mainnet3/warp/{ => artifacts}/verification.json (100%) rename typescript/infra/config/environments/mainnet3/warp/{ => artifacts}/viction-ETH-addresses.json (100%) rename typescript/infra/config/environments/mainnet3/warp/{ => artifacts}/viction-USDC-addresses.json (100%) rename typescript/infra/config/environments/mainnet3/warp/{ => artifacts}/viction-USDT-addresses.json (100%) delete mode 100644 typescript/infra/config/environments/mainnet3/warp/bsc-lumia-LUMIA-deployments.yaml delete mode 100644 typescript/infra/config/environments/mainnet3/warp/eclipse-ORCA-deployments.yaml delete mode 100644 typescript/infra/config/environments/mainnet3/warp/eclipse-SOL-deployments.yaml delete mode 100644 typescript/infra/config/environments/mainnet3/warp/eclipse-USDC-deployments.yaml delete mode 100644 typescript/infra/config/environments/mainnet3/warp/eclipse-USDT-deployments.yaml delete mode 100644 typescript/infra/config/environments/mainnet3/warp/eclipse-WBTC-deployments.yaml delete mode 100644 typescript/infra/config/environments/mainnet3/warp/eclipse-WIF-deployments.yaml delete mode 100644 typescript/infra/config/environments/mainnet3/warp/eclipse-tETH-deployments.yaml delete mode 100644 typescript/infra/config/environments/mainnet3/warp/ethereumUSDC-inevm-deployments.yaml delete mode 100644 typescript/infra/config/environments/mainnet3/warp/ethereumUSDT-inevm-deployments.yaml delete mode 100644 typescript/infra/config/environments/mainnet3/warp/injective-inevm-deployments.yaml delete mode 100644 typescript/infra/config/environments/mainnet3/warp/nautilus-solana-bsc-deployments.yaml delete mode 100644 typescript/infra/config/environments/mainnet3/warp/neutron-mantapacific-deployments.yaml delete mode 100644 typescript/infra/config/environments/mainnet3/warp/sei-FASTUSD-deployments.yaml delete mode 100644 typescript/infra/config/environments/mainnet3/warp/stTIA-eclipse-stride-deployments.yaml delete mode 100644 typescript/infra/config/environments/mainnet3/warp/viction-ethereum-ETH-deployments.yaml delete mode 100644 typescript/infra/config/environments/mainnet3/warp/viction-ethereum-USDC-deployments.yaml delete mode 100644 typescript/infra/config/environments/mainnet3/warp/viction-ethereum-USDT-deployments.yaml delete mode 100644 typescript/infra/scripts/warp-routes/monitor-warp-routes-balances.ts create mode 100644 typescript/infra/scripts/warp-routes/monitor/metrics.ts create mode 100644 typescript/infra/scripts/warp-routes/monitor/monitor-warp-route-balances.ts create mode 100644 typescript/infra/scripts/warp-routes/monitor/types.ts create mode 100644 typescript/infra/scripts/warp-routes/monitor/utils.ts create mode 100644 typescript/infra/test/warpIds.test.ts diff --git a/.registryrc b/.registryrc index b0f729b8d..24eb8a50a 100644 --- a/.registryrc +++ b/.registryrc @@ -1 +1 @@ -d71eb5f42616998f77ce01079fd06a8e118966f7 +10fdae0f566c7c213b6b1b27b8620e8776f2895f diff --git a/typescript/infra/config/environments/mainnet3/agent.ts b/typescript/infra/config/environments/mainnet3/agent.ts index 77d1cdb5f..1637a3538 100644 --- a/typescript/infra/config/environments/mainnet3/agent.ts +++ b/typescript/infra/config/environments/mainnet3/agent.ts @@ -24,20 +24,20 @@ import { supportedChainNames, } from './supportedChainNames.js'; import { validatorChainConfig } from './validators.js'; -import ancient8EthereumUsdcAddresses from './warp/ancient8-USDC-addresses.json'; -import arbitrumTIAAddresses from './warp/arbitrum-TIA-addresses.json'; -import arbitrumNeutronEclipAddresses from './warp/arbitrum-neutron-eclip-addresses.json'; -import eclipseStrideTiaAddresses from './warp/eclipse-stride-TIA-addresses.json'; -import eclipseStrideStTiaAddresses from './warp/eclipse-stride-stTIA-addresses.json'; -import inevmEthereumUsdcAddresses from './warp/inevm-USDC-addresses.json'; -import inevmEthereumUsdtAddresses from './warp/inevm-USDT-addresses.json'; -import injectiveInevmInjAddresses from './warp/injective-inevm-addresses.json'; -import mantaTIAAddresses from './warp/manta-TIA-addresses.json'; -import merklyEthAddresses from './warp/merkly-eth-addresses.json'; -import renzoEzEthAddressesV3 from './warp/renzo-ezETH-addresses-v3.json'; -import victionEthereumEthAddresses from './warp/viction-ETH-addresses.json'; -import victionEthereumUsdcAddresses from './warp/viction-USDC-addresses.json'; -import victionEthereumUsdtAddresses from './warp/viction-USDT-addresses.json'; +import ancient8EthereumUsdcAddresses from './warp/artifacts/ancient8-USDC-addresses.json'; +import arbitrumTIAAddresses from './warp/artifacts/arbitrum-TIA-addresses.json'; +import arbitrumNeutronEclipAddresses from './warp/artifacts/arbitrum-neutron-eclip-addresses.json'; +import eclipseStrideTiaAddresses from './warp/artifacts/eclipse-stride-TIA-addresses.json'; +import eclipseStrideStTiaAddresses from './warp/artifacts/eclipse-stride-stTIA-addresses.json'; +import inevmEthereumUsdcAddresses from './warp/artifacts/inevm-USDC-addresses.json'; +import inevmEthereumUsdtAddresses from './warp/artifacts/inevm-USDT-addresses.json'; +import injectiveInevmInjAddresses from './warp/artifacts/injective-inevm-addresses.json'; +import mantaTIAAddresses from './warp/artifacts/manta-TIA-addresses.json'; +import merklyEthAddresses from './warp/artifacts/merkly-eth-addresses.json'; +import renzoEzEthAddressesV3 from './warp/artifacts/renzo-ezETH-addresses-v3.json'; +import victionEthereumEthAddresses from './warp/artifacts/viction-ETH-addresses.json'; +import victionEthereumUsdcAddresses from './warp/artifacts/viction-USDC-addresses.json'; +import victionEthereumUsdtAddresses from './warp/artifacts/viction-USDT-addresses.json'; import { WarpRouteIds } from './warp/warpIds.js'; // const releaseCandidateHelloworldMatchingList = routerMatchingList( diff --git a/typescript/infra/config/environments/mainnet3/warp/AMPHRETH-deployments.yaml b/typescript/infra/config/environments/mainnet3/warp/AMPHRETH-deployments.yaml deleted file mode 100644 index 222a321c2..000000000 --- a/typescript/infra/config/environments/mainnet3/warp/AMPHRETH-deployments.yaml +++ /dev/null @@ -1,28 +0,0 @@ -# Configs and artifacts for the deployment of Hyperlane Warp Routes -description: Hyperlane Warp Route artifacts -timestamp: '2024-10-18T14:00:00.000Z' -deployer: Abacus Works (Hyperlane) -data: - config: - arbitrum: - protocolType: ethereum - type: synthetic - hypAddress: '0x6D251aADfc6Ff69031e01eA39bE3cb5BABf8438f' - name: Amphor Restaked ETH - symbol: AMPHRETH - decimals: 18 - ethereum: - protocolType: ethereum - type: collateral - hypAddress: '0xdc89990a6fdC1C922b841f1d977835628A24Ed57' - tokenAddress: '0x5fD13359Ba15A84B76f7F87568309040176167cd' - name: Amphor Restaked ETH - symbol: AMPHRETH - decimals: 18 - zircuit: - protocolType: ethereum - type: synthetic - hypAddress: '0x7D5a79539d7B1c9aE5e54d18EEE188840f1Fe4CC' - name: Amphor Restaked ETH - symbol: AMPHRETH - decimals: 18 diff --git a/typescript/infra/config/environments/mainnet3/warp/EZETH-deployments.yaml b/typescript/infra/config/environments/mainnet3/warp/EZETH-deployments.yaml deleted file mode 100644 index 26a0a5807..000000000 --- a/typescript/infra/config/environments/mainnet3/warp/EZETH-deployments.yaml +++ /dev/null @@ -1,86 +0,0 @@ -description: Hyperlane Warp Route artifacts -timestamp: '2024-06-04T16:00:00.000Z' -deployer: Abacus Works (Hyperlane) -data: - config: - ethereum: - protocolType: ethereum - type: xERC20Lockbox - name: Renzo Restaked ETH - symbol: ezETH - hypAddress: '0xC59336D8edDa9722B4f1Ec104007191Ec16f7087' - tokenAddress: '0xbf5495Efe5DB9ce00f80364C8B423567e58d2110' - tokenCoinGeckoId: renzo-restaked-eth - decimals: 18 - bsc: - protocolType: ethereum - type: xERC20 - name: Renzo Restaked ETH - symbol: ezETH - hypAddress: '0xE00C6185a5c19219F1FFeD213b4406a254968c26' - tokenAddress: '0x2416092f143378750bb29b79eD961ab195CcEea5' - decimals: 18 - arbitrum: - protocolType: ethereum - type: xERC20 - name: Renzo Restaked ETH - symbol: ezETH - hypAddress: '0xB26bBfC6d1F469C821Ea25099017862e7368F4E8' - tokenAddress: '0x2416092f143378750bb29b79eD961ab195CcEea5' - decimals: 18 - optimism: - protocolType: ethereum - type: xERC20 - name: Renzo Restaked ETH - symbol: ezETH - hypAddress: '0xacEB607CdF59EB8022Cc0699eEF3eCF246d149e2' - tokenAddress: '0x2416092f143378750bb29b79eD961ab195CcEea5' - decimals: 18 - base: - protocolType: ethereum - type: xERC20 - name: Renzo Restaked ETH - symbol: ezETH - hypAddress: '0x2552516453368e42705D791F674b312b8b87CD9e' - tokenAddress: '0x2416092f143378750bb29b79eD961ab195CcEea5' - decimals: 18 - blast: - protocolType: ethereum - type: xERC20 - name: Renzo Restaked ETH - symbol: ezETH - hypAddress: '0x486b39378f99f073A3043C6Aabe8666876A8F3C5' - tokenAddress: '0x2416092f143378750bb29b79eD961ab195CcEea5' - decimals: 18 - mode: - protocolType: ethereum - type: xERC20 - name: Renzo Restaked ETH - symbol: ezETH - hypAddress: '0xC59336D8edDa9722B4f1Ec104007191Ec16f7087' - tokenAddress: '0x2416092f143378750bb29b79eD961ab195CcEea5' - decimals: 18 - linea: - protocolType: ethereum - type: xERC20 - name: Renzo Restaked ETH - symbol: ezETH - hypAddress: '0xC59336D8edDa9722B4f1Ec104007191Ec16f7087' - tokenAddress: '0x2416092f143378750bb29b79eD961ab195CcEea5' - decimals: 18 - fraxtal: - protocolType: ethereum - type: xERC20 - name: Renzo Restaked ETH - symbol: ezETH - hypAddress: '0x3aE8635A4D581d40a6Edfb3f2ED480f9532994F5' - tokenAddress: '0x2416092f143378750bb29b79eD961ab195CcEea5' - decimals: 18 - zircuit: - protocolType: ethereum - type: xERC20 - name: Renzo Restaked ETH - symbol: ezETH - hypAddress: '0x2552516453368e42705D791F674b312b8b87CD9e' - tokenAddress: '0x2416092f143378750bb29b79eD961ab195CcEea5' - decimals: 18 diff --git a/typescript/infra/config/environments/mainnet3/warp/TIA-eclipse-stride-deployments.yaml b/typescript/infra/config/environments/mainnet3/warp/TIA-eclipse-stride-deployments.yaml deleted file mode 100644 index 45c9e0efc..000000000 --- a/typescript/infra/config/environments/mainnet3/warp/TIA-eclipse-stride-deployments.yaml +++ /dev/null @@ -1,24 +0,0 @@ -# Configs and artifacts for the deployment of Hyperlane Warp Routes -description: Hyperlane Warp Route artifacts -timestamp: '2024-10-18T14:00:00.000Z' -deployer: Abacus Works (Hyperlane) -data: - config: - stride: - protocolType: cosmos - type: collateral - hypAddress: stride1pvtesu3ve7qn7ctll2x495mrqf2ysp6fws68grvcu6f7n2ajghgsh2jdj6 - tokenAddress: ibc/BF3B4F53F3694B66E13C23107C84B6485BD2B96296BB7EC680EA77BBA75B4801 - tokenCoinGeckoId: celestia - name: Celestia - symbol: TIA - decimals: 6 - eclipsemainnet: - protocolType: sealevel - type: synthetic - hypAddress: 'BpXHAiktwjx7fN6M9ST9wr6qKAsH27wZFhdHEhReJsR6' - tokenAddress: '9RryNMhAVJpAwAGjCAMKbbTFwgjapqPkzpGMfTQhEjf8' - isSpl2022: true - name: Turbo Eth - symbol: tETH - decimals: 6 diff --git a/typescript/infra/config/environments/mainnet3/warp/ancient8-USDC-deployments.yaml b/typescript/infra/config/environments/mainnet3/warp/ancient8-USDC-deployments.yaml deleted file mode 100644 index d87b3fa0a..000000000 --- a/typescript/infra/config/environments/mainnet3/warp/ancient8-USDC-deployments.yaml +++ /dev/null @@ -1,23 +0,0 @@ -# Configs and artifacts for the deployment of Hyperlane Warp Routes -# Between ancient8 and Ethereum -description: Hyperlane Warp Route artifacts -timestamp: '2024-04-15T16:00:00.000Z' -deployer: Abacus Works (Hyperlane) -data: - config: - ethereum: - protocolType: ethereum - type: collateral - hypAddress: '0x8b4192B9Ad1fCa440A5808641261e5289e6de95D' - tokenAddress: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48' # USDC - tokenCoinGeckoId: usd-coin - name: USDC - symbol: USDC - decimals: 6 - ancient8: - protocolType: ethereum - type: synthetic - hypAddress: '0x97423A68BAe94b5De52d767a17aBCc54c157c0E5' - name: USDC - symbol: USDC - decimals: 6 diff --git a/typescript/infra/config/environments/mainnet3/warp/addresses.json b/typescript/infra/config/environments/mainnet3/warp/artifacts/addresses.json similarity index 100% rename from typescript/infra/config/environments/mainnet3/warp/addresses.json rename to typescript/infra/config/environments/mainnet3/warp/artifacts/addresses.json diff --git a/typescript/infra/config/environments/mainnet3/warp/ancient8-USDC-addresses.json b/typescript/infra/config/environments/mainnet3/warp/artifacts/ancient8-USDC-addresses.json similarity index 100% rename from typescript/infra/config/environments/mainnet3/warp/ancient8-USDC-addresses.json rename to typescript/infra/config/environments/mainnet3/warp/artifacts/ancient8-USDC-addresses.json diff --git a/typescript/infra/config/environments/mainnet3/warp/arbitrum-TIA-addresses.json b/typescript/infra/config/environments/mainnet3/warp/artifacts/arbitrum-TIA-addresses.json similarity index 100% rename from typescript/infra/config/environments/mainnet3/warp/arbitrum-TIA-addresses.json rename to typescript/infra/config/environments/mainnet3/warp/artifacts/arbitrum-TIA-addresses.json diff --git a/typescript/infra/config/environments/mainnet3/warp/arbitrum-neutron-eclip-addresses.json b/typescript/infra/config/environments/mainnet3/warp/artifacts/arbitrum-neutron-eclip-addresses.json similarity index 100% rename from typescript/infra/config/environments/mainnet3/warp/arbitrum-neutron-eclip-addresses.json rename to typescript/infra/config/environments/mainnet3/warp/artifacts/arbitrum-neutron-eclip-addresses.json diff --git a/typescript/infra/config/environments/mainnet3/warp/eclipse-stride-TIA-addresses.json b/typescript/infra/config/environments/mainnet3/warp/artifacts/eclipse-stride-TIA-addresses.json similarity index 100% rename from typescript/infra/config/environments/mainnet3/warp/eclipse-stride-TIA-addresses.json rename to typescript/infra/config/environments/mainnet3/warp/artifacts/eclipse-stride-TIA-addresses.json diff --git a/typescript/infra/config/environments/mainnet3/warp/eclipse-stride-stTIA-addresses.json b/typescript/infra/config/environments/mainnet3/warp/artifacts/eclipse-stride-stTIA-addresses.json similarity index 100% rename from typescript/infra/config/environments/mainnet3/warp/eclipse-stride-stTIA-addresses.json rename to typescript/infra/config/environments/mainnet3/warp/artifacts/eclipse-stride-stTIA-addresses.json diff --git a/typescript/infra/config/environments/mainnet3/warp/inevm-USDC-addresses.json b/typescript/infra/config/environments/mainnet3/warp/artifacts/inevm-USDC-addresses.json similarity index 100% rename from typescript/infra/config/environments/mainnet3/warp/inevm-USDC-addresses.json rename to typescript/infra/config/environments/mainnet3/warp/artifacts/inevm-USDC-addresses.json diff --git a/typescript/infra/config/environments/mainnet3/warp/inevm-USDT-addresses.json b/typescript/infra/config/environments/mainnet3/warp/artifacts/inevm-USDT-addresses.json similarity index 100% rename from typescript/infra/config/environments/mainnet3/warp/inevm-USDT-addresses.json rename to typescript/infra/config/environments/mainnet3/warp/artifacts/inevm-USDT-addresses.json diff --git a/typescript/infra/config/environments/mainnet3/warp/injective-inevm-addresses.json b/typescript/infra/config/environments/mainnet3/warp/artifacts/injective-inevm-addresses.json similarity index 100% rename from typescript/infra/config/environments/mainnet3/warp/injective-inevm-addresses.json rename to typescript/infra/config/environments/mainnet3/warp/artifacts/injective-inevm-addresses.json diff --git a/typescript/infra/config/environments/mainnet3/warp/manta-TIA-addresses.json b/typescript/infra/config/environments/mainnet3/warp/artifacts/manta-TIA-addresses.json similarity index 100% rename from typescript/infra/config/environments/mainnet3/warp/manta-TIA-addresses.json rename to typescript/infra/config/environments/mainnet3/warp/artifacts/manta-TIA-addresses.json diff --git a/typescript/infra/config/environments/mainnet3/warp/merkly-erc20-addresses.json b/typescript/infra/config/environments/mainnet3/warp/artifacts/merkly-erc20-addresses.json similarity index 100% rename from typescript/infra/config/environments/mainnet3/warp/merkly-erc20-addresses.json rename to typescript/infra/config/environments/mainnet3/warp/artifacts/merkly-erc20-addresses.json diff --git a/typescript/infra/config/environments/mainnet3/warp/merkly-eth-addresses.json b/typescript/infra/config/environments/mainnet3/warp/artifacts/merkly-eth-addresses.json similarity index 100% rename from typescript/infra/config/environments/mainnet3/warp/merkly-eth-addresses.json rename to typescript/infra/config/environments/mainnet3/warp/artifacts/merkly-eth-addresses.json diff --git a/typescript/infra/config/environments/mainnet3/warp/merkly-nft-addresses.json b/typescript/infra/config/environments/mainnet3/warp/artifacts/merkly-nft-addresses.json similarity index 100% rename from typescript/infra/config/environments/mainnet3/warp/merkly-nft-addresses.json rename to typescript/infra/config/environments/mainnet3/warp/artifacts/merkly-nft-addresses.json diff --git a/typescript/infra/config/environments/mainnet3/warp/renzo-ezETH-addresses-v1.json b/typescript/infra/config/environments/mainnet3/warp/artifacts/renzo-ezETH-addresses-v1.json similarity index 100% rename from typescript/infra/config/environments/mainnet3/warp/renzo-ezETH-addresses-v1.json rename to typescript/infra/config/environments/mainnet3/warp/artifacts/renzo-ezETH-addresses-v1.json diff --git a/typescript/infra/config/environments/mainnet3/warp/renzo-ezETH-addresses-v3.json b/typescript/infra/config/environments/mainnet3/warp/artifacts/renzo-ezETH-addresses-v3.json similarity index 100% rename from typescript/infra/config/environments/mainnet3/warp/renzo-ezETH-addresses-v3.json rename to typescript/infra/config/environments/mainnet3/warp/artifacts/renzo-ezETH-addresses-v3.json diff --git a/typescript/infra/config/environments/mainnet3/warp/verification.json b/typescript/infra/config/environments/mainnet3/warp/artifacts/verification.json similarity index 100% rename from typescript/infra/config/environments/mainnet3/warp/verification.json rename to typescript/infra/config/environments/mainnet3/warp/artifacts/verification.json diff --git a/typescript/infra/config/environments/mainnet3/warp/viction-ETH-addresses.json b/typescript/infra/config/environments/mainnet3/warp/artifacts/viction-ETH-addresses.json similarity index 100% rename from typescript/infra/config/environments/mainnet3/warp/viction-ETH-addresses.json rename to typescript/infra/config/environments/mainnet3/warp/artifacts/viction-ETH-addresses.json diff --git a/typescript/infra/config/environments/mainnet3/warp/viction-USDC-addresses.json b/typescript/infra/config/environments/mainnet3/warp/artifacts/viction-USDC-addresses.json similarity index 100% rename from typescript/infra/config/environments/mainnet3/warp/viction-USDC-addresses.json rename to typescript/infra/config/environments/mainnet3/warp/artifacts/viction-USDC-addresses.json diff --git a/typescript/infra/config/environments/mainnet3/warp/viction-USDT-addresses.json b/typescript/infra/config/environments/mainnet3/warp/artifacts/viction-USDT-addresses.json similarity index 100% rename from typescript/infra/config/environments/mainnet3/warp/viction-USDT-addresses.json rename to typescript/infra/config/environments/mainnet3/warp/artifacts/viction-USDT-addresses.json diff --git a/typescript/infra/config/environments/mainnet3/warp/bsc-lumia-LUMIA-deployments.yaml b/typescript/infra/config/environments/mainnet3/warp/bsc-lumia-LUMIA-deployments.yaml deleted file mode 100644 index d106ac884..000000000 --- a/typescript/infra/config/environments/mainnet3/warp/bsc-lumia-LUMIA-deployments.yaml +++ /dev/null @@ -1,30 +0,0 @@ -# Configs and artifacts for the deployment of Hyperlane Warp Routes -# Between Ethereum and Binance Smart Chain and Lumia -description: Hyperlane Warp Route artifacts -timestamp: '2024-10-18T14:00:00.000Z' -deployer: Abacus Works (Hyperlane) -data: - config: - ethereum: - protocolType: ethereum - type: collateral - hypAddress: '0xdD313D475f8A9d81CBE2eA953a357f52e10BA357' - tokenAddress: '0xd9343a049d5dbd89cd19dc6bca8c48fb3a0a42a7' - tokenCoinGeckoId: lumia - name: Lumia Token - symbol: LUMIA - decimals: 18 - bsc: - protocolType: ethereum - type: synthetic - hypAddress: '0x7F39BcdCa8E0E581c1d43aaa1cB862AA1c8C2047' - name: Lumia Token - symbol: LUMIA - decimals: 18 - lumia: - protocolType: ethereum - type: native - hypAddress: '0x6a77331cE28E47c3Cb9Fea48AB6cD1e9594ce0A9' - name: Lumia Token - symbol: LUMIA - decimals: 18 diff --git a/typescript/infra/config/environments/mainnet3/warp/eclipse-ORCA-deployments.yaml b/typescript/infra/config/environments/mainnet3/warp/eclipse-ORCA-deployments.yaml deleted file mode 100644 index 8205cc93e..000000000 --- a/typescript/infra/config/environments/mainnet3/warp/eclipse-ORCA-deployments.yaml +++ /dev/null @@ -1,24 +0,0 @@ -# Configs and artifacts for the deployment of Hyperlane Warp Routes -description: Hyperlane Warp Route artifacts -timestamp: '2024-09-19T16:00:00.000Z' -deployer: Abacus Works (Hyperlane) -data: - config: - solanamainnet: - protocolType: sealevel - type: collateral - hypAddress: '8acihSm2QTGswniKgdgr4JBvJihZ1cakfvbqWCPBLoSp' - tokenAddress: 'orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE' - tokenCoinGeckoId: orca - name: Orca - symbol: ORCA - decimals: 6 - eclipsemainnet: - protocolType: sealevel - type: synthetic - hypAddress: '8CvWJS7SPtauAXinJUURkBDLsGUXWiiTdENkEFUPjQ9j' - tokenAddress: '2tGbYEm4nuPFyS6zjDTELzEhvVKizgKewi6xT7AaSKzn' - isSpl2022: true - name: Orca - symbol: ORCA - decimals: 6 diff --git a/typescript/infra/config/environments/mainnet3/warp/eclipse-SOL-deployments.yaml b/typescript/infra/config/environments/mainnet3/warp/eclipse-SOL-deployments.yaml deleted file mode 100644 index 711e6d428..000000000 --- a/typescript/infra/config/environments/mainnet3/warp/eclipse-SOL-deployments.yaml +++ /dev/null @@ -1,24 +0,0 @@ -# Configs and artifacts for the deployment of Hyperlane Warp Routes -# Between injective and inevm -description: Hyperlane Warp Route artifacts -timestamp: '2024-09-19T16:00:00.000Z' -deployer: Abacus Works (Hyperlane) -data: - config: - solanamainnet: - protocolType: sealevel - type: native - hypAddress: '8DtAGQpcMuD5sG3KdxDy49ydqXUggR1LQtebh2TECbAc' - tokenCoinGeckoId: solana - name: Solana - symbol: SOL - decimals: 9 - eclipsemainnet: - protocolType: sealevel - type: synthetic - hypAddress: 'FJu4E1BDYKVg7aTWdwATZRUvytJZ8ZZ2gQuvPfMWAz9y' - tokenAddress: 'BeRUj3h7BqkbdfFU7FBNYbodgf8GCHodzKvF9aVjNNfL' - isSpl2022: true - name: Solana - symbol: SOL - decimals: 9 diff --git a/typescript/infra/config/environments/mainnet3/warp/eclipse-USDC-deployments.yaml b/typescript/infra/config/environments/mainnet3/warp/eclipse-USDC-deployments.yaml deleted file mode 100644 index 7405cb94d..000000000 --- a/typescript/infra/config/environments/mainnet3/warp/eclipse-USDC-deployments.yaml +++ /dev/null @@ -1,35 +0,0 @@ -# Configs and artifacts for the deployment of Hyperlane Warp Routes -# Between injective and inevm -description: Hyperlane Warp Route artifacts -timestamp: '2024-09-19T16:00:00.000Z' -deployer: Abacus Works (Hyperlane) -data: - config: - ethereum: - protocolType: ethereum - type: collateral - hypAddress: '0xe1De9910fe71cC216490AC7FCF019e13a34481D7' - tokenAddress: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48' # USDC - tokenCoinGeckoId: usd-coin - name: USDC - symbol: USDC - decimals: 6 - solanamainnet: - protocolType: sealevel - type: collateral - hypAddress: '3EpVCPUgyjq2MfGeCttyey6bs5zya5wjYZ2BE6yDg6bm' - tokenAddress: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v' - tokenCoinGeckoId: usd-coin - isSpl2022: false - name: USDC - symbol: USDC - decimals: 6 - eclipsemainnet: - protocolType: sealevel - type: synthetic - hypAddress: 'EqRSt9aUDMKYKhzd1DGMderr3KNp29VZH3x5P7LFTC8m' - tokenAddress: 'AKEWE7Bgh87GPp171b4cJPSSZfmZwQ3KaqYqXoKLNAEE' - isSpl2022: true - name: USDC - symbol: USDC - decimals: 6 diff --git a/typescript/infra/config/environments/mainnet3/warp/eclipse-USDT-deployments.yaml b/typescript/infra/config/environments/mainnet3/warp/eclipse-USDT-deployments.yaml deleted file mode 100644 index 0a126ed76..000000000 --- a/typescript/infra/config/environments/mainnet3/warp/eclipse-USDT-deployments.yaml +++ /dev/null @@ -1,34 +0,0 @@ -# Configs and artifacts for the deployment of Hyperlane Warp Routes -description: Hyperlane Warp Route artifacts -timestamp: '2024-09-19T16:00:00.000Z' -deployer: Abacus Works (Hyperlane) -data: - config: - ethereum: - protocolType: ethereum - type: collateral - hypAddress: '0x647C621CEb36853Ef6A907E397Adf18568E70543' - tokenAddress: '0xdac17f958d2ee523a2206206994597c13d831ec7' # USDT - tokenCoinGeckoId: tether - name: USDT - symbol: USDT - decimals: 6 - solanamainnet: - protocolType: sealevel - type: collateral - hypAddress: 'Bk79wMjvpPCh5iQcCEjPWFcG1V2TfgdwaBsWBEYFYSNU' - tokenAddress: 'Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB' - tokenCoinGeckoId: tether - isSpl2022: false - name: USDT - symbol: USDT - decimals: 6 - eclipsemainnet: - protocolType: sealevel - type: synthetic - hypAddress: '5g5ujyYUNvdydwyDVCpZwPpgYRqH5RYJRi156cxyE3me' - tokenAddress: 'CEBP3CqAbW4zdZA57H2wfaSG1QNdzQ72GiQEbQXyW9Tm' - isSpl2022: true - name: USDT - symbol: USDT - decimals: 6 diff --git a/typescript/infra/config/environments/mainnet3/warp/eclipse-WBTC-deployments.yaml b/typescript/infra/config/environments/mainnet3/warp/eclipse-WBTC-deployments.yaml deleted file mode 100644 index bd993b8c9..000000000 --- a/typescript/infra/config/environments/mainnet3/warp/eclipse-WBTC-deployments.yaml +++ /dev/null @@ -1,23 +0,0 @@ -# Configs and artifacts for the deployment of Hyperlane Warp Routes -description: Hyperlane Warp Route artifacts -timestamp: '2024-09-19T16:00:00.000Z' -deployer: Abacus Works (Hyperlane) -data: - config: - ethereum: - protocolType: ethereum - type: collateral - hypAddress: '0x5B4e223DE74ef8c3218e66EEcC541003CAB3121A' - tokenAddress: '0x2260fac5e5542a773aa44fbcfedf7c193bc2c599' - name: WBTC - symbol: WBTC - decimals: 8 - eclipsemainnet: - protocolType: sealevel - type: synthetic - hypAddress: 'A7EGCDYFw5R7Jfm6cYtKvY8dmkrYMgwRCJFkyQwpHTYu' - tokenAddress: '7UTjr1VC6Z9DPsWD6mh5wPzNtufN17VnzpKS3ASpfAji' - isSpl2022: true - name: WBTC - symbol: WBTC - decimals: 8 diff --git a/typescript/infra/config/environments/mainnet3/warp/eclipse-WIF-deployments.yaml b/typescript/infra/config/environments/mainnet3/warp/eclipse-WIF-deployments.yaml deleted file mode 100644 index 1b7245c91..000000000 --- a/typescript/infra/config/environments/mainnet3/warp/eclipse-WIF-deployments.yaml +++ /dev/null @@ -1,25 +0,0 @@ -# Configs and artifacts for the deployment of Hyperlane Warp Routes -# Between injective and inevm -description: Hyperlane Warp Route artifacts -timestamp: '2024-09-19T16:00:00.000Z' -deployer: Abacus Works (Hyperlane) -data: - config: - solanamainnet: - protocolType: sealevel - type: collateral - hypAddress: 'CuQmsT4eSF4dYiiGUGYYQxJ7c58pUAD5ADE3BbFGzQKx' - tokenAddress: 'EKpQGSJtjMFqKZ9KQanSqYXRcF8fBopzLHYxdM65zcjm' - tokenCoinGeckoId: dogwifcoin - name: dogwifhat - symbol: WIF - decimals: 9 - eclipsemainnet: - protocolType: sealevel - type: synthetic - hypAddress: '6tBGmKNxirxBYnm9khkaTtcr2fhJ9YviCgRm1RWM8NJv' - tokenAddress: '841P4tebEgNux2jaWSjCoi9LhrVr9eHGjLc758Va3RPH' - isSpl2022: false - name: dogwifhat - symbol: WIF - decimals: 9 diff --git a/typescript/infra/config/environments/mainnet3/warp/eclipse-tETH-deployments.yaml b/typescript/infra/config/environments/mainnet3/warp/eclipse-tETH-deployments.yaml deleted file mode 100644 index 1f77a34e5..000000000 --- a/typescript/infra/config/environments/mainnet3/warp/eclipse-tETH-deployments.yaml +++ /dev/null @@ -1,24 +0,0 @@ -# Configs and artifacts for the deployment of Hyperlane Warp Routes -# Between injective and inevm -description: Hyperlane Warp Route artifacts -timestamp: '2024-09-19T16:00:00.000Z' -deployer: Abacus Works (Hyperlane) -data: - config: - ethereum: - protocolType: ethereum - type: collateral - hypAddress: '0xc2495f3183F043627CAECD56dAaa726e3B2D9c09' - tokenAddress: '0x19e099B7aEd41FA52718D780dDA74678113C0b32' - name: Turbo Eth - symbol: tETH - decimals: 18 - eclipsemainnet: - protocolType: sealevel - type: synthetic - hypAddress: '6GM7hy6M6LjhadG1xuKXPQ3jPC1eieEszR8DforoRzUp' - tokenAddress: 'GU7NS9xCwgNPiAdJ69iusFrRfawjDDPjeMBovhV1d4kn' - isSpl2022: false - name: Turbo Eth - symbol: tETH - decimals: 9 diff --git a/typescript/infra/config/environments/mainnet3/warp/ethereumUSDC-inevm-deployments.yaml b/typescript/infra/config/environments/mainnet3/warp/ethereumUSDC-inevm-deployments.yaml deleted file mode 100644 index 90f22e0df..000000000 --- a/typescript/infra/config/environments/mainnet3/warp/ethereumUSDC-inevm-deployments.yaml +++ /dev/null @@ -1,23 +0,0 @@ -# Configs and artifacts for the deployment of Hyperlane Warp Routes -# Between injective and inevm -description: Hyperlane Warp Route artifacts -timestamp: '2024-02-06T16:00:00.000Z' -deployer: Abacus Works (Hyperlane) -data: - config: - ethereum: - protocolType: ethereum - type: collateral - hypAddress: '0xED56728fb977b0bBdacf65bCdD5e17Bb7e84504f' - tokenAddress: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48' # USDC - tokenCoinGeckoId: usd-coin - name: USDC - symbol: USDC - decimals: 6 - inevm: - protocolType: ethereum - type: synthetic - hypAddress: '0x8358D8291e3bEDb04804975eEa0fe9fe0fAfB147' - name: USDC - symbol: USDC - decimals: 6 diff --git a/typescript/infra/config/environments/mainnet3/warp/ethereumUSDT-inevm-deployments.yaml b/typescript/infra/config/environments/mainnet3/warp/ethereumUSDT-inevm-deployments.yaml deleted file mode 100644 index 91976ddd9..000000000 --- a/typescript/infra/config/environments/mainnet3/warp/ethereumUSDT-inevm-deployments.yaml +++ /dev/null @@ -1,23 +0,0 @@ -# Configs and artifacts for the deployment of Hyperlane Warp Routes -# Between injective and inevm -description: Hyperlane Warp Route artifacts -timestamp: '2024-02-06T16:00:00.000Z' -deployer: Abacus Works (Hyperlane) -data: - config: - ethereum: - protocolType: ethereum - type: collateral - hypAddress: '0xab852e67bf03E74C89aF67C4BA97dd1088D3dA19' - tokenAddress: '0xdac17f958d2ee523a2206206994597c13d831ec7' # USDT - tokenCoinGeckoId: tether - name: Tether USD - symbol: USDT - decimals: 6 - inevm: - protocolType: ethereum - type: synthetic - hypAddress: '0x97423A68BAe94b5De52d767a17aBCc54c157c0E5' - name: Tether USD - symbol: USDT - decimals: 6 diff --git a/typescript/infra/config/environments/mainnet3/warp/injective-inevm-deployments.yaml b/typescript/infra/config/environments/mainnet3/warp/injective-inevm-deployments.yaml deleted file mode 100644 index cd39382ea..000000000 --- a/typescript/infra/config/environments/mainnet3/warp/injective-inevm-deployments.yaml +++ /dev/null @@ -1,23 +0,0 @@ -# Configs and artifacts for the deployment of Hyperlane Warp Routes -# Between injective and inevm -description: Hyperlane Warp Route artifacts -timestamp: '2024-01-31T16:00:00.000Z' -deployer: Abacus Works (Hyperlane) -data: - config: - injective: - protocolType: cosmos - type: native - hypAddress: inj1mv9tjvkaw7x8w8y9vds8pkfq46g2vcfkjehc6k - tokenCoinGeckoId: injective-protocol - name: Injective Coin - symbol: INJ - decimals: 18 - ibcDenom: inj - inevm: - protocolType: ethereum - type: native - hypAddress: '0x26f32245fCF5Ad53159E875d5Cae62aEcf19c2d4' - name: Injective coin - symbol: INJ - decimals: 18 diff --git a/typescript/infra/config/environments/mainnet3/warp/nautilus-solana-bsc-deployments.yaml b/typescript/infra/config/environments/mainnet3/warp/nautilus-solana-bsc-deployments.yaml deleted file mode 100644 index e3e877007..000000000 --- a/typescript/infra/config/environments/mainnet3/warp/nautilus-solana-bsc-deployments.yaml +++ /dev/null @@ -1,31 +0,0 @@ -# Configs and artifacts for the deployment of Hyperlane Warp Routes -# Between nautilus and bsc, solana -description: Hyperlane Warp Route artifacts -timestamp: '2023-09-23T16:00:00.000Z' -deployer: Abacus Works (Hyperlane) -data: - config: - bsc: - protocolType: ethereum - type: collateral - hypAddress: '0xC27980812E2E66491FD457D488509b7E04144b98' - tokenAddress: '0x37a56cdcD83Dce2868f721De58cB3830C44C6303' - name: Zebec - symbol: ZBC - decimals: 9 - nautilus: - protocolType: ethereum - type: native - hypAddress: '0x4501bBE6e731A4bC5c60C03A77435b2f6d5e9Fe7' - name: Zebec - symbol: ZBC - decimals: 18 - solana: - protocolType: sealevel - type: collateral - tokenAddress: 'wzbcJyhGhQDLTV1S99apZiiBdE4jmYfbw99saMMdP59' - hypAddress: 'EJqwFjvVJSAxH8Ur2PYuMfdvoJeutjmH6GkoEFQ4MdSa' - name: Zebec - symbol: ZBC - decimals: 9 - isSpl2022: true diff --git a/typescript/infra/config/environments/mainnet3/warp/neutron-mantapacific-deployments.yaml b/typescript/infra/config/environments/mainnet3/warp/neutron-mantapacific-deployments.yaml deleted file mode 100644 index bf4e1770a..000000000 --- a/typescript/infra/config/environments/mainnet3/warp/neutron-mantapacific-deployments.yaml +++ /dev/null @@ -1,23 +0,0 @@ -# Configs and artifacts for the deployment of Hyperlane Warp Routes -# Between neutron and mantapacific -description: Hyperlane Warp Route artifacts -timestamp: '2023-09-23T16:00:00.000Z' -deployer: Abacus Works (Hyperlane) -data: - config: - neutron: - protocolType: cosmos - type: collateral - hypAddress: neutron1ch7x3xgpnj62weyes8vfada35zff6z59kt2psqhnx9gjnt2ttqdqtva3pa - tokenAddress: ibc/773B4D0A3CD667B2275D5A4A7A2F0909C0BA0F4059C0B9181E680DDF4965DCC7 - tokenCoinGeckoId: celestia - name: Celestia - symbol: TIA - decimals: 6 - mantapacific: - protocolType: ethereum - type: synthetic - hypAddress: '0x6Fae4D9935E2fcb11fC79a64e917fb2BF14DaFaa' - name: Celestia - symbol: TIA - decimals: 6 diff --git a/typescript/infra/config/environments/mainnet3/warp/sei-FASTUSD-deployments.yaml b/typescript/infra/config/environments/mainnet3/warp/sei-FASTUSD-deployments.yaml deleted file mode 100644 index ed9672e41..000000000 --- a/typescript/infra/config/environments/mainnet3/warp/sei-FASTUSD-deployments.yaml +++ /dev/null @@ -1,22 +0,0 @@ -description: Hyperlane Warp Route artifacts -timestamp: '2024-10-17T14:00:00.000Z' -deployer: Abacus Works (Hyperlane) -data: - config: - ethereum: - protocolType: ethereum - type: collateral - hypAddress: '0x9AD81058c6C3Bf552C9014CB30E824717A0ee21b' - tokenAddress: '0x15700B564Ca08D9439C58cA5053166E8317aa138' - tokenCoinGeckoId: elixir-deusd # unique setup where we want deUSD to be deposited as collateral and we want fastUSD to be minted as a synthetic on sei - name: fastUSD - symbol: fastUSD - decimals: 18 - sei: - protocolType: ethereum - type: xERC20 - hypAddress: '0xeA895A7Ff45d8d3857A04c1E38A362f3bd9a076f' - tokenAddress: '0x37a4dD9CED2b19Cfe8FAC251cd727b5787E45269' - name: fastUSD - symbol: fastUSD - decimals: 18 diff --git a/typescript/infra/config/environments/mainnet3/warp/stTIA-eclipse-stride-deployments.yaml b/typescript/infra/config/environments/mainnet3/warp/stTIA-eclipse-stride-deployments.yaml deleted file mode 100644 index 7f18e471c..000000000 --- a/typescript/infra/config/environments/mainnet3/warp/stTIA-eclipse-stride-deployments.yaml +++ /dev/null @@ -1,24 +0,0 @@ -# Configs and artifacts for the deployment of Hyperlane Warp Routes -description: Hyperlane Warp Route artifacts -timestamp: '2024-10-18T14:00:00.000Z' -deployer: Abacus Works (Hyperlane) -data: - config: - stride: - protocolType: cosmos - type: collateral - hypAddress: stride134axwdlam929m3mar3wv95nvkyep7mr87ravkqcpf8dfe3v0pjlqwrw6ee - tokenAddress: 'stutia' - tokenCoinGeckoId: stride-staked-tia - name: Stride Staked TIA - symbol: stTIA - decimals: 6 - eclipsemainnet: - protocolType: sealevel - type: synthetic - hypAddress: 'tKUHyJ5NxhnwU94JUmzh1ekukDcHHX8mZF6fqxbMwX6' - tokenAddress: 'V5m1Cc9VK61mKL8xVYrjR7bjD2BC5VpADLa6ws3G8KM' - isSpl2022: true - name: Turbo Eth - symbol: tETH - decimals: 6 diff --git a/typescript/infra/config/environments/mainnet3/warp/viction-ethereum-ETH-deployments.yaml b/typescript/infra/config/environments/mainnet3/warp/viction-ethereum-ETH-deployments.yaml deleted file mode 100644 index c3e03b54d..000000000 --- a/typescript/infra/config/environments/mainnet3/warp/viction-ethereum-ETH-deployments.yaml +++ /dev/null @@ -1,22 +0,0 @@ -# Configs and artifacts for the deployment of Hyperlane Warp Routes -# Between viction and ethereum, ETH -description: Hyperlane Warp Route artifacts -timestamp: '2023-02-14T20:00:00.000Z' -deployer: Abacus Works (Hyperlane) -data: - config: - ethereum: - protocolType: ethereum - type: native - hypAddress: '0x15b5D6B614242B118AA404528A7f3E2Ad241e4A4' - tokenCoinGeckoId: ethereum - name: Ether - symbol: ETH - decimals: 18 - viction: - protocolType: ethereum - type: synthetic - hypAddress: '0x182E8d7c5F1B06201b102123FC7dF0EaeB445a7B' - name: ETH - symbol: ETH - decimals: 18 diff --git a/typescript/infra/config/environments/mainnet3/warp/viction-ethereum-USDC-deployments.yaml b/typescript/infra/config/environments/mainnet3/warp/viction-ethereum-USDC-deployments.yaml deleted file mode 100644 index 8a84e6a7c..000000000 --- a/typescript/infra/config/environments/mainnet3/warp/viction-ethereum-USDC-deployments.yaml +++ /dev/null @@ -1,23 +0,0 @@ -# Configs and artifacts for the deployment of Hyperlane Warp Routes -# Between viction and ethereum, USDC -description: Hyperlane Warp Route artifacts -timestamp: '2023-02-14T20:00:00.000Z' -deployer: Abacus Works (Hyperlane) -data: - config: - ethereum: - protocolType: ethereum - type: collateral - hypAddress: '0x31Dca7762930f56D81292f85E65c9D67575804fE' - tokenAddress: '0x31Dca7762930f56D81292f85E65c9D67575804fE' # USDC - tokenCoinGeckoId: usd-coin - name: USD Coin - symbol: USDC - decimals: 6 - viction: - protocolType: ethereum - type: synthetic - hypAddress: '0xBDa330Ea8F3005C421C8088e638fBB64fA71b9e0' - name: USDC - symbol: USDC - decimals: 6 diff --git a/typescript/infra/config/environments/mainnet3/warp/viction-ethereum-USDT-deployments.yaml b/typescript/infra/config/environments/mainnet3/warp/viction-ethereum-USDT-deployments.yaml deleted file mode 100644 index a22598042..000000000 --- a/typescript/infra/config/environments/mainnet3/warp/viction-ethereum-USDT-deployments.yaml +++ /dev/null @@ -1,23 +0,0 @@ -# Configs and artifacts for the deployment of Hyperlane Warp Routes -# Between viction and ethereum, USDT -description: Hyperlane Warp Route artifacts -timestamp: '2023-02-14T20:00:00.000Z' -deployer: Abacus Works (Hyperlane) -data: - config: - ethereum: - protocolType: ethereum - type: collateral - hypAddress: '0x4221a16A01F61c2b38A03C52d828a7041f6AAA49' - tokenAddress: '0xdAC17F958D2ee523a2206206994597C13D831ec7' # USDT - tokenCoinGeckoId: tether - name: Tether USD - symbol: USDT - decimals: 6 - viction: - protocolType: ethereum - type: synthetic - hypAddress: '0x48083c69f5a42c6b69abbad48ae195bd36770ee2' - name: USDT - symbol: USDT - decimals: 6 diff --git a/typescript/infra/config/environments/mainnet3/warp/warpIds.ts b/typescript/infra/config/environments/mainnet3/warp/warpIds.ts index d70348b56..a68ed19c8 100644 --- a/typescript/infra/config/environments/mainnet3/warp/warpIds.ts +++ b/typescript/infra/config/environments/mainnet3/warp/warpIds.ts @@ -9,10 +9,11 @@ export enum WarpRouteIds { EclipseEthereumTETH = 'tETH/eclipsemainnet-ethereum', EclipseEthereumWBTC = 'WBTC/eclipsemainnet-ethereum', EclipseEthereumWeETHs = 'weETHs/eclipsemainnet-ethereum', + EclipseSolanaORCA = 'ORCA/eclipsemainnet-solanamainnet', EclipseSolanaSOL = 'SOL/eclipsemainnet-solanamainnet', EclipseSolanaWIF = 'WIF/eclipsemainnet-solanamainnet', - EclipseStrideSTTIA = 'stTIA/eclipse-stride', - EclipseStrideTIA = 'TIA/eclipse-stride', + EclipseStrideSTTIA = 'stTIA/eclipsemainnet-stride', + EclipseStrideTIA = 'TIA/eclipsemainnet-stride', EthereumInevmUSDC = 'USDC/ethereum-inevm', EthereumInevmUSDT = 'USDT/ethereum-inevm', EthereumSeiFastUSD = 'FASTUSD/ethereum-sei', diff --git a/typescript/infra/config/registry.ts b/typescript/infra/config/registry.ts index 4b72c9f5b..8b9ea5edb 100644 --- a/typescript/infra/config/registry.ts +++ b/typescript/infra/config/registry.ts @@ -12,6 +12,7 @@ import { ChainMap, ChainMetadata, ChainName, + WarpCoreConfig, getDomainId as resolveDomainId, getReorgPeriod as resolveReorgPeriod, } from '@hyperlane-xyz/sdk'; @@ -91,7 +92,7 @@ export function getChainAddresses(): ChainMap { return getRegistry().getAddresses(); } -export function getWarpAddresses(warpRouteId: string) { +export function getWarpCoreConfig(warpRouteId: string): WarpCoreConfig { const registry = getRegistry(); const warpRouteConfig = registry.getWarpRoute(warpRouteId); @@ -100,8 +101,12 @@ export function getWarpAddresses(warpRouteId: string) { `Warp route config for ${warpRouteId} not found in registry`, ); } + return warpRouteConfig; +} - return warpConfigToWarpAddresses(warpRouteConfig); +export function getWarpAddresses(warpRouteId: string) { + const warpCoreConfig = getWarpCoreConfig(warpRouteId); + return warpConfigToWarpAddresses(warpCoreConfig); } export function getEnvChains(env: DeployEnvironment): ChainName[] { diff --git a/typescript/infra/helm/warp-routes/templates/_helpers.tpl b/typescript/infra/helm/warp-routes/templates/_helpers.tpl index 52bc42a86..bc732a5a3 100644 --- a/typescript/infra/helm/warp-routes/templates/_helpers.tpl +++ b/typescript/infra/helm/warp-routes/templates/_helpers.tpl @@ -72,11 +72,11 @@ The warp-routes container value: pretty command: - ./node_modules/.bin/tsx - - ./typescript/infra/scripts/warp-routes/monitor-warp-routes-balances.ts + - ./typescript/infra/scripts/warp-routes/monitor/monitor-warp-route-balances.ts - -v - - "10000" - - -f - - {{ .Values.configFilePath }} + - "30000" + - --warpRouteId + - {{ .Values.warpRouteId }} - -e - {{ .Values.environment}} envFrom: diff --git a/typescript/infra/helm/warp-routes/templates/env-var-external-secret.yaml b/typescript/infra/helm/warp-routes/templates/env-var-external-secret.yaml index d1f1eda25..5bad068b9 100644 --- a/typescript/infra/helm/warp-routes/templates/env-var-external-secret.yaml +++ b/typescript/infra/helm/warp-routes/templates/env-var-external-secret.yaml @@ -22,6 +22,7 @@ spec: data: GCP_SECRET_OVERRIDES_ENABLED: "true" GCP_SECRET_OVERRIDE_{{ $.Values.hyperlane.runEnv | upper }}_COINGECKO_API_KEY: {{ printf "'{{ .%s_coingecko_api_key | toString }}'" .Values.hyperlane.runEnv }} + GCP_SECRET_OVERRIDE_HYPERLANE_{{ .Values.hyperlane.runEnv | upper }}_KEY_DEPLOYER: {{ print "'{{ .deployer_key | toString }}'" }} {{/* * For each network, create an environment variable with the RPC endpoint. * The templating of external-secrets will use the data section below to know how @@ -34,6 +35,9 @@ spec: - secretKey: {{ printf "%s_coingecko_api_key" .Values.hyperlane.runEnv }} remoteRef: key: {{ printf "%s-coingecko-api-key" .Values.hyperlane.runEnv }} + - secretKey: deployer_key + remoteRef: + key: {{ printf "hyperlane-%s-key-deployer" .Values.hyperlane.runEnv }} {{/* * For each network, load the secret in GCP secret manager with the form: environment-rpc-endpoint-network, * and associate it with the secret key networkname_rpc. diff --git a/typescript/infra/scripts/warp-routes/deploy-warp-monitor.ts b/typescript/infra/scripts/warp-routes/deploy-warp-monitor.ts index 95a749ace..bc19f434f 100644 --- a/typescript/infra/scripts/warp-routes/deploy-warp-monitor.ts +++ b/typescript/infra/scripts/warp-routes/deploy-warp-monitor.ts @@ -1,32 +1,58 @@ +import { checkbox } from '@inquirer/prompts'; import yargs from 'yargs'; import { Contexts } from '../../config/contexts.js'; +import { WarpRouteIds } from '../../config/environments/mainnet3/warp/warpIds.js'; import { HelmCommand } from '../../src/utils/helm.js'; import { WarpRouteMonitorHelmManager } from '../../src/warp/helm.js'; -import { assertCorrectKubeContext, getAgentConfig } from '../agent-utils.js'; +import { + assertCorrectKubeContext, + getAgentConfig, + getArgs, + withWarpRouteId, +} from '../agent-utils.js'; import { getEnvironmentConfig } from '../core-utils.js'; async function main() { - const { filePath } = await yargs(process.argv.slice(2)) - .alias('f', 'filePath') - .describe( - 'filePath', - 'indicate the filepath to the warp route yaml file relative to the monorepo root', - ) - .demandOption('filePath') - .string('filePath') - .parse(); - - const environment = 'mainnet3'; + const { environment, warpRouteId } = await withWarpRouteId(getArgs()).argv; + + let warpRouteIds; + if (warpRouteId) { + warpRouteIds = [warpRouteId]; + } else { + warpRouteIds = await getWarpRouteIdsInteractive(); + } + await assertCorrectKubeContext(getEnvironmentConfig(environment)); const agentConfig = getAgentConfig(Contexts.Hyperlane, environment); - const helmManager = new WarpRouteMonitorHelmManager( - filePath, - environment, - agentConfig.environmentChainNames, - ); - await helmManager.runHelmCommand(HelmCommand.InstallOrUpgrade); + const deployWarpMonitor = async (warpRouteId: string) => { + const helmManager = new WarpRouteMonitorHelmManager( + warpRouteId, + environment, + agentConfig.environmentChainNames, + ); + await helmManager.runHelmCommand(HelmCommand.InstallOrUpgrade); + }; + + for (const id of warpRouteIds) { + console.log(`Deploying Warp Monitor for Warp Route ID: ${id}`); + await deployWarpMonitor(id); + } +} + +async function getWarpRouteIdsInteractive() { + const choices = Object.values(WarpRouteIds).map((id) => ({ + value: id, + })); + + const selection = await checkbox({ + message: 'Select Warp Route IDs to deploy', + choices, + pageSize: 30, + }); + + return selection; } main() diff --git a/typescript/infra/scripts/warp-routes/monitor-warp-routes-balances.ts b/typescript/infra/scripts/warp-routes/monitor-warp-routes-balances.ts deleted file mode 100644 index 06b4fb78f..000000000 --- a/typescript/infra/scripts/warp-routes/monitor-warp-routes-balances.ts +++ /dev/null @@ -1,697 +0,0 @@ -import { SystemProgram } from '@solana/web3.js'; -import { ethers } from 'ethers'; -import { Gauge, Registry } from 'prom-client'; - -import { - ERC20__factory, - HypXERC20Lockbox__factory, - HypXERC20__factory, - IXERC20, - IXERC20__factory, -} from '@hyperlane-xyz/core'; -import { createWarpRouteConfigId } from '@hyperlane-xyz/registry'; -import { - ChainMap, - ChainMetadata, - ChainName, - CoinGeckoTokenPriceGetter, - CosmNativeTokenAdapter, - CwNativeTokenAdapter, - MultiProtocolProvider, - SealevelHypCollateralAdapter, - SealevelHypNativeAdapter, - SealevelHypSyntheticAdapter, - TokenType, - WarpRouteConfig, - WarpRouteConfigSchema, -} from '@hyperlane-xyz/sdk'; -import { - ProtocolType, - objMap, - promiseObjAll, - rootLogger, -} from '@hyperlane-xyz/utils'; - -import { DeployEnvironment } from '../../src/config/environment.js'; -import { fetchGCPSecret } from '../../src/utils/gcloud.js'; -import { startMetricsServer } from '../../src/utils/metrics.js'; -import { readYaml } from '../../src/utils/utils.js'; -import { getArgs } from '../agent-utils.js'; -import { getEnvironmentConfig } from '../core-utils.js'; - -const logger = rootLogger.child({ module: 'warp-balance-monitor' }); - -const metricsRegister = new Registry(); - -interface WarpRouteMetrics { - chain_name: ChainName; - token_address: string; - token_name: string; - wallet_address: string; - token_type: TokenType; - warp_route_id: string; - related_chain_names: string; -} - -type WarpRouteMetricLabels = keyof WarpRouteMetrics; - -const warpRouteMetricLabels: WarpRouteMetricLabels[] = [ - 'chain_name', - 'token_address', - 'token_name', - 'wallet_address', - 'token_type', - 'warp_route_id', - 'related_chain_names', -]; - -const warpRouteTokenBalance = new Gauge({ - name: 'hyperlane_warp_route_token_balance', - help: 'HypERC20 token balance of a Warp Route', - registers: [metricsRegister], - labelNames: warpRouteMetricLabels, -}); - -const warpRouteCollateralValue = new Gauge({ - name: 'hyperlane_warp_route_collateral_value', - help: 'Total value of collateral held in a HypERC20Collateral or HypNative contract of a Warp Route', - registers: [metricsRegister], - labelNames: warpRouteMetricLabels, -}); - -const xERC20LimitsGauge = new Gauge({ - name: 'hyperlane_xerc20_limits', - help: 'Current minting and burning limits of xERC20 tokens', - registers: [metricsRegister], - labelNames: ['chain_name', 'limit_type', 'token_name'], -}); - -interface xERC20Limit { - tokenName: string; - mint: number; - burn: number; - mintMax: number; - burnMax: number; -} - -interface WarpRouteInfo { - balance: number; - valueUSD?: number; -} - -export function readWarpRouteConfig(filePath: string) { - const config = readYaml(filePath); - if (!config) throw new Error(`No warp config found at ${filePath}`); - const result = WarpRouteConfigSchema.safeParse(config); - if (!result.success) { - const errorMessages = result.error.issues.map( - (issue: any) => `${issue.path} => ${issue.message}`, - ); - throw new Error(`Invalid warp config:\n ${errorMessages.join('\n')}`); - } - return result.data; -} - -async function main(): Promise { - const { checkFrequency, filePath, environment } = await getArgs() - .describe('checkFrequency', 'frequency to check balances in ms') - .demandOption('checkFrequency') - .alias('v', 'checkFrequency') // v as in Greek letter nu - .number('checkFrequency') - .alias('f', 'filePath') - .describe( - 'filePath', - 'indicate the filepatch to the warp route yaml file relative to typescript/infra', - ) - .demandOption('filePath') - .string('filePath') - .parse(); - - startMetricsServer(metricsRegister); - - const tokenConfig: WarpRouteConfig = - readWarpRouteConfig(filePath).data.config; - - const envConfig = getEnvironmentConfig(environment); - const registry = await envConfig.getRegistry(); - const chainMetadata = await registry.getMetadata(); - - await checkWarpRouteMetrics(checkFrequency, tokenConfig, chainMetadata); - - return true; -} - -// TODO: see issue https://github.com/hyperlane-xyz/hyperlane-monorepo/issues/2708 -async function checkBalance( - tokenConfig: WarpRouteConfig, - multiProtocolProvider: MultiProtocolProvider, - tokenPriceGetter: CoinGeckoTokenPriceGetter, -): Promise> { - const output = objMap( - tokenConfig, - async (chain: ChainName, token: WarpRouteConfig[ChainName]) => { - switch (token.type) { - case TokenType.native: { - switch (token.protocolType) { - case ProtocolType.Ethereum: { - const provider = multiProtocolProvider.getEthersV5Provider(chain); - const nativeBalance = await provider.getBalance(token.hypAddress); - - return getNativeTokenWarpInfo( - nativeBalance, - token.decimals, - tokenPriceGetter, - chain, - ); - } - case ProtocolType.Sealevel: { - const adapter = new SealevelHypNativeAdapter( - chain, - multiProtocolProvider, - { - token: token.tokenAddress, - warpRouter: token.hypAddress, - // Mailbox only required for transfers, using system as placeholder - mailbox: SystemProgram.programId.toBase58(), - }, - // Not used for native tokens, but required for the adapter - token?.isSpl2022 ?? false, - ); - const balance = ethers.BigNumber.from( - await adapter.getBalance(token.hypAddress), - ); - - return getNativeTokenWarpInfo( - balance, - token.decimals, - tokenPriceGetter, - chain, - ); - } - case ProtocolType.Cosmos: { - if (!token.ibcDenom) - throw new Error('IBC denom missing for native token'); - const adapter = new CosmNativeTokenAdapter( - chain, - multiProtocolProvider, - {}, - { ibcDenom: token.ibcDenom }, - ); - const tokenBalance = await adapter.getBalance(token.hypAddress); - - return getNativeTokenWarpInfo( - tokenBalance, - token.decimals, - tokenPriceGetter, - chain, - ); - } - } - break; - } - case TokenType.collateral: { - switch (token.protocolType) { - case ProtocolType.Ethereum: { - const provider = multiProtocolProvider.getEthersV5Provider(chain); - if (!token.tokenAddress) - throw new Error('Token address missing for collateral token'); - const tokenContract = ERC20__factory.connect( - token.tokenAddress, - provider, - ); - const collateralBalance = await tokenContract.balanceOf( - token.hypAddress, - ); - - return getCollateralTokenWarpInfo( - collateralBalance, - token.decimals, - tokenPriceGetter, - token.tokenCoinGeckoId, - ); - } - case ProtocolType.Sealevel: { - if (!token.tokenAddress) - throw new Error('Token address missing for collateral token'); - const adapter = new SealevelHypCollateralAdapter( - chain, - multiProtocolProvider, - { - token: token.tokenAddress, - warpRouter: token.hypAddress, - // Mailbox only required for transfers, using system as placeholder - mailbox: SystemProgram.programId.toBase58(), - }, - token?.isSpl2022 ?? false, - ); - const collateralBalance = ethers.BigNumber.from( - await adapter.getBalance(token.hypAddress), - ); - - return getCollateralTokenWarpInfo( - collateralBalance, - token.decimals, - tokenPriceGetter, - token.tokenCoinGeckoId, - ); - } - case ProtocolType.Cosmos: { - if (!token.tokenAddress) - throw new Error('Token address missing for cosmos token'); - const adapter = new CwNativeTokenAdapter( - chain, - multiProtocolProvider, - { - token: token.hypAddress, - }, - token.tokenAddress, - ); - const collateralBalance = ethers.BigNumber.from( - await adapter.getBalance(token.hypAddress), - ); - - return getCollateralTokenWarpInfo( - collateralBalance, - token.decimals, - tokenPriceGetter, - token.tokenCoinGeckoId, - ); - } - } - break; - } - case TokenType.synthetic: { - switch (token.protocolType) { - case ProtocolType.Ethereum: { - const provider = multiProtocolProvider.getEthersV5Provider(chain); - const tokenContract = ERC20__factory.connect( - token.hypAddress, - provider, - ); - const syntheticBalance = await tokenContract.totalSupply(); - return { - balance: parseFloat( - ethers.utils.formatUnits(syntheticBalance, token.decimals), - ), - }; - } - case ProtocolType.Sealevel: { - if (!token.tokenAddress) - throw new Error('Token address missing for synthetic token'); - const adapter = new SealevelHypSyntheticAdapter( - chain, - multiProtocolProvider, - { - token: token.tokenAddress, - warpRouter: token.hypAddress, - // Mailbox only required for transfers, using system as placeholder - mailbox: SystemProgram.programId.toBase58(), - }, - token?.isSpl2022 ?? false, - ); - const syntheticBalance = ethers.BigNumber.from( - await adapter.getTotalSupply(), - ); - return { - balance: parseFloat( - ethers.utils.formatUnits(syntheticBalance, token.decimals), - ), - }; - } - case ProtocolType.Cosmos: - // TODO - cosmos synthetic - return { balance: 0 }; - } - break; - } - case TokenType.XERC20: { - switch (token.protocolType) { - case ProtocolType.Ethereum: { - const provider = multiProtocolProvider.getEthersV5Provider(chain); - const hypXERC20 = HypXERC20__factory.connect( - token.hypAddress, - provider, - ); - const xerc20Address = await hypXERC20.wrappedToken(); - const xerc20 = IXERC20__factory.connect(xerc20Address, provider); - const syntheticBalance = await xerc20.totalSupply(); - - return { - balance: parseFloat( - ethers.utils.formatUnits(syntheticBalance, token.decimals), - ), - }; - } - default: - throw new Error( - `Unsupported protocol type ${token.protocolType} for token type ${token.type}`, - ); - } - } - case TokenType.XERC20Lockbox: { - switch (token.protocolType) { - case ProtocolType.Ethereum: { - if (!token.tokenAddress) - throw new Error( - 'Token address missing for xERC20Lockbox token', - ); - const provider = multiProtocolProvider.getEthersV5Provider(chain); - const hypXERC20Lockbox = HypXERC20Lockbox__factory.connect( - token.hypAddress, - provider, - ); - const xerc20LockboxAddress = await hypXERC20Lockbox.lockbox(); - const tokenContract = ERC20__factory.connect( - token.tokenAddress, - provider, - ); - - const collateralBalance = await tokenContract.balanceOf( - xerc20LockboxAddress, - ); - - return getCollateralTokenWarpInfo( - collateralBalance, - token.decimals, - tokenPriceGetter, - token.tokenCoinGeckoId, - ); - } - default: - throw new Error( - `Unsupported protocol type ${token.protocolType} for token type ${token.type}`, - ); - } - } - } - return { balance: 0 }; - }, - ); - - return promiseObjAll(output); -} - -export function updateTokenBalanceMetrics( - tokenConfig: WarpRouteConfig, - balances: ChainMap, -) { - objMap(tokenConfig, (chain: ChainName, token: WarpRouteConfig[ChainName]) => { - const metrics: WarpRouteMetrics = { - chain_name: chain, - token_address: token.tokenAddress ?? ethers.constants.AddressZero, - token_name: token.name, - wallet_address: token.hypAddress, - token_type: token.type, - warp_route_id: createWarpRouteConfigId( - token.symbol, - Object.keys(tokenConfig) as ChainName[], - ), - related_chain_names: Object.keys(tokenConfig) - .filter((chainName) => chainName !== chain) - .sort() - .join(','), - }; - - warpRouteTokenBalance.labels(metrics).set(balances[chain].balance); - if (balances[chain].valueUSD) { - warpRouteCollateralValue - .labels(metrics) - .set(balances[chain].valueUSD as number); - logger.debug('Collateral value updated for chain', { - chain, - related_chain_names: metrics.related_chain_names, - warp_route_id: metrics.warp_route_id, - token: metrics.token_name, - value: balances[chain].valueUSD, - }); - } - logger.debug('Wallet balance updated for chain', { - chain, - related_chain_names: metrics.related_chain_names, - warp_route_id: metrics.warp_route_id, - token: metrics.token_name, - balance: balances[chain].balance, - }); - }); -} - -export function updateXERC20LimitsMetrics( - xERC20Limits: ChainMap, -) { - objMap(xERC20Limits, (chain: ChainName, limits: xERC20Limit | undefined) => { - if (limits) { - xERC20LimitsGauge - .labels({ - chain_name: chain, - limit_type: 'mint', - token_name: limits.tokenName, - }) - .set(limits.mint); - xERC20LimitsGauge - .labels({ - chain_name: chain, - limit_type: 'burn', - token_name: limits.tokenName, - }) - .set(limits.burn); - xERC20LimitsGauge - .labels({ - chain_name: chain, - limit_type: 'mintMax', - token_name: limits.tokenName, - }) - .set(limits.mintMax); - xERC20LimitsGauge - .labels({ - chain_name: chain, - limit_type: 'burnMax', - token_name: limits.tokenName, - }) - .set(limits.burnMax); - logger.info('xERC20 limits updated for chain', { - chain, - limits, - }); - } - }); -} - -async function getXERC20Limits( - tokenConfig: WarpRouteConfig, - chainMetadata: ChainMap, -): Promise> { - const multiProtocolProvider = new MultiProtocolProvider(chainMetadata); - - const output = objMap( - tokenConfig, - async (chain: ChainName, token: WarpRouteConfig[ChainName]) => { - switch (token.protocolType) { - case ProtocolType.Ethereum: { - switch (token.type) { - case TokenType.XERC20Lockbox: { - const provider = multiProtocolProvider.getEthersV5Provider(chain); - const routerAddress = token.hypAddress; - const lockbox = HypXERC20Lockbox__factory.connect( - token.hypAddress, - provider, - ); - const xerc20Address = await lockbox.xERC20(); - const xerc20 = IXERC20__factory.connect(xerc20Address, provider); - return getXERC20Limit( - routerAddress, - xerc20, - token.decimals, - token.name, - ); - } - case TokenType.XERC20: { - const provider = multiProtocolProvider.getEthersV5Provider(chain); - const routerAddress = token.hypAddress; - const hypXERC20 = HypXERC20__factory.connect( - routerAddress, - provider, - ); - const xerc20Address = await hypXERC20.wrappedToken(); - const xerc20 = IXERC20__factory.connect(xerc20Address, provider); - return getXERC20Limit( - routerAddress, - xerc20, - token.decimals, - token.name, - ); - } - default: - logger.info( - `Unsupported token type ${token.type} for xERC20 limits check on protocol type ${token.protocolType}`, - ); - - return undefined; - } - } - default: - throw new Error(`Unsupported protocol type ${token.protocolType}`); - } - }, - ); - - return promiseObjAll(output); -} - -const getXERC20Limit = async ( - routerAddress: string, - xerc20: IXERC20, - decimals: number, - tokenName: string, -): Promise => { - const mintCurrent = await xerc20.mintingCurrentLimitOf(routerAddress); - const mintMax = await xerc20.mintingMaxLimitOf(routerAddress); - const burnCurrent = await xerc20.burningCurrentLimitOf(routerAddress); - const burnMax = await xerc20.burningMaxLimitOf(routerAddress); - return { - tokenName, - mint: parseFloat(ethers.utils.formatUnits(mintCurrent, decimals)), - mintMax: parseFloat(ethers.utils.formatUnits(mintMax, decimals)), - burn: parseFloat(ethers.utils.formatUnits(burnCurrent, decimals)), - burnMax: parseFloat(ethers.utils.formatUnits(burnMax, decimals)), - }; -}; - -async function getTokenPriceByChain( - chain: ChainName, - tokenPriceGetter: CoinGeckoTokenPriceGetter, -): Promise { - try { - return await tokenPriceGetter.getTokenPrice(chain); - } catch (e) { - logger.warn('Error getting token price', e); - return undefined; - } -} - -async function getNativeTokenValue( - chain: ChainName, - balanceFloat: number, - tokenPriceGetter: CoinGeckoTokenPriceGetter, -): Promise { - const price = await getTokenPriceByChain(chain, tokenPriceGetter); - logger.debug(`${chain} native token price ${price}`); - if (!price) return undefined; - return balanceFloat * price; -} - -async function getNativeTokenWarpInfo( - balance: ethers.BigNumber | bigint, - decimal: number, - tokenPriceGetter: CoinGeckoTokenPriceGetter, - chain: ChainName, -): Promise { - const balanceFloat = parseFloat(ethers.utils.formatUnits(balance, decimal)); - const value = await getNativeTokenValue( - chain, - balanceFloat, - tokenPriceGetter, - ); - return { balance: balanceFloat, valueUSD: value }; -} - -async function getCollateralTokenPrice( - tokenCoinGeckoId: string | undefined, - tokenPriceGetter: CoinGeckoTokenPriceGetter, -): Promise { - if (!tokenCoinGeckoId) return undefined; - const prices = await tokenPriceGetter.getTokenPriceByIds([tokenCoinGeckoId]); - if (!prices) return undefined; - return prices[0]; -} - -async function getCollateralTokenValue( - tokenCoinGeckoId: string | undefined, - balanceFloat: number, - tokenPriceGetter: CoinGeckoTokenPriceGetter, -): Promise { - const price = await getCollateralTokenPrice( - tokenCoinGeckoId, - tokenPriceGetter, - ); - logger.debug(`${tokenCoinGeckoId} token price ${price}`); - if (!price) return undefined; - return balanceFloat * price; -} - -async function getCollateralTokenWarpInfo( - balance: ethers.BigNumber | bigint, - decimal: number, - tokenPriceGetter: CoinGeckoTokenPriceGetter, - tokenCoinGeckoId?: string, -): Promise { - const balanceFloat = parseFloat(ethers.utils.formatUnits(balance, decimal)); - const value = await getCollateralTokenValue( - tokenCoinGeckoId, - balanceFloat, - tokenPriceGetter, - ); - return { balance: balanceFloat, valueUSD: value }; -} - -async function checkWarpRouteMetrics( - checkFrequency: number, - tokenConfig: WarpRouteConfig, - chainMetadata: ChainMap, -) { - const tokenPriceGetter = new CoinGeckoTokenPriceGetter({ - chainMetadata, - apiKey: await getCoinGeckoApiKey(), - }); - - setInterval(async () => { - try { - const multiProtocolProvider = new MultiProtocolProvider(chainMetadata); - const balances = await checkBalance( - tokenConfig, - multiProtocolProvider, - tokenPriceGetter, - ); - logger.info('Token Balances:', balances); - updateTokenBalanceMetrics(tokenConfig, balances); - } catch (e) { - logger.error('Error checking balances', e); - } - - // only check xERC20 limits if there are xERC20 tokens in the config - if ( - Object.keys(tokenConfig).some( - (chain) => - tokenConfig[chain].type === TokenType.XERC20 || - tokenConfig[chain].type === TokenType.XERC20Lockbox, - ) - ) { - try { - const xERC20Limits = await getXERC20Limits(tokenConfig, chainMetadata); - logger.info('xERC20 Limits:', xERC20Limits); - updateXERC20LimitsMetrics(xERC20Limits); - } catch (e) { - logger.error('Error checking xERC20 limits', e); - } - } - }, checkFrequency); -} - -async function getCoinGeckoApiKey(): Promise { - const environment: DeployEnvironment = 'mainnet3'; - let apiKey: string | undefined; - try { - apiKey = (await fetchGCPSecret( - `${environment}-coingecko-api-key`, - false, - )) as string; - } catch (e) { - logger.error( - 'Error fetching CoinGecko API key, proceeding with public tier', - e, - ); - } - - return apiKey; -} - -main().then(logger.info).catch(logger.error); diff --git a/typescript/infra/scripts/warp-routes/monitor/metrics.ts b/typescript/infra/scripts/warp-routes/monitor/metrics.ts new file mode 100644 index 000000000..7f832b512 --- /dev/null +++ b/typescript/infra/scripts/warp-routes/monitor/metrics.ts @@ -0,0 +1,105 @@ +import { Gauge, Registry } from 'prom-client'; + +import { createWarpRouteConfigId } from '@hyperlane-xyz/registry'; +import { ChainName, Token, TokenStandard, WarpCore } from '@hyperlane-xyz/sdk'; + +import { WarpRouteBalance, XERC20Limit } from './types.js'; +import { logger } from './utils.js'; + +export const metricsRegister = new Registry(); + +type WarpRouteMetricLabels = keyof WarpRouteMetrics; + +interface WarpRouteMetrics { + chain_name: ChainName; + token_address: string; + token_name: string; + wallet_address: string; + token_standard: TokenStandard; + warp_route_id: string; + related_chain_names: string; +} + +const warpRouteMetricLabels: WarpRouteMetricLabels[] = [ + 'chain_name', + 'token_address', + 'token_name', + 'wallet_address', + 'token_standard', + 'warp_route_id', + 'related_chain_names', +]; + +const warpRouteTokenBalance = new Gauge({ + name: 'hyperlane_warp_route_token_balance', + help: 'HypERC20 token balance of a Warp Route', + registers: [metricsRegister], + labelNames: warpRouteMetricLabels, +}); + +const warpRouteCollateralValue = new Gauge({ + name: 'hyperlane_warp_route_collateral_value', + help: 'Total value of collateral held in a HypERC20Collateral or HypNative contract of a Warp Route', + registers: [metricsRegister], + labelNames: warpRouteMetricLabels, +}); + +const xERC20LimitsGauge = new Gauge({ + name: 'hyperlane_xerc20_limits', + help: 'Current minting and burning limits of xERC20 tokens', + registers: [metricsRegister], + labelNames: ['chain_name', 'limit_type', 'token_name'], +}); + +export function updateTokenBalanceMetrics( + warpCore: WarpCore, + token: Token, + balanceInfo: WarpRouteBalance, +) { + const metrics: WarpRouteMetrics = { + chain_name: token.chainName, + token_address: token.collateralAddressOrDenom || token.addressOrDenom, + token_name: token.name, + wallet_address: token.addressOrDenom, + token_standard: token.standard, + warp_route_id: createWarpRouteConfigId( + token.symbol, + warpCore.getTokenChains(), + ), + related_chain_names: warpCore + .getTokenChains() + .filter((chainName) => chainName !== token.chainName) + .sort() + .join(','), + }; + + warpRouteTokenBalance.labels(metrics).set(balanceInfo.balance); + logger.info('Wallet balance updated for token', { + labels: metrics, + balance: balanceInfo.balance, + }); + + if (balanceInfo.valueUSD) { + warpRouteCollateralValue.labels(metrics).set(balanceInfo.valueUSD); + logger.info('Wallet balance updated for token', { + labels: metrics, + valueUSD: balanceInfo.valueUSD, + }); + } +} + +export function updateXERC20LimitsMetrics(token: Token, limits: XERC20Limit) { + for (const [limitType, limit] of Object.entries(limits)) { + xERC20LimitsGauge + .labels({ + chain_name: token.chainName, + limit_type: limitType, + token_name: token.name, + }) + .set(limit); + } + logger.info('xERC20 limits updated for chain', { + chain: token.chainName, + limits, + }); +} 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 new file mode 100644 index 000000000..f9af0039d --- /dev/null +++ b/typescript/infra/scripts/warp-routes/monitor/monitor-warp-route-balances.ts @@ -0,0 +1,254 @@ +import { PopulatedTransaction } from 'ethers'; + +import { + ChainMap, + ChainMetadata, + CoinGeckoTokenPriceGetter, + EvmHypXERC20Adapter, + EvmHypXERC20LockboxAdapter, + IHypXERC20Adapter, + MultiProtocolProvider, + RouterConfig, + Token, + TokenStandard, + WarpCore, +} from '@hyperlane-xyz/sdk'; +import { ProtocolType, objMap, objMerge } from '@hyperlane-xyz/utils'; + +import { getWarpCoreConfig } from '../../../config/registry.js'; +import { + DeployEnvironment, + getRouterConfigsForAllVms, +} from '../../../src/config/environment.js'; +import { fetchGCPSecret } from '../../../src/utils/gcloud.js'; +import { startMetricsServer } from '../../../src/utils/metrics.js'; +import { getArgs, withWarpRouteIdRequired } from '../../agent-utils.js'; +import { getEnvironmentConfig } from '../../core-utils.js'; + +import { + metricsRegister, + updateTokenBalanceMetrics, + updateXERC20LimitsMetrics, +} from './metrics.js'; +import { WarpRouteBalance, XERC20Limit } from './types.js'; +import { logger, tryFn } from './utils.js'; + +async function main() { + const { checkFrequency, environment, warpRouteId } = + await withWarpRouteIdRequired(getArgs()) + .describe('checkFrequency', 'frequency to check balances in ms') + .demandOption('checkFrequency') + .alias('v', 'checkFrequency') // v as in Greek letter nu + .number('checkFrequency') + .parse(); + + startMetricsServer(metricsRegister); + + const envConfig = getEnvironmentConfig(environment); + const registry = await envConfig.getRegistry(); + const chainMetadata = await registry.getMetadata(); + + // The Sealevel warp adapters require the Mailbox address, so we + // get router configs (that include the Mailbox address) for all chains + // and merge them with the chain metadata. + const routerConfig = await getRouterConfigsForAllVms( + envConfig, + await envConfig.getMultiProvider(), + ); + const mailboxes = objMap(routerConfig, (_chain, config: RouterConfig) => ({ + mailbox: config.mailbox, + })); + const multiProtocolProvider = new MultiProtocolProvider( + objMerge(chainMetadata, mailboxes), + ); + const warpCoreConfig = getWarpCoreConfig(warpRouteId); + const warpCore = WarpCore.FromConfig(multiProtocolProvider, warpCoreConfig); + + await pollAndUpdateWarpRouteMetrics(checkFrequency, warpCore, chainMetadata); +} + +// Indefinitely loops, updating warp route metrics at the specified frequency. +async function pollAndUpdateWarpRouteMetrics( + checkFrequency: number, + warpCore: WarpCore, + chainMetadata: ChainMap, +) { + const tokenPriceGetter = new CoinGeckoTokenPriceGetter({ + chainMetadata, + apiKey: await getCoinGeckoApiKey(), + }); + + setInterval(async () => { + await tryFn(async () => { + await Promise.all( + warpCore.tokens.map((token) => + updateTokenMetrics(warpCore, token, tokenPriceGetter), + ), + ); + }, 'Updating warp route metrics'); + }, checkFrequency); +} + +// Updates the metrics for a single token in a warp route. +async function updateTokenMetrics( + warpCore: WarpCore, + token: Token, + tokenPriceGetter: CoinGeckoTokenPriceGetter, +) { + const promises = [ + tryFn(async () => { + const balanceInfo = await getTokenBridgedBalance( + warpCore, + token, + tokenPriceGetter, + ); + if (!balanceInfo) { + return; + } + updateTokenBalanceMetrics(warpCore, token, balanceInfo); + }, 'Getting bridged balance and value'), + ]; + + if (token.isXerc20()) { + promises.push( + tryFn(async () => { + const limits = await getXERC20Limits(warpCore, token); + updateXERC20LimitsMetrics(token, limits); + }, 'Getting xERC20 limits'), + ); + } + + await Promise.all(promises); +} + +// Gets the bridged balance and value of a token in a warp route. +async function getTokenBridgedBalance( + warpCore: WarpCore, + token: Token, + tokenPriceGetter: CoinGeckoTokenPriceGetter, +): Promise { + if (!token.isHypToken()) { + logger.warn('Cannot get bridged balance for a non-Hyperlane token', token); + return undefined; + } + + const adapter = token.getHypAdapter(warpCore.multiProvider); + const bridgedSupply = await adapter.getBridgedSupply(); + if (!bridgedSupply) { + logger.warn('Bridged supply not found for token', token); + return undefined; + } + const balance = token.amount(bridgedSupply).getDecimalFormattedAmount(); + + let tokenPrice; + // Only record value for collateralized and xERC20 lockbox tokens. + if ( + token.isCollateralized() || + token.standard === TokenStandard.EvmHypXERC20Lockbox + ) { + tokenPrice = await tryGetTokenPrice(token, tokenPriceGetter); + } + + return { + balance, + valueUSD: tokenPrice ? balance * tokenPrice : undefined, + }; +} + +async function getXERC20Limits( + warpCore: WarpCore, + token: Token, +): Promise { + if (token.protocol !== ProtocolType.Ethereum) { + throw new Error(`Unsupported XERC20 protocol type ${token.protocol}`); + } + + if (token.standard === TokenStandard.EvmHypXERC20) { + const adapter = token.getAdapter( + warpCore.multiProvider, + ) as EvmHypXERC20Adapter; + return getXERC20Limit(token, adapter); + } else if (token.standard === TokenStandard.EvmHypXERC20Lockbox) { + const adapter = token.getAdapter( + warpCore.multiProvider, + ) as EvmHypXERC20LockboxAdapter; + return getXERC20Limit(token, adapter); + } + throw new Error(`Unsupported XERC20 token standard ${token.standard}`); +} + +async function getXERC20Limit( + token: Token, + xerc20: IHypXERC20Adapter, +): Promise { + const formatBigInt = (num: bigint) => { + return token.amount(num).getDecimalFormattedAmount(); + }; + + const [mintCurrent, mintMax, burnCurrent, burnMax] = await Promise.all([ + xerc20.getMintLimit(), + xerc20.getMintMaxLimit(), + xerc20.getBurnLimit(), + xerc20.getBurnMaxLimit(), + ]); + + return { + mint: formatBigInt(mintCurrent), + mintMax: formatBigInt(mintMax), + burn: formatBigInt(burnCurrent), + burnMax: formatBigInt(burnMax), + }; +} + +// Tries to get the price of a token from CoinGecko. Returns undefined if there's no +// CoinGecko ID for the token. +async function tryGetTokenPrice( + token: Token, + tokenPriceGetter: CoinGeckoTokenPriceGetter, +): Promise { + // We only get a price if the token defines a CoinGecko ID. + // This way we can ignore values of certain types of collateralized warp routes, + // e.g. Native warp routes on rollups that have been pre-funded. + let coinGeckoId = token.coinGeckoId; + + if (!coinGeckoId) { + logger.warn('CoinGecko ID missing for token', token.symbol); + return undefined; + } + + return getCoingeckoPrice(tokenPriceGetter, coinGeckoId); +} + +async function getCoingeckoPrice( + tokenPriceGetter: CoinGeckoTokenPriceGetter, + coingeckoId: string, +): Promise { + const prices = await tokenPriceGetter.getTokenPriceByIds([coingeckoId]); + if (!prices) return undefined; + return prices[0]; +} + +async function getCoinGeckoApiKey(): Promise { + const environment: DeployEnvironment = 'mainnet3'; + let apiKey: string | undefined; + try { + apiKey = (await fetchGCPSecret( + `${environment}-coingecko-api-key`, + false, + )) as string; + } catch (e) { + logger.error( + 'Error fetching CoinGecko API key, proceeding with public tier', + e, + ); + } + + return apiKey; +} + +main() + .then(logger.info) + .catch((err) => { + logger.error('Error in main', err); + process.exit(1); + }); diff --git a/typescript/infra/scripts/warp-routes/monitor/types.ts b/typescript/infra/scripts/warp-routes/monitor/types.ts new file mode 100644 index 000000000..5a2d87749 --- /dev/null +++ b/typescript/infra/scripts/warp-routes/monitor/types.ts @@ -0,0 +1,11 @@ +export interface XERC20Limit { + mint: number; + burn: number; + mintMax: number; + burnMax: number; +} + +export interface WarpRouteBalance { + balance: number; + valueUSD?: number; +} diff --git a/typescript/infra/scripts/warp-routes/monitor/utils.ts b/typescript/infra/scripts/warp-routes/monitor/utils.ts new file mode 100644 index 000000000..414843416 --- /dev/null +++ b/typescript/infra/scripts/warp-routes/monitor/utils.ts @@ -0,0 +1,11 @@ +import { rootLogger } from '@hyperlane-xyz/utils'; + +export const logger = rootLogger.child({ module: 'warp-balance-monitor' }); + +export async function tryFn(fn: () => Promise, context: string) { + try { + await fn(); + } catch (e) { + logger.error(`Error in ${context}`, e); + } +} diff --git a/typescript/infra/src/warp/helm.ts b/typescript/infra/src/warp/helm.ts index 1db3dedce..019e9b5b2 100644 --- a/typescript/infra/src/warp/helm.ts +++ b/typescript/infra/src/warp/helm.ts @@ -11,7 +11,7 @@ export class WarpRouteMonitorHelmManager extends HelmManager { ); constructor( - readonly configFilePath: string, + readonly warpRouteId: string, readonly runEnv: DeployEnvironment, readonly environmentChainNames: string[], ) { @@ -19,17 +19,12 @@ export class WarpRouteMonitorHelmManager extends HelmManager { } async helmValues() { - const pathRelativeToMonorepoRoot = this.configFilePath.includes( - 'typescript/infra', - ) - ? this.configFilePath - : path.join('typescript/infra', this.configFilePath); return { image: { repository: 'gcr.io/abacus-labs-dev/hyperlane-monorepo', - tag: 'd3925b3-20241105-141649', + tag: '91aaa4a-20241108-204429', }, - configFilePath: pathRelativeToMonorepoRoot, + warpRouteId: this.warpRouteId, fullnameOverride: this.helmReleaseName, environment: this.runEnv, hyperlane: { @@ -43,8 +38,19 @@ export class WarpRouteMonitorHelmManager extends HelmManager { } get helmReleaseName(): string { - const match = this.configFilePath.match(/\/([^/]+)-deployments\.yaml$/); - const name = match ? match[1] : this.configFilePath; - return `hyperlane-warp-route-${name.toLowerCase()}`; // helm requires lower case release names + let name = `hyperlane-warp-route-${this.warpRouteId + .toLowerCase() + .replaceAll('/', '-')}`; + + // 52 because the max label length is 63, and there is an auto appended 11 char + // suffix, e.g. `controller-revision-hash=hyperlane-warp-route-tia-mantapacific-neutron-566dc75599` + const maxChars = 52; + + // Max out length, and it can't end with a dash. + if (name.length > maxChars) { + name = name.slice(0, maxChars); + name = name.replace(/-+$/, ''); + } + return name; } } diff --git a/typescript/infra/test/warpIds.test.ts b/typescript/infra/test/warpIds.test.ts new file mode 100644 index 000000000..ba171c5ba --- /dev/null +++ b/typescript/infra/test/warpIds.test.ts @@ -0,0 +1,15 @@ +import { expect } from 'chai'; + +import { WarpRouteIds } from '../config/environments/mainnet3/warp/warpIds.js'; +import { getRegistry } from '../config/registry.js'; + +describe('Warp IDs', () => { + it('Has all warp IDs in the registry', () => { + const registry = getRegistry(); + for (const warpId of Object.values(WarpRouteIds)) { + // That's a long sentence! + expect(registry.getWarpRoute(warpId), `Warp ID ${warpId} not in registry`) + .to.not.be.null.and.not.be.undefined; + } + }); +}); diff --git a/typescript/sdk/src/index.ts b/typescript/sdk/src/index.ts index ccc0a324f..75d74e5c8 100644 --- a/typescript/sdk/src/index.ts +++ b/typescript/sdk/src/index.ts @@ -420,11 +420,14 @@ export { EvmHypCollateralAdapter, EvmHypNativeAdapter, EvmHypSyntheticAdapter, + EvmHypXERC20Adapter, + EvmHypXERC20LockboxAdapter, EvmNativeTokenAdapter, EvmTokenAdapter, } from './token/adapters/EvmTokenAdapter.js'; export { IHypTokenAdapter, + IHypXERC20Adapter, ITokenAdapter, InterchainGasQuote, TransferParams, diff --git a/typescript/sdk/src/token/Token.ts b/typescript/sdk/src/token/Token.ts index 527adc2b5..b63915969 100644 --- a/typescript/sdk/src/token/Token.ts +++ b/typescript/sdk/src/token/Token.ts @@ -24,6 +24,7 @@ import { TOKEN_NFT_STANDARDS, TOKEN_STANDARD_TO_PROTOCOL, TokenStandard, + XERC20_STANDARDS, } from './TokenStandard.js'; import { CwHypCollateralAdapter, @@ -353,10 +354,18 @@ export class Token implements IToken { return Object.values(PROTOCOL_TO_NATIVE_STANDARD).includes(this.standard); } + isCollateralized(): boolean { + return TOKEN_COLLATERALIZED_STANDARDS.includes(this.standard); + } + isHypToken(): boolean { return TOKEN_HYP_STANDARDS.includes(this.standard); } + isXerc20(): boolean { + return XERC20_STANDARDS.includes(this.standard); + } + isIbcToken(): boolean { return this.standard === TokenStandard.CosmosIbc; } @@ -417,7 +426,7 @@ export class Token implements IToken { if (this.equals(token)) return true; - if (TOKEN_COLLATERALIZED_STANDARDS.includes(this.standard)) { + if (this.isCollateralized()) { if ( this.collateralAddressOrDenom && eqAddress(this.collateralAddressOrDenom, token.addressOrDenom) diff --git a/typescript/sdk/src/token/TokenStandard.ts b/typescript/sdk/src/token/TokenStandard.ts index ee434b777..690096a43 100644 --- a/typescript/sdk/src/token/TokenStandard.ts +++ b/typescript/sdk/src/token/TokenStandard.ts @@ -108,11 +108,13 @@ export const TOKEN_COLLATERALIZED_STANDARDS = [ TokenStandard.CwHypNative, ]; -export const MINT_LIMITED_STANDARDS = [ +export const XERC20_STANDARDS = [ TokenStandard.EvmHypXERC20, TokenStandard.EvmHypXERC20Lockbox, ]; +export const MINT_LIMITED_STANDARDS = [...XERC20_STANDARDS]; + export const TOKEN_HYP_STANDARDS = [ TokenStandard.EvmHypNative, TokenStandard.EvmHypCollateral, diff --git a/typescript/sdk/src/token/adapters/CosmWasmTokenAdapter.ts b/typescript/sdk/src/token/adapters/CosmWasmTokenAdapter.ts index 10f32e5b0..e472133bd 100644 --- a/typescript/sdk/src/token/adapters/CosmWasmTokenAdapter.ts +++ b/typescript/sdk/src/token/adapters/CosmWasmTokenAdapter.ts @@ -90,6 +90,11 @@ export class CwNativeTokenAdapter ], }; } + + async getTotalSupply(): Promise { + // Not implemented. + return undefined; + } } export type CW20Metadata = TokenMetadata; @@ -172,6 +177,11 @@ export class CwTokenAdapter }, }); } + + async getTotalSupply(): Promise { + // Not implemented. + return undefined; + } } type TokenRouterResponse = @@ -274,6 +284,10 @@ export class CwHypSyntheticAdapter })); } + getBridgedSupply(): Promise { + return this.getTotalSupply(); + } + async quoteTransferRemoteGas( _destination: Domain, ): Promise { @@ -366,6 +380,10 @@ export class CwHypNativeAdapter return this.cw20adapter.getAllRouters(); } + getBridgedSupply(): Promise { + return this.getBalance(this.addresses.warpRouter); + } + quoteTransferRemoteGas(destination: Domain): Promise { return this.cw20adapter.quoteTransferRemoteGas(destination); } diff --git a/typescript/sdk/src/token/adapters/CosmosTokenAdapter.ts b/typescript/sdk/src/token/adapters/CosmosTokenAdapter.ts index 73f094b94..06ea3dde1 100644 --- a/typescript/sdk/src/token/adapters/CosmosTokenAdapter.ts +++ b/typescript/sdk/src/token/adapters/CosmosTokenAdapter.ts @@ -61,6 +61,11 @@ export class CosmNativeTokenAdapter ): Promise { throw new Error('TODO not yet implemented'); } + + async getTotalSupply(): Promise { + // Not implemented. + return undefined; + } } // Interacts with native tokens on a Cosmos chain and adds support for IBC transfers @@ -103,6 +108,11 @@ export class CosmIbcTokenAdapter > { throw new Error('Method not applicable to IBC adapters'); } + + getBridgedSupply(): Promise { + throw new Error('Method not applicable to IBC adapters'); + } + async quoteTransferRemoteGas( _destination: Domain, ): Promise { diff --git a/typescript/sdk/src/token/adapters/EvmTokenAdapter.ts b/typescript/sdk/src/token/adapters/EvmTokenAdapter.ts index 885cdad2f..794d5cdff 100644 --- a/typescript/sdk/src/token/adapters/EvmTokenAdapter.ts +++ b/typescript/sdk/src/token/adapters/EvmTokenAdapter.ts @@ -11,6 +11,7 @@ import { HypXERC20Lockbox, HypXERC20Lockbox__factory, HypXERC20__factory, + IXERC20, IXERC20__factory, } from '@hyperlane-xyz/core'; import { @@ -77,6 +78,11 @@ export class EvmNativeTokenAdapter const value = BigNumber.from(weiAmountOrId.toString()); return { value, to: recipient }; } + + async getTotalSupply(): Promise { + // Not implemented, native tokens don't have an accessible total supply + return undefined; + } } // Interacts with ERC20/721 contracts @@ -109,7 +115,7 @@ export class EvmTokenAdapter isNft ? 0 : this.contract.decimals(), this.contract.symbol(), this.contract.name(), - this.contract.totalSupply(), + this.getTotalSupply(), ]); return { decimals, symbol, name, totalSupply: totalSupply.toString() }; } @@ -142,6 +148,11 @@ export class EvmTokenAdapter weiAmountOrId.toString(), ); } + + async getTotalSupply(): Promise { + const totalSupply = await this.contract.totalSupply(); + return totalSupply.toBigInt(); + } } // Interacts with Hyp Synthetic token contracts (aka 'HypTokens') @@ -192,6 +203,10 @@ export class EvmHypSyntheticAdapter return domains.map((d, i) => ({ domain: d, address: routers[i] })); } + getBridgedSupply(): Promise { + return this.getTotalSupply(); + } + async quoteTransferRemoteGas( destination: Domain, ): Promise { @@ -254,6 +269,10 @@ export class EvmHypCollateralAdapter }); } + override getBridgedSupply(): Promise { + return this.getBalance(this.addresses.token); + } + override getMetadata(isNft?: boolean): Promise { return this.getWrappedTokenAdapter().then((t) => t.getMetadata(isNft)); } @@ -305,26 +324,44 @@ export class EvmHypXERC20LockboxAdapter ); } - async getMintLimit(): Promise { - const xERC20 = await this.hypXERC20Lockbox.xERC20(); + /** + * Note this may be inaccurate, as this returns the balance + * of the lockbox contract, 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 lockboxAddress = await this.hypXERC20Lockbox.lockbox(); + return this.getBalance(lockboxAddress); + } - const limit = await IXERC20__factory.connect( - xERC20, - this.getProvider(), - ).mintingCurrentLimitOf(this.contract.address); + async getMintLimit(): Promise { + const xERC20 = await this.getXErc20(); + const limit = await xERC20.mintingCurrentLimitOf(this.contract.address); + return limit.toBigInt(); + } - return BigInt(limit.toString()); + async getMintMaxLimit(): Promise { + const xERC20 = await this.getXErc20(); + const limit = await xERC20.mintingMaxLimitOf(this.contract.address); + return limit.toBigInt(); } async getBurnLimit(): Promise { - const xERC20 = await this.hypXERC20Lockbox.xERC20(); + const xERC20 = await this.getXErc20(); + const limit = await xERC20.burningCurrentLimitOf(this.contract.address); + return limit.toBigInt(); + } - const limit = await IXERC20__factory.connect( - xERC20, - this.getProvider(), - ).mintingCurrentLimitOf(this.contract.address); + async getBurnMaxLimit(): Promise { + const xERC20 = await this.getXErc20(); + const limit = await xERC20.burningMaxLimitOf(this.contract.address); + return limit.toBigInt(); + } + + async getXErc20(): Promise { + const xERC20 = await this.hypXERC20Lockbox.xERC20(); - return BigInt(limit.toString()); + return IXERC20__factory.connect(xERC20, this.getProvider()); } } @@ -348,26 +385,47 @@ export class EvmHypXERC20Adapter ); } - async getMintLimit(): Promise { - const xERC20 = await this.hypXERC20.wrappedToken(); + /** + * Note this may be inaccurate, as this returns the total supply + * of the xERC20 contract, 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 xerc20TokenAddress = await this.hypXERC20.wrappedToken(); + const xerc20 = new EvmTokenAdapter(this.chainName, this.multiProvider, { + token: xerc20TokenAddress, + }); + return xerc20.getTotalSupply(); + } - const limit = await IXERC20__factory.connect( - xERC20, - this.getProvider(), - ).mintingCurrentLimitOf(this.contract.address); + async getMintLimit(): Promise { + const xERC20 = await this.getXErc20(); + const limit = await xERC20.mintingCurrentLimitOf(this.contract.address); + return limit.toBigInt(); + } - return BigInt(limit.toString()); + async getMintMaxLimit(): Promise { + const xERC20 = await this.getXErc20(); + const limit = await xERC20.mintingMaxLimitOf(this.contract.address); + return limit.toBigInt(); } async getBurnLimit(): Promise { - const xERC20 = await this.hypXERC20.wrappedToken(); + const xERC20 = await this.getXErc20(); + const limit = await xERC20.burningCurrentLimitOf(this.contract.address); + return limit.toBigInt(); + } - const limit = await IXERC20__factory.connect( - xERC20, - this.getProvider(), - ).burningCurrentLimitOf(this.contract.address); + async getBurnMaxLimit(): Promise { + const xERC20 = await this.getXErc20(); + const limit = await xERC20.burningMaxLimitOf(this.contract.address); + return limit.toBigInt(); + } + + async getXErc20(): Promise { + const xERC20 = await this.hypXERC20.wrappedToken(); - return BigInt(limit.toString()); + return IXERC20__factory.connect(xERC20, this.getProvider()); } } diff --git a/typescript/sdk/src/token/adapters/ITokenAdapter.ts b/typescript/sdk/src/token/adapters/ITokenAdapter.ts index f0a8032d5..d989fb709 100644 --- a/typescript/sdk/src/token/adapters/ITokenAdapter.ts +++ b/typescript/sdk/src/token/adapters/ITokenAdapter.ts @@ -23,6 +23,7 @@ export interface InterchainGasQuote { export interface ITokenAdapter { getBalance(address: Address): Promise; + getTotalSupply(): Promise; getMetadata(isNft?: boolean): Promise; isApproveRequired( owner: Address, @@ -37,11 +38,15 @@ export interface IHypTokenAdapter extends ITokenAdapter { getDomains(): Promise; getRouterAddress(domain: Domain): Promise; getAllRouters(): Promise>; + getBridgedSupply(): Promise; quoteTransferRemoteGas(destination: Domain): Promise; populateTransferRemoteTx(p: TransferRemoteParams): Promise; } export interface IHypXERC20Adapter extends IHypTokenAdapter { getMintLimit(): Promise; + getMintMaxLimit(): Promise; + getBurnLimit(): Promise; + getBurnMaxLimit(): Promise; } diff --git a/typescript/sdk/src/token/adapters/SealevelTokenAdapter.ts b/typescript/sdk/src/token/adapters/SealevelTokenAdapter.ts index 1df0d8637..788fa5f91 100644 --- a/typescript/sdk/src/token/adapters/SealevelTokenAdapter.ts +++ b/typescript/sdk/src/token/adapters/SealevelTokenAdapter.ts @@ -113,6 +113,11 @@ export class SealevelNativeTokenAdapter }), ); } + + async getTotalSupply(): Promise { + // Not implemented. + return undefined; + } } // Interacts with SPL token programs @@ -190,6 +195,13 @@ export class SealevelTokenAdapter this.getTokenProgramId(), ); } + + async getTotalSupply(): Promise { + const response = await this.getProvider().getTokenSupply( + this.tokenMintPubKey, + ); + return BigInt(response.value.amount); + } } interface HypTokenAddresses { @@ -266,6 +278,11 @@ export abstract class SealevelHypTokenAdapter })); } + // Intended to be overridden by subclasses + async getBridgedSupply(): Promise { + return undefined; + } + async quoteTransferRemoteGas( _destination: Domain, ): Promise { @@ -581,6 +598,10 @@ export class SealevelHypNativeAdapter extends SealevelHypTokenAdapter { return this.wrappedNative.getBalance(owner); } + override async getBridgedSupply(): Promise { + return this.getBalance(this.addresses.warpRouter); + } + override async getMetadata(): Promise { return this.wrappedNative.getMetadata(); } @@ -632,6 +653,10 @@ export class SealevelHypCollateralAdapter extends SealevelHypTokenAdapter { return super.getBalance(owner); } + override async getBridgedSupply(): Promise { + return this.getBalance(this.addresses.warpRouter); + } + override getTransferInstructionKeyList( params: KeyListParams, ): Array { @@ -697,6 +722,10 @@ export class SealevelHypSyntheticAdapter extends SealevelHypTokenAdapter { } } + override async getBridgedSupply(): Promise { + return this.getTotalSupply(); + } + async getTotalSupply(): Promise { const response = await this.getProvider().getTokenSupply( this.tokenMintPubKey,