Skip to content

Commit

Permalink
feat: deploy apxETH and ezSOL routes (#4901)
Browse files Browse the repository at this point in the history
### Description

Ownership transfer pending getting addresses

### Drive-by changes

<!--
Are there any minor or drive-by changes also included?
-->

### Related issues

<!--
- Fixes #[issue number here]
-->

### Backward compatibility

<!--
Are these changes backward compatible? Are there any infrastructure
implications, e.g. changes that would prohibit deploying older commits
using this infra tooling?

Yes/No
-->

### Testing

<!--
What kind of testing have these changes undergone?

None/Manual/Unit Tests
-->
  • Loading branch information
tkporter authored Nov 26, 2024
1 parent 43192bd commit d518157
Show file tree
Hide file tree
Showing 23 changed files with 184 additions and 32 deletions.
5 changes: 5 additions & 0 deletions .changeset/bright-students-exist.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@hyperlane-xyz/cli': minor
---

Support using the CLI to deploy warp routes that involve foreign deployments
2 changes: 1 addition & 1 deletion .registryrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
fa13e998aceff5a82b1a4e0791fe392791bb0393
385b83950adba6f033be836b627bab7d89aae38d
21 changes: 19 additions & 2 deletions rust/sealevel/client/src/cmd_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,23 @@ use solana_sdk::{

const SOLANA_DOMAIN: u32 = 1399811149;

pub(crate) fn get_compute_unit_price_micro_lamports_for_id(domain: u32) -> u64 {
get_compute_unit_price(domain == SOLANA_DOMAIN)
}

pub(crate) fn get_compute_unit_price_micro_lamports_for_chain_name(chain_name: &str) -> u64 {
get_compute_unit_price(chain_name == "solanamainnet")
}

fn get_compute_unit_price(is_solanamainnet: bool) -> u64 {
if is_solanamainnet {
// Generally taking a low/medium value from https://www.quicknode.com/gas-tracker/solana
500_000
} else {
0
}
}

pub(crate) fn account_exists(client: &RpcClient, account: &Pubkey) -> Result<bool, ClientError> {
// Using `get_account_with_commitment` instead of `get_account` so we get Ok(None) when the account
// doesn't exist, rather than an error
Expand Down Expand Up @@ -73,9 +90,9 @@ pub(crate) fn deploy_program(
program_keypair_path,
];

let compute_unit_price = get_compute_unit_price_micro_lamports_for_id(local_domain).to_string();
if local_domain.eq(&SOLANA_DOMAIN) {
// May need tweaking depending on gas prices / available balance
command.append(&mut vec!["--with-compute-unit-price", "550000"]);
command.extend(vec!["--with-compute-unit-price", &compute_unit_price]);
}

build_cmd(command.as_slice(), None, None);
Expand Down
22 changes: 8 additions & 14 deletions rust/sealevel/client/src/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,26 +9,21 @@ use solana_sdk::{compute_budget, compute_budget::ComputeBudgetInstruction};
use std::collections::HashMap;
use std::{fs::File, path::Path};

use crate::cmd_utils::get_compute_unit_price_micro_lamports_for_chain_name;
use crate::ONE_SOL_IN_LAMPORTS;
use crate::{
artifacts::{read_json, write_json},
cmd_utils::{create_and_write_keypair, create_new_directory, deploy_program},
multisig_ism::deploy_multisig_ism_message_id,
Context, CoreCmd, CoreDeploy, CoreSubCmd,
};
use crate::{DEFAULT_INSTRUCTION_COMPUTE_UNIT_LIMIT, ONE_SOL_IN_LAMPORTS};
use hyperlane_core::H256;
use hyperlane_sealevel_igp::accounts::{SOL_DECIMALS, TOKEN_EXCHANGE_RATE_SCALE};

pub(crate) fn adjust_gas_price_if_needed(chain_name: &str, ctx: &mut Context) {
if chain_name.eq("solanamainnet") {
let compute_unit_price = get_compute_unit_price_micro_lamports_for_chain_name(chain_name);
let mut initial_instructions = ctx.initial_instructions.borrow_mut();
const PROCESS_DESIRED_PRIORITIZATION_FEE_LAMPORTS_PER_TX: u64 = 50_000_000;
const MICRO_LAMPORT_FEE_PER_LIMIT: u64 =
// Convert to micro-lamports
(PROCESS_DESIRED_PRIORITIZATION_FEE_LAMPORTS_PER_TX * 1_000_000)
// Divide by the max compute units
/ DEFAULT_INSTRUCTION_COMPUTE_UNIT_LIMIT as u64;

for i in initial_instructions.iter_mut() {
if i.instruction.program_id != compute_budget::id() {
continue;
Expand All @@ -41,20 +36,19 @@ pub(crate) fn adjust_gas_price_if_needed(chain_name: &str, ctx: &mut Context) {
ComputeBudgetInstruction::SetComputeUnitPrice { .. }
) {
// The compute unit price has already been set, so we override it and return early
i.instruction = ComputeBudgetInstruction::set_compute_unit_price(
MICRO_LAMPORT_FEE_PER_LIMIT,
);
i.instruction =
ComputeBudgetInstruction::set_compute_unit_price(compute_unit_price);
return;
}
}
}

initial_instructions.push(
(
ComputeBudgetInstruction::set_compute_unit_price(MICRO_LAMPORT_FEE_PER_LIMIT),
ComputeBudgetInstruction::set_compute_unit_price(compute_unit_price),
Some(format!(
"Set compute unit price to {}",
MICRO_LAMPORT_FEE_PER_LIMIT
"Set compute unit price to {} micro-lamports",
compute_unit_price
)),
)
.into(),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"eclipsemainnet": {
"hex": "0x82f7445ccda6396092998c8f841f0d4eb63cca29ba23cfd2609d283f3ee9d13f",
"base58": "9pEgj7m2VkwLtJHPtTw5d8vbB7kfjzcXXCRgdwruW7C2"
},
"ethereum": {
"hex": "0x000000000000000000000000d34fe1685c28a68bb4b8faaadcb2769962ae737c",
"base58": "1111111111113wkPRLXCJuj9539UEURsN3qhoaYb"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"eclipsemainnet": {
"type": "synthetic",
"decimals": 9,
"remoteDecimals": 18,
"name": "Autocompounding Pirex Ether",
"symbol": "apxETH",
"uri": "https://raw.githubusercontent.com/hyperlane-xyz/hyperlane-registry/ae7df1bc00af19f8ba692c14e4df3acdbf30497d/deployments/warp_routes/APXETH/metadata.json",
"interchainGasPaymaster": "3Wp4qKkgf4tjXz1soGyTSndCgBPLZFSrZkiDZ8Qp9EEj"
},
"ethereum": {
"type": "collateral",
"decimals": 18,
"token": "0x9ba021b0a9b958b5e75ce9f6dff97c7ee52cb3e6",
"foreignDeployment": "0xd34FE1685c28A68Bb4B8fAaadCb2769962AE737c"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"eclipsemainnet": {
"hex": "0xb06d58417c929a624e9b689e604e6d60ca652168ee76b9a290bd5b974b22b306",
"base58": "CshTfxXWMvnRAwBTCjQ4577bkP5po5ZuNG1QTuQxA5Au"
},
"solanamainnet": {
"hex": "0x08bb318b88b38cc6f450b185e51a9c42402dc9d36fa6741c19c2aa62464a5eb3",
"base58": "b5pMgizA9vrGRt3hVqnU7vUVGBQUnLpwPzcJhG1ucyQ"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"solanamainnet": {
"type": "collateral",
"decimals": 9,
"interchainGasPaymaster": "AkeHBbE5JkwVppujCQQ6WuxsVsJtruBAjUo6fDCFp6fF",
"token": "ezSoL6fY1PVdJcJsUpe5CM3xkfmy3zoVCABybm5WtiC",
"splTokenProgram": "token"
},
"eclipsemainnet": {
"type": "synthetic",
"decimals": 9,
"name": "Renzo Restaked SOL",
"symbol": "ezSOL",
"uri": "https://raw.githubusercontent.com/hyperlane-xyz/hyperlane-registry/ae7df1bc00af19f8ba692c14e4df3acdbf30497d/deployments/warp_routes/EZSOL/metadata.json",
"interchainGasPaymaster": "3Wp4qKkgf4tjXz1soGyTSndCgBPLZFSrZkiDZ8Qp9EEj"
}
}
22 changes: 18 additions & 4 deletions typescript/cli/src/deploy/warp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,16 +136,24 @@ export async function runWarpRouteDeploy({

await runDeployPlanStep(deploymentParams);

// Some of the below functions throw if passed non-EVM chains
const ethereumChains = chains.filter(
(chain) => chainMetadata[chain].protocol === ProtocolType.Ethereum,
);

await runPreflightChecksForChains({
context,
chains,
chains: ethereumChains,
minGas: MINIMUM_WARP_DEPLOY_GAS,
});

const userAddress = await signer.getAddress();

const initialBalances = await prepareDeploy(context, userAddress, chains);

const initialBalances = await prepareDeploy(
context,
userAddress,
ethereumChains,
);
const deployedContracts = await executeDeploy(deploymentParams, apiKeys);

const warpCoreConfig = await getWarpCoreConfig(
Expand All @@ -155,7 +163,13 @@ export async function runWarpRouteDeploy({

await writeDeploymentArtifacts(warpCoreConfig, context);

await completeDeploy(context, 'warp', initialBalances, userAddress, chains);
await completeDeploy(
context,
'warp',
initialBalances,
userAddress,
ethereumChains,
);
}

async function runDeployPlanStep({ context, warpDeployConfig }: DeployParams) {
Expand Down
9 changes: 8 additions & 1 deletion typescript/cli/src/utils/balances.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ import { confirm } from '@inquirer/prompts';
import { ethers } from 'ethers';

import { ChainName, MultiProvider } from '@hyperlane-xyz/sdk';
import { ProtocolType } from '@hyperlane-xyz/utils';

import { logGreen, logRed } from '../logger.js';
import { logGray, logGreen, logRed } from '../logger.js';

export async function nativeBalancesAreSufficient(
multiProvider: MultiProvider,
Expand All @@ -15,6 +16,12 @@ export async function nativeBalancesAreSufficient(

const sufficientBalances: boolean[] = [];
for (const chain of chains) {
// Only Ethereum chains are supported
if (multiProvider.getProtocol(chain) !== ProtocolType.Ethereum) {
logGray(`Skipping balance check for non-EVM chain: ${chain}`);
continue;
}

const provider = multiProvider.getProvider(chain);
const gasPrice = await provider.getGasPrice();
const minBalanceWei = gasPrice.mul(minGas).toString();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { ethers } from 'ethers';

import {
ChainMap,
OwnableConfig,
TokenRouterConfig,
TokenType,
} from '@hyperlane-xyz/sdk';

import { getOwnerConfigForAddress } from '../../../../../src/config/environment.js';
import {
RouterConfigWithoutOwner,
tokens,
} from '../../../../../src/config/warp.js';
import { DEPLOYER } from '../../owners.js';
import { SEALEVEL_WARP_ROUTE_HANDLER_GAS_AMOUNT } from '../consts.js';

const ethereumOwner = DEPLOYER;
const eclipseOwner = '9bRSUPjfS3xS6n5EfkJzHFTRDa4AHLda8BU2pP4HoWnf';

export async function getEclipseEthereumApxEthWarpConfig(
routerConfig: ChainMap<RouterConfigWithoutOwner>,
_abacusWorksEnvOwnerConfig: ChainMap<OwnableConfig>,
): Promise<ChainMap<TokenRouterConfig>> {
const eclipsemainnet: TokenRouterConfig = {
...routerConfig.eclipsemainnet,
...getOwnerConfigForAddress(eclipseOwner),
type: TokenType.synthetic,
foreignDeployment: '9pEgj7m2VkwLtJHPtTw5d8vbB7kfjzcXXCRgdwruW7C2',
gas: SEALEVEL_WARP_ROUTE_HANDLER_GAS_AMOUNT,
interchainSecurityModule: ethers.constants.AddressZero,
};

let ethereum: TokenRouterConfig = {
...routerConfig.ethereum,
...getOwnerConfigForAddress(ethereumOwner),
type: TokenType.collateral,
token: tokens.ethereum.apxETH,
interchainSecurityModule: ethers.constants.AddressZero,
};

return {
eclipsemainnet,
ethereum,
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
} from '@hyperlane-xyz/sdk';

import { tokens } from '../../../../../src/config/warp.js';
import { SEALEVEL_WARP_ROUTE_HANDLER_GAS_AMOUNT } from '../consts.js';

export const getEclipseEthereumSolanaUSDCWarpConfig = async (
routerConfig: ChainMap<RouterConfig>,
Expand All @@ -16,7 +17,7 @@ export const getEclipseEthereumSolanaUSDCWarpConfig = async (
...routerConfig.eclipsemainnet,
type: TokenType.synthetic,
foreignDeployment: 'D6k6T3G74ij6atCtBiWBs5TbFa1hFVcrFUSGZHuV7q3Z',
gas: 300_000,
gas: SEALEVEL_WARP_ROUTE_HANDLER_GAS_AMOUNT,
};

const ethereum: TokenRouterConfig = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
RouterConfigWithoutOwner,
tokens,
} from '../../../../../src/config/warp.js';
import { SEALEVEL_WARP_ROUTE_HANDLER_GAS_AMOUNT } from '../consts.js';

export const getEclipseEthereumSolanaUSDTWarpConfig = async (
routerConfig: ChainMap<RouterConfigWithoutOwner>,
Expand All @@ -21,7 +22,7 @@ export const getEclipseEthereumSolanaUSDTWarpConfig = async (
...abacusWorksEnvOwnerConfig.eclipsemainnet,
type: TokenType.synthetic,
foreignDeployment: '5g5ujyYUNvdydwyDVCpZwPpgYRqH5RYJRi156cxyE3me',
gas: 300_000,
gas: SEALEVEL_WARP_ROUTE_HANDLER_GAS_AMOUNT,
interchainSecurityModule: ethers.constants.AddressZero,
};
let ethereum: TokenRouterConfig = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,16 @@ import {
TokenType,
} from '@hyperlane-xyz/sdk';

import { SEALEVEL_WARP_ROUTE_HANDLER_GAS_AMOUNT } from '../consts.js';

export const getEthereumEclipseTETHWarpConfig = async (
routerConfig: ChainMap<RouterConfig>,
): Promise<ChainMap<TokenRouterConfig>> => {
const eclipsemainnet: TokenRouterConfig = {
...routerConfig.eclipsemainnet,
type: TokenType.synthetic,
foreignDeployment: 'BJa3fPvvjKx8gRCWunoSrWBbsmieub37gsGpjp4BfTfW',
gas: 300_000,
gas: SEALEVEL_WARP_ROUTE_HANDLER_GAS_AMOUNT,
};

const ethereum: TokenRouterConfig = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
RouterConfigWithoutOwner,
tokens,
} from '../../../../../src/config/warp.js';
import { SEALEVEL_WARP_ROUTE_HANDLER_GAS_AMOUNT } from '../consts.js';

export const getEclipseEthereumWBTCWarpConfig = async (
routerConfig: ChainMap<RouterConfigWithoutOwner>,
Expand All @@ -21,7 +22,7 @@ export const getEclipseEthereumWBTCWarpConfig = async (
...abacusWorksEnvOwnerConfig.eclipsemainnet,
type: TokenType.synthetic,
foreignDeployment: 'A7EGCDYFw5R7Jfm6cYtKvY8dmkrYMgwRCJFkyQwpHTYu',
gas: 300_000,
gas: SEALEVEL_WARP_ROUTE_HANDLER_GAS_AMOUNT,
interchainSecurityModule: ethers.constants.AddressZero,
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
RouterConfigWithoutOwner,
tokens,
} from '../../../../../src/config/warp.js';
import { SEALEVEL_WARP_ROUTE_HANDLER_GAS_AMOUNT } from '../consts.js';

// Safe owned by Veda
const ethereumOwner = '0xCEA8039076E35a825854c5C2f85659430b06ec96';
Expand All @@ -28,7 +29,7 @@ export async function getEclipseEthereumWeEthsWarpConfig(
...getOwnerConfigForAddress(eclipseOwner),
type: TokenType.synthetic,
foreignDeployment: '7Zx4wU1QAw98MfvnPFqRh1oyumek7G5VAX6TKB3U1tcn',
gas: 300_000,
gas: SEALEVEL_WARP_ROUTE_HANDLER_GAS_AMOUNT,
interchainSecurityModule: ethers.constants.AddressZero,
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {

import { getOwnerConfigForAddress } from '../../../../../src/config/environment.js';
import { RouterConfigWithoutOwner } from '../../../../../src/config/warp.js';
import { SEALEVEL_WARP_ROUTE_HANDLER_GAS_AMOUNT } from '../consts.js';

// Stride team
const strideOwner = 'stride1k8c2m5cn322akk5wy8lpt87dd2f4yh9azg7jlh';
Expand All @@ -20,7 +21,7 @@ export const getEclipseStrideTiaWarpConfig = async (
...abacusWorksEnvOwnerConfig.eclipsemainnet,
type: TokenType.synthetic,
foreignDeployment: 'BpXHAiktwjx7fN6M9ST9wr6qKAsH27wZFhdHEhReJsR6',
gas: 300_000,
gas: SEALEVEL_WARP_ROUTE_HANDLER_GAS_AMOUNT,
};

const stride: TokenRouterConfig = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {

import { getOwnerConfigForAddress } from '../../../../../src/config/environment.js';
import { RouterConfigWithoutOwner } from '../../../../../src/config/warp.js';
import { SEALEVEL_WARP_ROUTE_HANDLER_GAS_AMOUNT } from '../consts.js';

// Stride team
const strideOwner = 'stride1k8c2m5cn322akk5wy8lpt87dd2f4yh9azg7jlh';
Expand All @@ -20,7 +21,7 @@ export const getEclipseStrideStTiaWarpConfig = async (
...abacusWorksEnvOwnerConfig.eclipsemainnet,
type: TokenType.synthetic,
foreignDeployment: 'tKUHyJ5NxhnwU94JUmzh1ekukDcHHX8mZF6fqxbMwX6',
gas: 300_000,
gas: SEALEVEL_WARP_ROUTE_HANDLER_GAS_AMOUNT,
};

const stride: TokenRouterConfig = {
Expand Down
2 changes: 2 additions & 0 deletions typescript/infra/config/environments/mainnet3/warp/consts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// The amount of gas to pay for when performing a transferRemote to a Sealevel chain.
export const SEALEVEL_WARP_ROUTE_HANDLER_GAS_AMOUNT = 300_000;
Loading

0 comments on commit d518157

Please sign in to comment.