Set igp on sealevel (#2727)

### Description
Getter and setter for the warp route igp
<!--
What's included in this PR?
-->

### Drive-by changes

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

### Related issues

- Fixes https://github.com/hyperlane-xyz/issues/issues/571

### 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

Manual
pull/2499/merge
Daniel Savu 1 year ago committed by GitHub
parent eea423ad04
commit 51b966cca5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 126
      rust/sealevel/client/src/main.rs
  2. 34
      rust/sealevel/client/src/warp_route.rs
  3. 29
      rust/sealevel/libraries/hyperlane-sealevel-token/src/instruction.rs

@ -45,7 +45,7 @@ use hyperlane_sealevel_multisig_ism_message_id::{
},
};
use hyperlane_sealevel_token::{
hyperlane_token_ata_payer_pda_seeds, hyperlane_token_mint_pda_seeds, plugin::SyntheticPlugin,
hyperlane_token_ata_payer_pda_seeds, hyperlane_token_mint_pda_seeds,
spl_associated_token_account::get_associated_token_address_with_program_id, spl_token_2022,
};
use hyperlane_sealevel_token_collateral::{
@ -56,9 +56,7 @@ use hyperlane_sealevel_token_lib::{
hyperlane_token_pda_seeds,
instruction::{Instruction as HtInstruction, TransferRemote as HtTransferRemote},
};
use hyperlane_sealevel_token_native::{
hyperlane_token_native_collateral_pda_seeds, plugin::NativePlugin,
};
use hyperlane_sealevel_token_native::hyperlane_token_native_collateral_pda_seeds;
use hyperlane_sealevel_validator_announce::{
accounts::ValidatorStorageLocationsAccount,
instruction::{
@ -68,6 +66,7 @@ use hyperlane_sealevel_validator_announce::{
replay_protection_pda_seeds, validator_announce_pda_seeds,
validator_storage_locations_pda_seeds,
};
use warp_route::parse_token_account_data;
use crate::warp_route::process_warp_route_cmd;
pub(crate) use crate::{context::*, core::*};
@ -297,10 +296,11 @@ enum TokenSubCmd {
TransferRemote(TokenTransferRemote),
EnrollRemoteRouter(TokenEnrollRemoteRouter),
TransferOwnership(TransferOwnership),
Igp(Igp),
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum)]
enum TokenType {
pub enum TokenType {
Native,
Synthetic,
Collateral,
@ -345,6 +345,39 @@ struct TransferOwnership {
new_owner: Pubkey,
}
#[derive(Args)]
struct Igp {
#[arg(long, short, default_value_t = HYPERLANE_TOKEN_PROG_ID)]
program_id: Pubkey,
#[command(subcommand)]
cmd: GetSetCmd<GetIgpArgs, SetIgpArgs>,
}
#[derive(Subcommand)]
enum GetSetCmd<G: Args, S: Args> {
Get(G),
Set(S),
}
#[derive(Args)]
struct SetIgpArgs {
igp_program: Pubkey,
#[arg(value_enum)]
igp_type: IgpType,
igp_account: Pubkey,
}
#[derive(Args)]
struct GetIgpArgs {
token_type: TokenType,
}
#[derive(ValueEnum, Clone)]
enum IgpType {
Igp,
OverheadIgp,
}
#[derive(Args)]
struct IgpCmd {
#[command(subcommand)]
@ -388,13 +421,7 @@ struct GasOracleConfigArgs {
#[arg(long)]
remote_domain: u32,
#[command(subcommand)]
cmd: GasOracleSubCmd,
}
#[derive(Subcommand)]
enum GasOracleSubCmd {
Set(SetGasOracleArgs),
Get,
cmd: GetSetCmd<GetGasOracleArgs, SetGasOracleArgs>,
}
#[derive(Args)]
@ -407,6 +434,9 @@ struct SetGasOracleArgs {
token_decimals: u8,
}
#[derive(Args)]
struct GetGasOracleArgs;
#[derive(Args)]
struct DestinationGasOverheadArgs {
#[arg(long)]
@ -785,32 +815,7 @@ fn process_token_cmd(ctx: Context, cmd: TokenCmd) {
);
if let Some(info) = &accounts[0] {
println!("{:#?}", info);
match query.token_type {
TokenType::Native => {
match HyperlaneTokenAccount::<NativePlugin>::fetch(&mut info.data.as_ref())
{
Ok(token) => println!("{:#?}", token.into_inner()),
Err(err) => println!("Failed to deserialize account data: {}", err),
}
}
TokenType::Synthetic => {
match HyperlaneTokenAccount::<SyntheticPlugin>::fetch(
&mut info.data.as_ref(),
) {
Ok(token) => println!("{:#?}", token.into_inner()),
Err(err) => println!("Failed to deserialize account data: {}", err),
}
}
TokenType::Collateral => {
match HyperlaneTokenAccount::<CollateralPlugin>::fetch(
&mut info.data.as_ref(),
) {
Ok(token) => println!("{:#?}", token.into_inner()),
Err(err) => println!("Failed to deserialize account data: {}", err),
}
}
}
parse_token_account_data(query.token_type, &mut info.data.as_ref());
} else {
println!("Not yet created?");
}
@ -1108,6 +1113,46 @@ fn process_token_cmd(ctx: Context, cmd: TokenCmd) {
)
.send_with_payer();
}
TokenSubCmd::Igp(args) => match args.cmd {
GetSetCmd::Set(set_args) => {
let igp_type: InterchainGasPaymasterType = match set_args.igp_type {
IgpType::Igp => InterchainGasPaymasterType::Igp(set_args.igp_account),
IgpType::OverheadIgp => {
InterchainGasPaymasterType::OverheadIgp(set_args.igp_account)
}
};
let instruction = hyperlane_sealevel_token_lib::instruction::set_igp_instruction(
args.program_id,
ctx.payer_pubkey,
Some((set_args.igp_program, igp_type.clone())),
)
.unwrap();
ctx.new_txn()
.add_with_description(
instruction,
format!(
"Set IGP of {} to program {}, type {:?}",
args.program_id, set_args.igp_program, igp_type
),
)
.send_with_payer();
}
GetSetCmd::Get(get_args) => {
let (token_account, _token_bump) =
Pubkey::find_program_address(hyperlane_token_pda_seeds!(), &args.program_id);
let token_account = ctx
.client
.get_account_with_commitment(&token_account, ctx.commitment)
.unwrap()
.value
.expect(
"Token account not found. Make sure you are connected to the right RPC.",
);
parse_token_account_data(get_args.token_type, &mut &token_account.data[..]);
}
},
}
}
@ -1330,7 +1375,7 @@ fn process_igp_cmd(ctx: Context, cmd: IgpCmd) {
let core_program_ids =
read_core_program_ids(&args.environments_dir, &args.environment, &args.chain_name);
match args.cmd {
GasOracleSubCmd::Set(set_args) => {
GetSetCmd::Set(set_args) => {
let remote_gas_data = RemoteGasData {
token_exchange_rate: set_args.token_exchange_rate,
gas_price: set_args.gas_price,
@ -1351,8 +1396,7 @@ fn process_igp_cmd(ctx: Context, cmd: IgpCmd) {
ctx.new_txn().add(instruction).send_with_payer();
println!("Set gas oracle for remote domain {:?}", args.remote_domain);
}
GasOracleSubCmd::Get => {
// Read the gas oracle config
GetSetCmd::Get(_) => {
let igp_account = ctx
.client
.get_account_with_commitment(&core_program_ids.igp_account, ctx.commitment)

@ -1,6 +1,8 @@
use hyperlane_core::{utils::hex_or_base58_to_h256, H256};
use hyperlane_sealevel_token_collateral::plugin::CollateralPlugin;
use hyperlane_sealevel_token_native::plugin::NativePlugin;
use serde::{Deserialize, Serialize};
use std::{collections::HashMap, fs::File, path::Path, str::FromStr};
use std::{collections::HashMap, fmt::Debug, fs::File, path::Path, str::FromStr};
use solana_client::{client_error::ClientError, rpc_client::RpcClient};
use solana_program::program_error::ProgramError;
@ -10,7 +12,9 @@ use hyperlane_sealevel_connection_client::{
gas_router::GasRouterConfig, router::RemoteRouterConfig,
};
use hyperlane_sealevel_igp::accounts::InterchainGasPaymasterType;
use hyperlane_sealevel_token::{hyperlane_token_mint_pda_seeds, spl_token, spl_token_2022};
use hyperlane_sealevel_token::{
hyperlane_token_mint_pda_seeds, plugin::SyntheticPlugin, spl_token, spl_token_2022,
};
use hyperlane_sealevel_token_lib::{
accounts::HyperlaneTokenAccount,
hyperlane_token_pda_seeds,
@ -22,7 +26,7 @@ use crate::{
account_exists, create_and_write_keypair, create_new_directory, deploy_program_idempotent,
},
core::{read_core_program_ids, CoreProgramIds},
Context, WarpRouteCmd, WarpRouteSubCmd,
Context, TokenType as FlatTokenType, WarpRouteCmd, WarpRouteSubCmd,
};
#[derive(Debug, Deserialize, Serialize, Clone)]
@ -685,3 +689,27 @@ fn write_program_ids(warp_route_dir: &Path, routers: &HashMap<String, H256>) {
let program_ids_file = File::create(program_ids_file).unwrap();
serde_json::to_writer_pretty(program_ids_file, &serialized_program_ids).unwrap();
}
pub fn parse_token_account_data(token_type: FlatTokenType, data: &mut &[u8]) {
fn print_data_or_err<T: Debug>(data: Result<T, ProgramError>) {
match data {
Ok(data) => println!("{:#?}", data),
Err(err) => println!("Failed to deserialize account data: {}", err),
}
}
match token_type {
FlatTokenType::Native => {
let res = HyperlaneTokenAccount::<NativePlugin>::fetch(data);
print_data_or_err(res);
}
FlatTokenType::Synthetic => {
let res = HyperlaneTokenAccount::<SyntheticPlugin>::fetch(data);
print_data_or_err(res);
}
FlatTokenType::Collateral => {
let res = HyperlaneTokenAccount::<CollateralPlugin>::fetch(data);
print_data_or_err(res);
}
}
}

@ -200,3 +200,32 @@ pub fn transfer_ownership_instruction(
Ok(instruction)
}
/// Sets the igp for a warp route
pub fn set_igp_instruction(
program_id: Pubkey,
owner_payer: Pubkey,
igp_program_and_account: Option<(Pubkey, InterchainGasPaymasterType)>,
) -> Result<SolanaInstruction, ProgramError> {
let (token_key, _token_bump) =
Pubkey::try_find_program_address(hyperlane_token_pda_seeds!(), &program_id)
.ok_or(ProgramError::InvalidSeeds)?;
let ixn = Instruction::SetInterchainGasPaymaster(igp_program_and_account);
// Accounts:
// 0. [writeable] The token PDA account.
// 1. [signer] The current owner.
let accounts = vec![
AccountMeta::new(token_key, false),
AccountMeta::new_readonly(owner_payer, true),
];
let instruction = SolanaInstruction {
program_id,
data: ixn.encode()?,
accounts,
};
Ok(instruction)
}

Loading…
Cancel
Save