Merge main to v3 (#2812)
parent
9168cca6d2
commit
1d18549755
@ -1,3 +1,3 @@ |
|||||||
[toolchain] |
[toolchain] |
||||||
channel = "1.71.1" |
channel = "1.72.1" |
||||||
profile = "default" |
profile = "default" |
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,9 +1,8 @@ |
|||||||
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.1
|
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.3
|
||||||
|
|
||||||
pub use super::block::Entity as Block; |
pub use super::{ |
||||||
pub use super::cursor::Entity as Cursor; |
block::Entity as Block, cursor::Entity as Cursor, |
||||||
pub use super::delivered_message::Entity as DeliveredMessage; |
delivered_message::Entity as DeliveredMessage, domain::Entity as Domain, |
||||||
pub use super::domain::Entity as Domain; |
gas_payment::Entity as GasPayment, message::Entity as Message, |
||||||
pub use super::gas_payment::Entity as GasPayment; |
transaction::Entity as Transaction, |
||||||
pub use super::message::Entity as Message; |
}; |
||||||
pub use super::transaction::Entity as Transaction; |
|
||||||
|
@ -0,0 +1,59 @@ |
|||||||
|
use serde::{de::DeserializeOwned, Deserialize, Serialize}; |
||||||
|
|
||||||
|
use hyperlane_core::H256; |
||||||
|
use solana_program::pubkey::Pubkey; |
||||||
|
|
||||||
|
use std::{fs::File, io::Write, path::Path, str::FromStr}; |
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize)] |
||||||
|
pub(crate) struct SingularProgramIdArtifact { |
||||||
|
#[serde(with = "crate::serde::serde_pubkey")] |
||||||
|
pub program_id: Pubkey, |
||||||
|
} |
||||||
|
|
||||||
|
impl From<Pubkey> for SingularProgramIdArtifact { |
||||||
|
fn from(val: Pubkey) -> Self { |
||||||
|
SingularProgramIdArtifact { program_id: val } |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)] |
||||||
|
pub(crate) struct HexAndBase58ProgramIdArtifact { |
||||||
|
hex: String, |
||||||
|
base58: String, |
||||||
|
} |
||||||
|
|
||||||
|
impl From<H256> for HexAndBase58ProgramIdArtifact { |
||||||
|
fn from(val: H256) -> Self { |
||||||
|
HexAndBase58ProgramIdArtifact { |
||||||
|
hex: format!("0x{}", hex::encode(val)), |
||||||
|
base58: Pubkey::new_from_array(val.to_fixed_bytes()).to_string(), |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl From<&HexAndBase58ProgramIdArtifact> for Pubkey { |
||||||
|
fn from(val: &HexAndBase58ProgramIdArtifact) -> Self { |
||||||
|
Pubkey::from_str(&val.base58).unwrap() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub(crate) fn write_json<T>(path: &Path, program_id: T) |
||||||
|
where |
||||||
|
T: Serialize, |
||||||
|
{ |
||||||
|
let json = serde_json::to_string_pretty(&program_id).unwrap(); |
||||||
|
println!("Writing to file {} contents:\n{}", path.display(), json); |
||||||
|
|
||||||
|
let mut file = File::create(path).expect("Failed to create file"); |
||||||
|
file.write_all(json.as_bytes()) |
||||||
|
.expect("Failed write JSON to file"); |
||||||
|
} |
||||||
|
|
||||||
|
pub(crate) fn read_json<T>(path: &Path) -> T |
||||||
|
where |
||||||
|
T: DeserializeOwned, |
||||||
|
{ |
||||||
|
let file = File::open(path).expect("Failed to open JSON file"); |
||||||
|
serde_json::from_reader(file).expect("Failed to read JSON file") |
||||||
|
} |
@ -0,0 +1,197 @@ |
|||||||
|
use std::collections::HashMap; |
||||||
|
|
||||||
|
use hyperlane_core::H256; |
||||||
|
use hyperlane_sealevel_connection_client::router::RemoteRouterConfig; |
||||||
|
use hyperlane_sealevel_hello_world::{ |
||||||
|
accounts::{HelloWorldStorage, HelloWorldStorageAccount}, |
||||||
|
instruction::{ |
||||||
|
enroll_remote_routers_instruction, init_instruction, |
||||||
|
set_interchain_security_module_instruction, |
||||||
|
}, |
||||||
|
program_storage_pda_seeds, |
||||||
|
}; |
||||||
|
use serde::{Deserialize, Serialize}; |
||||||
|
use solana_sdk::{instruction::Instruction, pubkey::Pubkey}; |
||||||
|
|
||||||
|
use crate::{ |
||||||
|
cmd_utils::account_exists, |
||||||
|
router::{ |
||||||
|
deploy_routers, ChainMetadata, ConnectionClient, Ownable, RouterConfig, RouterConfigGetter, |
||||||
|
RouterDeployer, |
||||||
|
}, |
||||||
|
Context, CoreProgramIds, HelloWorldCmd, HelloWorldDeploy, HelloWorldSubCmd, RpcClient, |
||||||
|
}; |
||||||
|
|
||||||
|
pub(crate) fn process_helloworld_cmd(mut ctx: Context, cmd: HelloWorldCmd) { |
||||||
|
match cmd.cmd { |
||||||
|
HelloWorldSubCmd::Deploy(deploy) => { |
||||||
|
deploy_helloworld(&mut ctx, deploy); |
||||||
|
} |
||||||
|
HelloWorldSubCmd::Query(query) => { |
||||||
|
let program_storage_key = |
||||||
|
Pubkey::find_program_address(program_storage_pda_seeds!(), &query.program_id); |
||||||
|
let account = ctx.client.get_account(&program_storage_key.0).unwrap(); |
||||||
|
let storage = HelloWorldStorageAccount::fetch(&mut &account.data[..]) |
||||||
|
.unwrap() |
||||||
|
.into_inner(); |
||||||
|
println!("HelloWorld storage: {:?}", storage); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, Serialize, Clone)] |
||||||
|
struct HelloWorldConfig { |
||||||
|
#[serde(flatten)] |
||||||
|
router_config: RouterConfig, |
||||||
|
} |
||||||
|
|
||||||
|
struct HelloWorldDeployer {} |
||||||
|
|
||||||
|
impl HelloWorldDeployer { |
||||||
|
fn new() -> Self { |
||||||
|
Self {} |
||||||
|
} |
||||||
|
|
||||||
|
fn get_storage(&self, client: &RpcClient, program_id: &Pubkey) -> HelloWorldStorage { |
||||||
|
let (program_storage_account, _program_storage_bump) = |
||||||
|
Pubkey::find_program_address(program_storage_pda_seeds!(), program_id); |
||||||
|
|
||||||
|
let account = client.get_account(&program_storage_account).unwrap(); |
||||||
|
*HelloWorldStorageAccount::fetch(&mut &account.data[..]) |
||||||
|
.unwrap() |
||||||
|
.into_inner() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl RouterDeployer<HelloWorldConfig> for HelloWorldDeployer { |
||||||
|
fn program_name(&self, _config: &HelloWorldConfig) -> &str { |
||||||
|
"hyperlane_sealevel_hello_world" |
||||||
|
} |
||||||
|
|
||||||
|
fn enroll_remote_routers_instruction( |
||||||
|
&self, |
||||||
|
program_id: Pubkey, |
||||||
|
payer: Pubkey, |
||||||
|
router_configs: Vec<RemoteRouterConfig>, |
||||||
|
) -> Instruction { |
||||||
|
enroll_remote_routers_instruction(program_id, payer, router_configs).unwrap() |
||||||
|
} |
||||||
|
|
||||||
|
fn get_routers(&self, client: &RpcClient, program_id: &Pubkey) -> HashMap<u32, H256> { |
||||||
|
let storage = self.get_storage(client, program_id); |
||||||
|
|
||||||
|
storage.routers |
||||||
|
} |
||||||
|
|
||||||
|
fn init_program_idempotent( |
||||||
|
&self, |
||||||
|
ctx: &mut Context, |
||||||
|
client: &RpcClient, |
||||||
|
core_program_ids: &CoreProgramIds, |
||||||
|
chain_config: &ChainMetadata, |
||||||
|
app_config: &HelloWorldConfig, |
||||||
|
program_id: Pubkey, |
||||||
|
) { |
||||||
|
let (program_storage_account, _program_storage_bump) = |
||||||
|
Pubkey::find_program_address(program_storage_pda_seeds!(), &program_id); |
||||||
|
if account_exists(client, &program_storage_account).unwrap() { |
||||||
|
println!("HelloWorld storage already exists, skipping init"); |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
let domain_id = chain_config.domain_id(); |
||||||
|
let mailbox = app_config |
||||||
|
.router_config() |
||||||
|
.connection_client |
||||||
|
.mailbox(core_program_ids.mailbox); |
||||||
|
let ism = app_config |
||||||
|
.router_config() |
||||||
|
.connection_client |
||||||
|
.interchain_security_module(); |
||||||
|
let owner = Some(app_config.router_config().ownable.owner(ctx.payer_pubkey)); |
||||||
|
|
||||||
|
ctx.new_txn() |
||||||
|
.add_with_description( |
||||||
|
init_instruction( |
||||||
|
program_id, |
||||||
|
ctx.payer_pubkey, |
||||||
|
domain_id, |
||||||
|
mailbox, |
||||||
|
ism, |
||||||
|
// TODO revisit this when we want to deploy with IGPs
|
||||||
|
None, |
||||||
|
owner, |
||||||
|
) |
||||||
|
.unwrap(), |
||||||
|
format!( |
||||||
|
"Initializing HelloWorld program: domain_id: {}, mailbox: {}, ism: {:?}, owner: {:?}", |
||||||
|
domain_id, mailbox, ism, owner |
||||||
|
) |
||||||
|
) |
||||||
|
.with_client(client) |
||||||
|
.send_with_payer(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl RouterConfigGetter for HelloWorldConfig { |
||||||
|
fn router_config(&self) -> &RouterConfig { |
||||||
|
&self.router_config |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl Ownable for HelloWorldDeployer { |
||||||
|
/// Gets the owner configured on-chain.
|
||||||
|
fn get_owner(&self, client: &RpcClient, program_id: &Pubkey) -> Option<Pubkey> { |
||||||
|
let storage = self.get_storage(client, program_id); |
||||||
|
|
||||||
|
storage.owner |
||||||
|
} |
||||||
|
|
||||||
|
/// Gets an instruction to set the owner.
|
||||||
|
fn set_owner_instruction( |
||||||
|
&self, |
||||||
|
_client: &RpcClient, |
||||||
|
_program_id: &Pubkey, |
||||||
|
_new_owner: Option<Pubkey>, |
||||||
|
) -> Instruction { |
||||||
|
unimplemented!("HelloWorld does not support changing the owner") |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl ConnectionClient for HelloWorldDeployer { |
||||||
|
fn get_interchain_security_module( |
||||||
|
&self, |
||||||
|
client: &RpcClient, |
||||||
|
program_id: &Pubkey, |
||||||
|
) -> Option<Pubkey> { |
||||||
|
let storage = self.get_storage(client, program_id); |
||||||
|
|
||||||
|
storage.ism |
||||||
|
} |
||||||
|
|
||||||
|
fn set_interchain_security_module_instruction( |
||||||
|
&self, |
||||||
|
client: &RpcClient, |
||||||
|
program_id: &Pubkey, |
||||||
|
ism: Option<Pubkey>, |
||||||
|
) -> Instruction { |
||||||
|
let storage = self.get_storage(client, program_id); |
||||||
|
|
||||||
|
set_interchain_security_module_instruction(*program_id, storage.owner.unwrap(), ism) |
||||||
|
.unwrap() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fn deploy_helloworld(ctx: &mut Context, deploy: HelloWorldDeploy) { |
||||||
|
deploy_routers( |
||||||
|
ctx, |
||||||
|
HelloWorldDeployer::new(), |
||||||
|
"helloworld", |
||||||
|
&deploy.context, |
||||||
|
deploy.config_file, |
||||||
|
deploy.chain_config_file, |
||||||
|
deploy.environments_dir, |
||||||
|
&deploy.environment, |
||||||
|
deploy.built_so_dir, |
||||||
|
) |
||||||
|
} |
@ -0,0 +1,312 @@ |
|||||||
|
use std::collections::{HashMap, HashSet}; |
||||||
|
use std::{fs::File, path::Path}; |
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize}; |
||||||
|
use solana_program::pubkey::Pubkey; |
||||||
|
use solana_sdk::signature::Signer; |
||||||
|
|
||||||
|
use crate::{ |
||||||
|
artifacts::{write_json, SingularProgramIdArtifact}, |
||||||
|
cmd_utils::{create_and_write_keypair, create_new_directory, deploy_program}, |
||||||
|
router::ChainMetadata, |
||||||
|
Context, MultisigIsmMessageIdCmd, MultisigIsmMessageIdSubCmd, |
||||||
|
}; |
||||||
|
|
||||||
|
use hyperlane_core::H160; |
||||||
|
|
||||||
|
use hyperlane_sealevel_multisig_ism_message_id::{ |
||||||
|
access_control_pda_seeds, |
||||||
|
accounts::{AccessControlAccount, DomainDataAccount}, |
||||||
|
domain_data_pda_seeds, |
||||||
|
instruction::{set_validators_and_threshold_instruction, ValidatorsAndThreshold}, |
||||||
|
}; |
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize)] |
||||||
|
#[serde(rename_all = "camelCase")] |
||||||
|
pub(crate) struct MultisigIsmConfig { |
||||||
|
/// Note this type is ignored in this tooling. It'll always assume this
|
||||||
|
/// relates to a multisig-ism-message-id variant, which is the only type
|
||||||
|
/// implemented in Sealevel.
|
||||||
|
#[serde(rename = "type")] |
||||||
|
pub module_type: u8, |
||||||
|
pub validators: Vec<H160>, |
||||||
|
pub threshold: u8, |
||||||
|
} |
||||||
|
|
||||||
|
impl From<MultisigIsmConfig> for ValidatorsAndThreshold { |
||||||
|
fn from(val: MultisigIsmConfig) -> Self { |
||||||
|
ValidatorsAndThreshold { |
||||||
|
validators: val.validators, |
||||||
|
threshold: val.threshold, |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub(crate) fn process_multisig_ism_message_id_cmd(mut ctx: Context, cmd: MultisigIsmMessageIdCmd) { |
||||||
|
match cmd.cmd { |
||||||
|
MultisigIsmMessageIdSubCmd::Deploy(deploy) => { |
||||||
|
let environments_dir = |
||||||
|
create_new_directory(&deploy.environments_dir, &deploy.environment); |
||||||
|
let ism_dir = create_new_directory(&environments_dir, "multisig-ism-message-id"); |
||||||
|
let chain_dir = create_new_directory(&ism_dir, &deploy.chain); |
||||||
|
let context_dir = create_new_directory(&chain_dir, &deploy.context); |
||||||
|
let key_dir = create_new_directory(&context_dir, "keys"); |
||||||
|
|
||||||
|
let ism_program_id = |
||||||
|
deploy_multisig_ism_message_id(&mut ctx, &deploy.built_so_dir, true, &key_dir); |
||||||
|
|
||||||
|
write_json::<SingularProgramIdArtifact>( |
||||||
|
&context_dir.join("program-ids.json"), |
||||||
|
ism_program_id.into(), |
||||||
|
); |
||||||
|
} |
||||||
|
MultisigIsmMessageIdSubCmd::Init(init) => { |
||||||
|
let init_instruction = |
||||||
|
hyperlane_sealevel_multisig_ism_message_id::instruction::init_instruction( |
||||||
|
init.program_id, |
||||||
|
ctx.payer_pubkey, |
||||||
|
) |
||||||
|
.unwrap(); |
||||||
|
ctx.new_txn().add(init_instruction).send_with_payer(); |
||||||
|
} |
||||||
|
MultisigIsmMessageIdSubCmd::SetValidatorsAndThreshold(set_config) => { |
||||||
|
set_validators_and_threshold( |
||||||
|
&mut ctx, |
||||||
|
set_config.program_id, |
||||||
|
set_config.domain, |
||||||
|
ValidatorsAndThreshold { |
||||||
|
validators: set_config.validators, |
||||||
|
threshold: set_config.threshold, |
||||||
|
}, |
||||||
|
); |
||||||
|
} |
||||||
|
MultisigIsmMessageIdSubCmd::Query(query) => { |
||||||
|
let (access_control_pda_key, _access_control_pda_bump) = |
||||||
|
Pubkey::find_program_address(access_control_pda_seeds!(), &query.program_id); |
||||||
|
|
||||||
|
let accounts = ctx |
||||||
|
.client |
||||||
|
.get_multiple_accounts_with_commitment(&[access_control_pda_key], ctx.commitment) |
||||||
|
.unwrap() |
||||||
|
.value; |
||||||
|
let access_control = |
||||||
|
AccessControlAccount::fetch(&mut &accounts[0].as_ref().unwrap().data[..]) |
||||||
|
.unwrap() |
||||||
|
.into_inner(); |
||||||
|
println!("Access control: {:#?}", access_control); |
||||||
|
|
||||||
|
if let Some(domains) = query.domains { |
||||||
|
for domain in domains { |
||||||
|
println!("Querying domain data for origin domain: {}", domain); |
||||||
|
|
||||||
|
let (domain_data_pda_key, _domain_data_pda_bump) = Pubkey::find_program_address( |
||||||
|
domain_data_pda_seeds!(domain), |
||||||
|
&query.program_id, |
||||||
|
); |
||||||
|
|
||||||
|
let accounts = ctx |
||||||
|
.client |
||||||
|
.get_multiple_accounts_with_commitment( |
||||||
|
&[domain_data_pda_key], |
||||||
|
ctx.commitment, |
||||||
|
) |
||||||
|
.unwrap() |
||||||
|
.value; |
||||||
|
|
||||||
|
if let Some(account) = &accounts[0] { |
||||||
|
let domain_data = DomainDataAccount::fetch(&mut &account.data[..]) |
||||||
|
.unwrap() |
||||||
|
.into_inner(); |
||||||
|
println!("Domain data for {}:\n{:#?}", domain, domain_data); |
||||||
|
} else { |
||||||
|
println!("No domain data for domain {}", domain); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
MultisigIsmMessageIdSubCmd::TransferOwnership(transfer_ownership) => { |
||||||
|
let instruction = |
||||||
|
hyperlane_sealevel_multisig_ism_message_id::instruction::transfer_ownership_instruction( |
||||||
|
transfer_ownership.program_id, |
||||||
|
ctx.payer_pubkey, |
||||||
|
Some(transfer_ownership.new_owner), |
||||||
|
) |
||||||
|
.unwrap(); |
||||||
|
|
||||||
|
ctx.new_txn() |
||||||
|
.add_with_description( |
||||||
|
instruction, |
||||||
|
format!("Transfer ownership to {}", transfer_ownership.new_owner), |
||||||
|
) |
||||||
|
.send_with_payer(); |
||||||
|
} |
||||||
|
MultisigIsmMessageIdSubCmd::Configure(configure) => { |
||||||
|
configure_multisig_ism_message_id( |
||||||
|
&mut ctx, |
||||||
|
configure.program_id, |
||||||
|
&configure.multisig_config_file, |
||||||
|
&configure.chain_config_file, |
||||||
|
); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub(crate) fn deploy_multisig_ism_message_id( |
||||||
|
ctx: &mut Context, |
||||||
|
built_so_dir: &Path, |
||||||
|
use_existing_keys: bool, |
||||||
|
key_dir: &Path, |
||||||
|
) -> Pubkey { |
||||||
|
let (keypair, keypair_path) = create_and_write_keypair( |
||||||
|
key_dir, |
||||||
|
"hyperlane_sealevel_multisig_ism_message_id-keypair.json", |
||||||
|
use_existing_keys, |
||||||
|
); |
||||||
|
let program_id = keypair.pubkey(); |
||||||
|
|
||||||
|
deploy_program( |
||||||
|
ctx.payer_keypair_path(), |
||||||
|
keypair_path.to_str().unwrap(), |
||||||
|
built_so_dir |
||||||
|
.join("hyperlane_sealevel_multisig_ism_message_id.so") |
||||||
|
.to_str() |
||||||
|
.unwrap(), |
||||||
|
&ctx.client.url(), |
||||||
|
); |
||||||
|
|
||||||
|
println!( |
||||||
|
"Deployed Multisig ISM Message ID at program ID {}", |
||||||
|
program_id |
||||||
|
); |
||||||
|
|
||||||
|
// Initialize
|
||||||
|
let instruction = hyperlane_sealevel_multisig_ism_message_id::instruction::init_instruction( |
||||||
|
program_id, |
||||||
|
ctx.payer_pubkey, |
||||||
|
) |
||||||
|
.unwrap(); |
||||||
|
|
||||||
|
ctx.new_txn() |
||||||
|
.add_with_description( |
||||||
|
instruction, |
||||||
|
format!( |
||||||
|
"Initializing Multisig ISM Message ID with payer & owner {}", |
||||||
|
ctx.payer_pubkey |
||||||
|
), |
||||||
|
) |
||||||
|
.send_with_payer(); |
||||||
|
|
||||||
|
program_id |
||||||
|
} |
||||||
|
|
||||||
|
/// Configures the multisig-ism-message-id program
|
||||||
|
/// with the validators and thresholds for each of the domains
|
||||||
|
/// specified in the multisig config file.
|
||||||
|
fn configure_multisig_ism_message_id( |
||||||
|
ctx: &mut Context, |
||||||
|
program_id: Pubkey, |
||||||
|
multisig_config_file_path: &Path, |
||||||
|
chain_config_path: &Path, |
||||||
|
) { |
||||||
|
let multisig_config_file = |
||||||
|
File::open(multisig_config_file_path).expect("Failed to open config file"); |
||||||
|
let multisig_configs: HashMap<String, MultisigIsmConfig> = |
||||||
|
serde_json::from_reader(multisig_config_file).expect("Failed to read config file"); |
||||||
|
|
||||||
|
let chain_config_file = File::open(chain_config_path).unwrap(); |
||||||
|
let chain_configs: HashMap<String, ChainMetadata> = |
||||||
|
serde_json::from_reader(chain_config_file).unwrap(); |
||||||
|
|
||||||
|
for (chain_name, multisig_ism_config) in multisig_configs { |
||||||
|
println!( |
||||||
|
"Configuring Multisig ISM Message ID for chain {} and config {:?}", |
||||||
|
chain_name, multisig_ism_config |
||||||
|
); |
||||||
|
let chain_config = chain_configs.get(&chain_name).unwrap(); |
||||||
|
|
||||||
|
let matches = multisig_ism_config_matches_chain( |
||||||
|
ctx, |
||||||
|
program_id, |
||||||
|
chain_config.domain_id(), |
||||||
|
&multisig_ism_config, |
||||||
|
); |
||||||
|
|
||||||
|
if matches { |
||||||
|
println!( |
||||||
|
"Multisig ISM Message ID already correctly configured for chain {}", |
||||||
|
chain_name |
||||||
|
); |
||||||
|
} else { |
||||||
|
println!( |
||||||
|
"Multisig ISM Message ID incorrectly configured for chain {}, configuring now", |
||||||
|
chain_name |
||||||
|
); |
||||||
|
set_validators_and_threshold( |
||||||
|
ctx, |
||||||
|
program_id, |
||||||
|
chain_config.domain_id(), |
||||||
|
multisig_ism_config.into(), |
||||||
|
); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fn multisig_ism_config_matches_chain( |
||||||
|
ctx: &mut Context, |
||||||
|
program_id: Pubkey, |
||||||
|
remote_domain: u32, |
||||||
|
expected: &MultisigIsmConfig, |
||||||
|
) -> bool { |
||||||
|
let (domain_data_key, _domain_data_bump) = |
||||||
|
Pubkey::find_program_address(domain_data_pda_seeds!(remote_domain), &program_id); |
||||||
|
|
||||||
|
let domain_data_account = ctx |
||||||
|
.client |
||||||
|
.get_account_with_commitment(&domain_data_key, ctx.commitment) |
||||||
|
.expect("Failed to get domain data account") |
||||||
|
.value; |
||||||
|
|
||||||
|
if let Some(domain_data_account) = domain_data_account { |
||||||
|
let domain_data = DomainDataAccount::fetch(&mut &domain_data_account.data[..]) |
||||||
|
.unwrap() |
||||||
|
.into_inner(); |
||||||
|
let expected_validator_set = |
||||||
|
HashSet::<H160>::from_iter(expected.validators.iter().cloned()); |
||||||
|
let actual_validator_set = HashSet::<H160>::from_iter( |
||||||
|
domain_data |
||||||
|
.validators_and_threshold |
||||||
|
.validators |
||||||
|
.iter() |
||||||
|
.cloned(), |
||||||
|
); |
||||||
|
|
||||||
|
expected_validator_set == actual_validator_set |
||||||
|
&& expected.threshold == domain_data.validators_and_threshold.threshold |
||||||
|
} else { |
||||||
|
false |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub(crate) fn set_validators_and_threshold( |
||||||
|
ctx: &mut Context, |
||||||
|
program_id: Pubkey, |
||||||
|
domain: u32, |
||||||
|
validators_and_threshold: ValidatorsAndThreshold, |
||||||
|
) { |
||||||
|
let description = format!( |
||||||
|
"Set for remote domain {} validators and threshold: {:?}", |
||||||
|
domain, validators_and_threshold |
||||||
|
); |
||||||
|
ctx.new_txn() |
||||||
|
.add_with_description( |
||||||
|
set_validators_and_threshold_instruction( |
||||||
|
program_id, |
||||||
|
ctx.payer_pubkey, |
||||||
|
domain, |
||||||
|
validators_and_threshold, |
||||||
|
) |
||||||
|
.unwrap(), |
||||||
|
description, |
||||||
|
) |
||||||
|
.send_with_payer(); |
||||||
|
} |
@ -0,0 +1,593 @@ |
|||||||
|
use hyperlane_core::{utils::hex_or_base58_to_h256, H256}; |
||||||
|
use serde::{Deserialize, Serialize}; |
||||||
|
use std::{ |
||||||
|
collections::HashMap, |
||||||
|
fs::File, |
||||||
|
path::{Path, PathBuf}, |
||||||
|
}; |
||||||
|
|
||||||
|
use solana_client::rpc_client::RpcClient; |
||||||
|
use solana_program::instruction::Instruction; |
||||||
|
use solana_sdk::{commitment_config::CommitmentConfig, pubkey::Pubkey, signature::Signer}; |
||||||
|
|
||||||
|
use account_utils::DiscriminatorData; |
||||||
|
use hyperlane_sealevel_connection_client::router::RemoteRouterConfig; |
||||||
|
use hyperlane_sealevel_igp::accounts::{Igp, InterchainGasPaymasterType, OverheadIgp}; |
||||||
|
|
||||||
|
use crate::{ |
||||||
|
artifacts::{write_json, HexAndBase58ProgramIdArtifact}, |
||||||
|
cmd_utils::{create_and_write_keypair, create_new_directory, deploy_program_idempotent}, |
||||||
|
read_core_program_ids, Context, CoreProgramIds, |
||||||
|
}; |
||||||
|
|
||||||
|
/// Optional connection client configuration.
|
||||||
|
#[derive(Debug, Deserialize, Serialize, Clone)] |
||||||
|
#[serde(rename_all = "camelCase")] |
||||||
|
pub struct OptionalConnectionClientConfig { |
||||||
|
#[serde(default)] |
||||||
|
#[serde(with = "crate::serde::serde_option_pubkey")] |
||||||
|
mailbox: Option<Pubkey>, |
||||||
|
#[serde(default)] |
||||||
|
#[serde(with = "crate::serde::serde_option_pubkey")] |
||||||
|
interchain_gas_paymaster: Option<Pubkey>, |
||||||
|
#[serde(default)] |
||||||
|
#[serde(with = "crate::serde::serde_option_pubkey")] |
||||||
|
interchain_security_module: Option<Pubkey>, |
||||||
|
} |
||||||
|
|
||||||
|
impl OptionalConnectionClientConfig { |
||||||
|
pub fn mailbox(&self, default: Pubkey) -> Pubkey { |
||||||
|
self.mailbox.unwrap_or(default) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn interchain_security_module(&self) -> Option<Pubkey> { |
||||||
|
self.interchain_security_module |
||||||
|
} |
||||||
|
|
||||||
|
/// Uses the configured IGP account, if Some, to get the IGP program ID
|
||||||
|
/// and generate a config of the form Some((program_id, Igp account)).
|
||||||
|
pub fn interchain_gas_paymaster_config( |
||||||
|
&self, |
||||||
|
client: &RpcClient, |
||||||
|
) -> Option<(Pubkey, InterchainGasPaymasterType)> { |
||||||
|
if let Some(igp_pubkey) = self.interchain_gas_paymaster { |
||||||
|
let account = client |
||||||
|
.get_account(&self.interchain_gas_paymaster.unwrap()) |
||||||
|
.unwrap(); |
||||||
|
|
||||||
|
match &account.data[1..9] { |
||||||
|
Igp::DISCRIMINATOR_SLICE => { |
||||||
|
Some((account.owner, InterchainGasPaymasterType::Igp(igp_pubkey))) |
||||||
|
} |
||||||
|
OverheadIgp::DISCRIMINATOR_SLICE => Some(( |
||||||
|
account.owner, |
||||||
|
InterchainGasPaymasterType::OverheadIgp(igp_pubkey), |
||||||
|
)), |
||||||
|
_ => { |
||||||
|
panic!("Invalid IGP account configured {}", igp_pubkey); |
||||||
|
} |
||||||
|
} |
||||||
|
} else { |
||||||
|
None |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// Optional ownable configuration.
|
||||||
|
#[derive(Debug, Deserialize, Serialize, Clone)] |
||||||
|
#[serde(rename_all = "camelCase")] |
||||||
|
pub struct OptionalOwnableConfig { |
||||||
|
#[serde(default)] |
||||||
|
#[serde(with = "crate::serde::serde_option_pubkey")] |
||||||
|
pub owner: Option<Pubkey>, |
||||||
|
} |
||||||
|
|
||||||
|
impl OptionalOwnableConfig { |
||||||
|
pub fn owner(&self, default: Pubkey) -> Pubkey { |
||||||
|
self.owner.unwrap_or(default) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// Router configuration.
|
||||||
|
#[derive(Debug, Deserialize, Serialize, Clone)] |
||||||
|
#[serde(rename_all = "camelCase")] |
||||||
|
pub struct RouterConfig { |
||||||
|
// Kept as a string to allow for hex or base58
|
||||||
|
pub foreign_deployment: Option<String>, |
||||||
|
#[serde(flatten)] |
||||||
|
pub ownable: OptionalOwnableConfig, |
||||||
|
#[serde(flatten)] |
||||||
|
pub connection_client: OptionalConnectionClientConfig, |
||||||
|
} |
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, Serialize, Clone)] |
||||||
|
#[serde(rename_all = "camelCase")] |
||||||
|
pub struct RpcUrlConfig { |
||||||
|
pub http: String, |
||||||
|
} |
||||||
|
|
||||||
|
/// An abridged version of the Typescript ChainMetadata
|
||||||
|
#[derive(Debug, Deserialize, Serialize, Clone)] |
||||||
|
#[serde(rename_all = "camelCase")] |
||||||
|
pub struct ChainMetadata { |
||||||
|
chain_id: u32, |
||||||
|
/// Hyperlane domain, only required if differs from id above
|
||||||
|
domain_id: Option<u32>, |
||||||
|
name: String, |
||||||
|
/// Collection of RPC endpoints
|
||||||
|
rpc_urls: Vec<RpcUrlConfig>, |
||||||
|
} |
||||||
|
|
||||||
|
impl ChainMetadata { |
||||||
|
pub fn client(&self) -> RpcClient { |
||||||
|
RpcClient::new_with_commitment(self.rpc_urls[0].http.clone(), CommitmentConfig::confirmed()) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn domain_id(&self) -> u32 { |
||||||
|
self.domain_id.unwrap_or(self.chain_id) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub trait RouterConfigGetter { |
||||||
|
fn router_config(&self) -> &RouterConfig; |
||||||
|
} |
||||||
|
|
||||||
|
pub(crate) trait RouterDeployer<Config: RouterConfigGetter + std::fmt::Debug>: |
||||||
|
ConnectionClient |
||||||
|
{ |
||||||
|
#[allow(clippy::too_many_arguments)] |
||||||
|
fn deploy( |
||||||
|
&self, |
||||||
|
ctx: &mut Context, |
||||||
|
key_dir: &Path, |
||||||
|
environments_dir: &Path, |
||||||
|
environment: &str, |
||||||
|
built_so_dir: &Path, |
||||||
|
chain_config: &ChainMetadata, |
||||||
|
app_config: &Config, |
||||||
|
existing_program_ids: Option<&HashMap<String, Pubkey>>, |
||||||
|
) -> Pubkey { |
||||||
|
let program_name = self.program_name(app_config); |
||||||
|
|
||||||
|
println!( |
||||||
|
"Attempting deploy {} on chain: {}\nApp config: {:?}", |
||||||
|
program_name, chain_config.name, app_config |
||||||
|
); |
||||||
|
|
||||||
|
let program_id = existing_program_ids |
||||||
|
.and_then(|existing_program_ids| { |
||||||
|
existing_program_ids.get(&chain_config.name).and_then(|id| { |
||||||
|
chain_config |
||||||
|
.client() |
||||||
|
.get_account_with_commitment(id, ctx.commitment) |
||||||
|
.unwrap() |
||||||
|
.value |
||||||
|
.map(|_| { |
||||||
|
println!("Recovered existing program id {}", id); |
||||||
|
*id |
||||||
|
}) |
||||||
|
}) |
||||||
|
}) |
||||||
|
.unwrap_or_else(|| { |
||||||
|
let (keypair, keypair_path) = create_and_write_keypair( |
||||||
|
key_dir, |
||||||
|
format!("{}-{}.json", program_name, chain_config.name).as_str(), |
||||||
|
true, |
||||||
|
); |
||||||
|
let program_id = keypair.pubkey(); |
||||||
|
|
||||||
|
deploy_program_idempotent( |
||||||
|
ctx.payer_keypair_path(), |
||||||
|
&keypair, |
||||||
|
keypair_path.to_str().unwrap(), |
||||||
|
built_so_dir |
||||||
|
.join(format!("{}.so", program_name)) |
||||||
|
.to_str() |
||||||
|
.unwrap(), |
||||||
|
&chain_config.rpc_urls[0].http, |
||||||
|
) |
||||||
|
.unwrap(); |
||||||
|
|
||||||
|
program_id |
||||||
|
}); |
||||||
|
|
||||||
|
let core_program_ids = |
||||||
|
read_core_program_ids(environments_dir, environment, &chain_config.name); |
||||||
|
self.init_program_idempotent( |
||||||
|
ctx, |
||||||
|
&chain_config.client(), |
||||||
|
&core_program_ids, |
||||||
|
chain_config, |
||||||
|
app_config, |
||||||
|
program_id, |
||||||
|
); |
||||||
|
|
||||||
|
program_id |
||||||
|
} |
||||||
|
|
||||||
|
fn init_program_idempotent( |
||||||
|
&self, |
||||||
|
ctx: &mut Context, |
||||||
|
client: &RpcClient, |
||||||
|
core_program_ids: &CoreProgramIds, |
||||||
|
chain_config: &ChainMetadata, |
||||||
|
app_config: &Config, |
||||||
|
program_id: Pubkey, |
||||||
|
); |
||||||
|
|
||||||
|
fn post_deploy( |
||||||
|
&self, |
||||||
|
_ctx: &mut Context, |
||||||
|
_app_configs: &HashMap<String, Config>, |
||||||
|
_app_configs_to_deploy: &HashMap<&String, &Config>, |
||||||
|
_chain_configs: &HashMap<String, ChainMetadata>, |
||||||
|
_routers: &HashMap<u32, H256>, |
||||||
|
) { |
||||||
|
// By default, do nothing.
|
||||||
|
} |
||||||
|
|
||||||
|
/// The program's name, i.e. the name of the program's .so file (without the .so suffix)
|
||||||
|
/// and the name that will be used to create the keypair file
|
||||||
|
fn program_name(&self, config: &Config) -> &str; |
||||||
|
|
||||||
|
fn enroll_remote_routers_instruction( |
||||||
|
&self, |
||||||
|
program_id: Pubkey, |
||||||
|
payer: Pubkey, |
||||||
|
router_configs: Vec<RemoteRouterConfig>, |
||||||
|
) -> Instruction; |
||||||
|
|
||||||
|
fn get_routers(&self, rpc_client: &RpcClient, program_id: &Pubkey) -> HashMap<u32, H256>; |
||||||
|
} |
||||||
|
|
||||||
|
pub(crate) trait Ownable { |
||||||
|
/// Gets the owner configured on-chain.
|
||||||
|
fn get_owner(&self, client: &RpcClient, program_id: &Pubkey) -> Option<Pubkey>; |
||||||
|
|
||||||
|
/// Gets an instruction to set the owner.
|
||||||
|
fn set_owner_instruction( |
||||||
|
&self, |
||||||
|
client: &RpcClient, |
||||||
|
program_id: &Pubkey, |
||||||
|
new_owner: Option<Pubkey>, |
||||||
|
) -> Instruction; |
||||||
|
} |
||||||
|
|
||||||
|
pub(crate) trait ConnectionClient: Ownable { |
||||||
|
/// Gets the interchain security module configured on-chain.
|
||||||
|
fn get_interchain_security_module( |
||||||
|
&self, |
||||||
|
client: &RpcClient, |
||||||
|
program_id: &Pubkey, |
||||||
|
) -> Option<Pubkey>; |
||||||
|
|
||||||
|
/// Gets an instruction to set the interchain security module.
|
||||||
|
fn set_interchain_security_module_instruction( |
||||||
|
&self, |
||||||
|
client: &RpcClient, |
||||||
|
program_id: &Pubkey, |
||||||
|
ism: Option<Pubkey>, |
||||||
|
) -> Instruction; |
||||||
|
} |
||||||
|
|
||||||
|
/// Idempotently deploys routers on multiple Sealevel chains and enrolls all routers (including
|
||||||
|
/// foreign deployments) on each Sealevel chain.
|
||||||
|
#[allow(clippy::too_many_arguments)] |
||||||
|
pub(crate) fn deploy_routers< |
||||||
|
Config: for<'a> Deserialize<'a> + RouterConfigGetter + std::fmt::Debug + Clone, |
||||||
|
Deployer: RouterDeployer<Config>, |
||||||
|
>( |
||||||
|
ctx: &mut Context, |
||||||
|
deployer: Deployer, |
||||||
|
app_name: &str, |
||||||
|
deploy_name: &str, |
||||||
|
app_config_file_path: PathBuf, |
||||||
|
chain_config_file_path: PathBuf, |
||||||
|
environments_dir_path: PathBuf, |
||||||
|
environment: &str, |
||||||
|
built_so_dir_path: PathBuf, |
||||||
|
) { |
||||||
|
// Load the app configs from the app config file.
|
||||||
|
let app_config_file = File::open(app_config_file_path).unwrap(); |
||||||
|
let app_configs: HashMap<String, Config> = serde_json::from_reader(app_config_file).unwrap(); |
||||||
|
|
||||||
|
// Load the chain configs from the chain config file.
|
||||||
|
let chain_config_file = File::open(chain_config_file_path).unwrap(); |
||||||
|
let chain_configs: HashMap<String, ChainMetadata> = |
||||||
|
serde_json::from_reader(chain_config_file).unwrap(); |
||||||
|
|
||||||
|
let environments_dir = create_new_directory(&environments_dir_path, environment); |
||||||
|
|
||||||
|
let artifacts_dir = create_new_directory(&environments_dir, app_name); |
||||||
|
let deploy_dir = create_new_directory(&artifacts_dir, deploy_name); |
||||||
|
let keys_dir = create_new_directory(&deploy_dir, "keys"); |
||||||
|
|
||||||
|
let existing_program_ids = read_router_program_ids(&deploy_dir); |
||||||
|
|
||||||
|
// Builds a HashMap of all the foreign deployments from the app config.
|
||||||
|
// These domains with foreign deployments will not have any txs / deployments
|
||||||
|
// made directly to them, but the routers will be enrolled on the other chains.
|
||||||
|
let foreign_deployments = app_configs |
||||||
|
.iter() |
||||||
|
.filter_map(|(chain_name, app_config)| { |
||||||
|
app_config |
||||||
|
.router_config() |
||||||
|
.foreign_deployment |
||||||
|
.as_ref() |
||||||
|
.map(|foreign_deployment| { |
||||||
|
let chain_config = chain_configs.get(chain_name).unwrap(); |
||||||
|
( |
||||||
|
chain_config.domain_id(), |
||||||
|
hex_or_base58_to_h256(foreign_deployment).unwrap(), |
||||||
|
) |
||||||
|
}) |
||||||
|
}) |
||||||
|
.collect::<HashMap<u32, H256>>(); |
||||||
|
|
||||||
|
// A map of all the routers, including the foreign deployments.
|
||||||
|
let mut routers: HashMap<u32, H256> = foreign_deployments; |
||||||
|
|
||||||
|
// Non-foreign app configs to deploy to.
|
||||||
|
let app_configs_to_deploy = app_configs |
||||||
|
.iter() |
||||||
|
.filter(|(_, app_config)| app_config.router_config().foreign_deployment.is_none()) |
||||||
|
.collect::<HashMap<_, _>>(); |
||||||
|
|
||||||
|
// Now we deploy to chains that don't have a foreign deployment
|
||||||
|
for (chain_name, app_config) in app_configs_to_deploy.iter() { |
||||||
|
let chain_config = chain_configs |
||||||
|
.get(*chain_name) |
||||||
|
.unwrap_or_else(|| panic!("Chain config not found for chain: {}", chain_name)); |
||||||
|
|
||||||
|
if let Some(configured_owner) = app_config.router_config().ownable.owner { |
||||||
|
if configured_owner != ctx.payer_pubkey { |
||||||
|
println!("WARNING: Ownership transfer is not yet supported in this deploy tooling, ownership is granted to the payer account"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Deploy - this is idempotent.
|
||||||
|
let program_id = deployer.deploy( |
||||||
|
ctx, |
||||||
|
&keys_dir, |
||||||
|
&environments_dir_path, |
||||||
|
environment, |
||||||
|
&built_so_dir_path, |
||||||
|
chain_config, |
||||||
|
app_config, |
||||||
|
existing_program_ids.as_ref(), |
||||||
|
); |
||||||
|
|
||||||
|
// Add the router to the list of routers.
|
||||||
|
routers.insert( |
||||||
|
chain_config.domain_id(), |
||||||
|
H256::from_slice(&program_id.to_bytes()[..]), |
||||||
|
); |
||||||
|
|
||||||
|
configure_connection_client( |
||||||
|
ctx, |
||||||
|
&deployer, |
||||||
|
&program_id, |
||||||
|
app_config.router_config(), |
||||||
|
chain_config, |
||||||
|
); |
||||||
|
|
||||||
|
configure_owner( |
||||||
|
ctx, |
||||||
|
&deployer, |
||||||
|
&program_id, |
||||||
|
app_config.router_config(), |
||||||
|
chain_config, |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
// Now enroll all the routers.
|
||||||
|
enroll_all_remote_routers( |
||||||
|
&deployer, |
||||||
|
ctx, |
||||||
|
&app_configs_to_deploy, |
||||||
|
&chain_configs, |
||||||
|
&routers, |
||||||
|
); |
||||||
|
|
||||||
|
// Call the post-deploy hook.
|
||||||
|
deployer.post_deploy( |
||||||
|
ctx, |
||||||
|
&app_configs, |
||||||
|
&app_configs_to_deploy, |
||||||
|
&chain_configs, |
||||||
|
&routers, |
||||||
|
); |
||||||
|
|
||||||
|
// Now write the program ids to a file!
|
||||||
|
let routers_by_name: HashMap<String, H256> = routers |
||||||
|
.iter() |
||||||
|
.map(|(domain_id, router)| { |
||||||
|
( |
||||||
|
chain_configs |
||||||
|
.iter() |
||||||
|
.find(|(_, chain_config)| chain_config.domain_id() == *domain_id) |
||||||
|
.unwrap() |
||||||
|
.0 |
||||||
|
.clone(), |
||||||
|
*router, |
||||||
|
) |
||||||
|
}) |
||||||
|
.collect::<HashMap<String, H256>>(); |
||||||
|
write_router_program_ids(&deploy_dir, &routers_by_name); |
||||||
|
} |
||||||
|
|
||||||
|
// Idempotent.
|
||||||
|
// TODO: This should really be brought out into some nicer abstraction, and we should
|
||||||
|
// also look for IGP inconsistency etc.
|
||||||
|
fn configure_connection_client( |
||||||
|
ctx: &mut Context, |
||||||
|
deployer: &impl ConnectionClient, |
||||||
|
program_id: &Pubkey, |
||||||
|
router_config: &RouterConfig, |
||||||
|
chain_config: &ChainMetadata, |
||||||
|
) { |
||||||
|
// Just ISM for now
|
||||||
|
|
||||||
|
let client = chain_config.client(); |
||||||
|
|
||||||
|
let actual_ism = deployer.get_interchain_security_module(&client, program_id); |
||||||
|
let expected_ism = router_config.connection_client.interchain_security_module(); |
||||||
|
|
||||||
|
if actual_ism != expected_ism { |
||||||
|
ctx.new_txn() |
||||||
|
.add_with_description( |
||||||
|
deployer.set_interchain_security_module_instruction( |
||||||
|
&client, |
||||||
|
program_id, |
||||||
|
expected_ism, |
||||||
|
), |
||||||
|
format!( |
||||||
|
"Setting ISM for chain: {} ({}) to {:?}", |
||||||
|
chain_config.name, |
||||||
|
chain_config.domain_id(), |
||||||
|
expected_ism |
||||||
|
), |
||||||
|
) |
||||||
|
.with_client(&client) |
||||||
|
.send_with_payer(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Idempotent.
|
||||||
|
// TODO: This should really be brought out into some nicer abstraction
|
||||||
|
fn configure_owner( |
||||||
|
ctx: &mut Context, |
||||||
|
deployer: &impl ConnectionClient, |
||||||
|
program_id: &Pubkey, |
||||||
|
router_config: &RouterConfig, |
||||||
|
chain_config: &ChainMetadata, |
||||||
|
) { |
||||||
|
let client = chain_config.client(); |
||||||
|
|
||||||
|
let actual_owner = deployer.get_owner(&client, program_id); |
||||||
|
let expected_owner = Some(router_config.ownable.owner(ctx.payer_pubkey)); |
||||||
|
|
||||||
|
if actual_owner != expected_owner { |
||||||
|
ctx.new_txn() |
||||||
|
.add_with_description( |
||||||
|
deployer.set_owner_instruction(&client, program_id, expected_owner), |
||||||
|
format!( |
||||||
|
"Setting owner for chain: {} ({}) to {:?}", |
||||||
|
chain_config.name, |
||||||
|
chain_config.domain_id(), |
||||||
|
expected_owner, |
||||||
|
), |
||||||
|
) |
||||||
|
.with_client(&client) |
||||||
|
.send_with_payer(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// For each chain in app_configs_to_deploy, enrolls all the remote routers.
|
||||||
|
/// Idempotent.
|
||||||
|
fn enroll_all_remote_routers< |
||||||
|
Config: for<'a> Deserialize<'a> + RouterConfigGetter + std::fmt::Debug + Clone, |
||||||
|
>( |
||||||
|
deployer: &impl RouterDeployer<Config>, |
||||||
|
ctx: &mut Context, |
||||||
|
app_configs_to_deploy: &HashMap<&String, &Config>, |
||||||
|
chain_configs: &HashMap<String, ChainMetadata>, |
||||||
|
routers: &HashMap<u32, H256>, |
||||||
|
) { |
||||||
|
for (chain_name, _) in app_configs_to_deploy.iter() { |
||||||
|
let chain_config = chain_configs |
||||||
|
.get(*chain_name) |
||||||
|
.unwrap_or_else(|| panic!("Chain config not found for chain: {}", chain_name)); |
||||||
|
|
||||||
|
let domain_id = chain_config.domain_id(); |
||||||
|
let program_id: Pubkey = |
||||||
|
Pubkey::new_from_array(*routers.get(&domain_id).unwrap().as_fixed_bytes()); |
||||||
|
|
||||||
|
let enrolled_routers = deployer.get_routers(&chain_config.client(), &program_id); |
||||||
|
let expected_routers = routers |
||||||
|
.iter() |
||||||
|
.filter(|(router_domain_id, _)| *router_domain_id != &domain_id) |
||||||
|
.map(|(domain, router)| { |
||||||
|
( |
||||||
|
*domain, |
||||||
|
RemoteRouterConfig { |
||||||
|
domain: *domain, |
||||||
|
router: Some(*router), |
||||||
|
}, |
||||||
|
) |
||||||
|
}) |
||||||
|
.collect::<HashMap<u32, RemoteRouterConfig>>(); |
||||||
|
|
||||||
|
// Routers to enroll (or update to a Some value)
|
||||||
|
let routers_to_enroll = expected_routers |
||||||
|
.iter() |
||||||
|
.filter(|(domain, router_config)| { |
||||||
|
enrolled_routers.get(domain) != router_config.router.as_ref() |
||||||
|
}) |
||||||
|
.map(|(_, router_config)| router_config.clone()); |
||||||
|
|
||||||
|
// Routers to remove
|
||||||
|
let routers_to_unenroll = enrolled_routers |
||||||
|
.iter() |
||||||
|
.filter(|(domain, _)| !expected_routers.contains_key(domain)) |
||||||
|
.map(|(domain, _)| RemoteRouterConfig { |
||||||
|
domain: *domain, |
||||||
|
router: None, |
||||||
|
}); |
||||||
|
|
||||||
|
// All router config changes
|
||||||
|
let router_configs = routers_to_enroll |
||||||
|
.chain(routers_to_unenroll) |
||||||
|
.collect::<Vec<RemoteRouterConfig>>(); |
||||||
|
|
||||||
|
if !router_configs.is_empty() { |
||||||
|
println!( |
||||||
|
"Enrolling routers for chain: {}, program_id {}, routers: {:?}", |
||||||
|
chain_name, program_id, router_configs, |
||||||
|
); |
||||||
|
|
||||||
|
ctx.new_txn() |
||||||
|
.add(deployer.enroll_remote_routers_instruction( |
||||||
|
program_id, |
||||||
|
ctx.payer_pubkey, |
||||||
|
router_configs, |
||||||
|
)) |
||||||
|
.with_client(&chain_config.client()) |
||||||
|
.send_with_payer(); |
||||||
|
} else { |
||||||
|
println!( |
||||||
|
"No router changes for chain: {}, program_id {}", |
||||||
|
chain_name, program_id |
||||||
|
); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Writes router program IDs as hex and base58.
|
||||||
|
fn write_router_program_ids(deploy_dir: &Path, routers: &HashMap<String, H256>) { |
||||||
|
let serialized_program_ids = routers |
||||||
|
.iter() |
||||||
|
.map(|(chain_name, router)| (chain_name.clone(), (*router).into())) |
||||||
|
.collect::<HashMap<String, HexAndBase58ProgramIdArtifact>>(); |
||||||
|
|
||||||
|
let program_ids_file = deploy_dir.join("program-ids.json"); |
||||||
|
write_json(&program_ids_file, serialized_program_ids); |
||||||
|
} |
||||||
|
|
||||||
|
fn read_router_program_ids(deploy_dir: &Path) -> Option<HashMap<String, Pubkey>> { |
||||||
|
let program_ids_file = deploy_dir.join("program-ids.json"); |
||||||
|
|
||||||
|
if !program_ids_file.exists() { |
||||||
|
return None; |
||||||
|
} |
||||||
|
|
||||||
|
let serialized_program_ids: HashMap<String, HexAndBase58ProgramIdArtifact> = |
||||||
|
serde_json::from_reader(File::open(program_ids_file).unwrap()).unwrap(); |
||||||
|
|
||||||
|
let existing_program_ids = serialized_program_ids |
||||||
|
.iter() |
||||||
|
.map(|(chain_name, program_id)| (chain_name.clone(), program_id.into())) |
||||||
|
.collect::<HashMap<String, Pubkey>>(); |
||||||
|
|
||||||
|
Some(existing_program_ids) |
||||||
|
} |
@ -0,0 +1,68 @@ |
|||||||
|
/// For serializing and deserializing Pubkey
|
||||||
|
pub(crate) mod serde_pubkey { |
||||||
|
use borsh::BorshDeserialize; |
||||||
|
use serde::{Deserialize, Deserializer, Serializer}; |
||||||
|
use solana_sdk::pubkey::Pubkey; |
||||||
|
use std::str::FromStr; |
||||||
|
|
||||||
|
#[derive(Deserialize)] |
||||||
|
#[serde(untagged)] |
||||||
|
enum RawPubkey { |
||||||
|
String(String), |
||||||
|
Bytes(Vec<u8>), |
||||||
|
} |
||||||
|
|
||||||
|
pub fn serialize<S: Serializer>(k: &Pubkey, ser: S) -> Result<S::Ok, S::Error> { |
||||||
|
ser.serialize_str(&k.to_string()) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn deserialize<'de, D: Deserializer<'de>>(de: D) -> Result<Pubkey, D::Error> { |
||||||
|
match RawPubkey::deserialize(de)? { |
||||||
|
RawPubkey::String(s) => Pubkey::from_str(&s).map_err(serde::de::Error::custom), |
||||||
|
RawPubkey::Bytes(b) => Pubkey::try_from_slice(&b).map_err(serde::de::Error::custom), |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// For serializing and deserializing Option<Pubkey>
|
||||||
|
pub(crate) mod serde_option_pubkey { |
||||||
|
use borsh::BorshDeserialize; |
||||||
|
use serde::{Deserialize, Deserializer, Serializer}; |
||||||
|
use solana_sdk::pubkey::Pubkey; |
||||||
|
use std::str::FromStr; |
||||||
|
|
||||||
|
#[derive(Deserialize)] |
||||||
|
#[serde(untagged)] |
||||||
|
enum RawPubkey { |
||||||
|
String(String), |
||||||
|
Bytes(Vec<u8>), |
||||||
|
} |
||||||
|
|
||||||
|
pub fn serialize<S: Serializer>(k: &Option<Pubkey>, ser: S) -> Result<S::Ok, S::Error> { |
||||||
|
ser.serialize_str(&k.map(|k| k.to_string()).unwrap_or_default()) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn deserialize<'de, D: Deserializer<'de>>(de: D) -> Result<Option<Pubkey>, D::Error> { |
||||||
|
match Option::<RawPubkey>::deserialize(de)? { |
||||||
|
Some(RawPubkey::String(s)) => { |
||||||
|
if s.is_empty() { |
||||||
|
Ok(None) |
||||||
|
} else { |
||||||
|
Pubkey::from_str(&s) |
||||||
|
.map_err(serde::de::Error::custom) |
||||||
|
.map(Some) |
||||||
|
} |
||||||
|
} |
||||||
|
Some(RawPubkey::Bytes(b)) => { |
||||||
|
if b.is_empty() { |
||||||
|
Ok(None) |
||||||
|
} else { |
||||||
|
Pubkey::try_from_slice(&b) |
||||||
|
.map_err(serde::de::Error::custom) |
||||||
|
.map(Some) |
||||||
|
} |
||||||
|
} |
||||||
|
None => Ok(None), |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -1 +0,0 @@ |
|||||||
[113,244,152,170,85,122,42,51,10,74,244,18,91,8,135,77,156,19,172,122,139,50,248,3,186,184,186,140,110,165,78,161,76,88,146,213,185,127,121,92,132,2,249,73,19,192,73,170,105,85,247,241,48,175,67,28,165,29,224,252,173,165,38,140] |
|
@ -1 +0,0 @@ |
|||||||
[135,153,145,193,50,88,169,205,206,171,48,1,17,242,3,43,225,72,101,163,93,126,105,165,159,44,243,196,182,240,4,87,22,253,47,198,217,75,23,60,181,129,251,103,140,170,111,35,152,97,16,23,64,17,198,239,79,225,120,141,55,38,60,86] |
|
@ -1 +0,0 @@ |
|||||||
[252,76,67,201,250,68,86,32,216,136,163,46,192,20,249,175,209,94,101,235,24,240,204,4,246,159,180,138,253,20,48,146,182,104,250,124,231,168,239,248,95,199,219,250,126,156,57,113,83,209,232,171,10,90,153,238,72,138,186,34,77,87,172,211] |
|
@ -1,5 +0,0 @@ |
|||||||
{ |
|
||||||
"mailbox": "692KZJaoe2KRcD6uhCQDLLXnLNA5ZLnfvdqjE4aX9iu1", |
|
||||||
"validator_announce": "DH43ae1LwemXAboWwSh8zc9pG8j72gKUEXNi57w8fEnn", |
|
||||||
"multisig_ism_message_id": "2YjtZDiUoptoSsA5eVrDCcX6wxNK6YoEVW7y82x5Z2fw" |
|
||||||
} |
|
@ -1 +0,0 @@ |
|||||||
[6,132,236,247,134,194,48,96,56,63,48,146,121,215,228,1,80,199,79,128,232,145,31,24,170,246,162,253,52,12,244,198,141,84,17,12,114,138,14,65,37,185,65,155,156,209,188,73,159,63,157,69,158,103,155,16,217,78,19,53,6,226,115,117] |
|
@ -1 +0,0 @@ |
|||||||
[75,122,156,10,143,146,130,96,41,203,245,228,178,140,170,105,167,226,18,171,187,4,70,210,1,234,232,194,206,26,65,248,243,199,245,54,127,196,31,152,114,133,16,172,1,103,105,249,111,240,129,216,26,184,14,131,242,197,189,46,163,142,2,120] |
|
@ -1 +0,0 @@ |
|||||||
[60,166,246,212,217,15,197,101,188,59,172,187,217,44,158,58,65,180,5,179,193,73,206,199,134,54,56,70,26,169,141,82,49,9,182,63,146,255,211,243,158,55,120,3,60,23,151,134,195,85,195,50,62,205,7,162,107,106,40,106,220,117,82,91] |
|
@ -1,5 +0,0 @@ |
|||||||
{ |
|
||||||
"mailbox": "AWgqPcY1vjHRoFLHNgs15fdvy4bqEakHmYXW78B8GgYk", |
|
||||||
"validator_announce": "4JRZrYJnXJn6KPSCG4tA6GBomP2zwQv8bD65anWnHmNz", |
|
||||||
"multisig_ism_message_id": "HQcv2ibNRuJdHU8Lt9t655YUjXj4Rp9nW8mbcA26cYqM" |
|
||||||
} |
|
@ -1,29 +0,0 @@ |
|||||||
{ |
|
||||||
"solanadevnet": { |
|
||||||
"chainId": 13375, |
|
||||||
"name": "solanadevnet", |
|
||||||
"publicRpcUrls": [ |
|
||||||
{ |
|
||||||
"http": "https://api.devnet.solana.com" |
|
||||||
} |
|
||||||
] |
|
||||||
}, |
|
||||||
"solanadevnet1": { |
|
||||||
"chainId": 13376, |
|
||||||
"name": "solanadevnet1", |
|
||||||
"publicRpcUrls": [ |
|
||||||
{ |
|
||||||
"http": "https://api.devnet.solana.com" |
|
||||||
} |
|
||||||
] |
|
||||||
}, |
|
||||||
"fuji": { |
|
||||||
"chainId": 43113, |
|
||||||
"name": "fuji", |
|
||||||
"publicRpcUrls": [ |
|
||||||
{ |
|
||||||
"http": "https://api.avax-test.network/ext/bc/C/rpc" |
|
||||||
} |
|
||||||
] |
|
||||||
} |
|
||||||
} |
|
@ -1 +0,0 @@ |
|||||||
[234,24,62,69,201,85,23,105,162,73,39,96,54,24,252,131,65,61,204,71,240,230,98,153,79,12,102,57,135,254,59,159,71,62,216,28,221,183,176,75,40,167,248,151,145,3,242,74,196,153,147,167,98,202,124,87,70,27,115,81,78,50,199,68] |
|
@ -1 +0,0 @@ |
|||||||
[39,54,74,37,67,213,195,70,204,38,146,230,111,25,95,162,197,128,223,145,57,112,78,217,51,236,68,252,254,70,26,37,135,224,112,242,167,101,9,162,147,37,98,70,138,147,6,126,136,247,145,107,228,139,68,251,82,120,107,18,4,102,190,221] |
|
@ -1,14 +0,0 @@ |
|||||||
{ |
|
||||||
"solanadevnet1": { |
|
||||||
"hex": "0x473ed81cddb7b04b28a7f8979103f24ac49993a762ca7c57461b73514e32c744", |
|
||||||
"base58": "5o7XXLy8N67cgCjSt4zKNnzAbDRpkVruu8BbpPNehBrK" |
|
||||||
}, |
|
||||||
"fuji": { |
|
||||||
"hex": "0x000000000000000000000000b3af04fc8b461138eca4f5fc1d5955bbe6d20fca", |
|
||||||
"base58": "1111111111113WC5zqqJzmcsiZZcai6ZxbvW84do" |
|
||||||
}, |
|
||||||
"solanadevnet": { |
|
||||||
"hex": "0x87e070f2a76509a2932562468a93067e88f7916be48b44fb52786b120466bedd", |
|
||||||
"base58": "A9QY6ZQ3t1T3Pk58gTx1vsSeH2B2AywwK2V7SpH2w2cC" |
|
||||||
} |
|
||||||
} |
|
@ -1,23 +0,0 @@ |
|||||||
{ |
|
||||||
"solanadevnet": { |
|
||||||
"type": "collateral", |
|
||||||
"token": "Gh9ZwEmdLJ8DscKNTkTqPbNwLNNBjuSzaG9Vp2KGtKJr", |
|
||||||
"splTokenProgram": "token", |
|
||||||
"decimals": 6, |
|
||||||
"name": "USD Coin Dev", |
|
||||||
"symbol": "USDC" |
|
||||||
}, |
|
||||||
"solanadevnet1": { |
|
||||||
"type": "synthetic", |
|
||||||
"decimals": 6, |
|
||||||
"name": "USD Coin Dev", |
|
||||||
"symbol": "USDC" |
|
||||||
}, |
|
||||||
"fuji": { |
|
||||||
"type": "synthetic", |
|
||||||
"decimals": 6, |
|
||||||
"name": "USD Coin Dev", |
|
||||||
"symbol": "USDC", |
|
||||||
"foreignDeployment": "0xb3AF04Fc8b461138eCA4F5fC1D5955Bbe6D20Fca" |
|
||||||
} |
|
||||||
} |
|
@ -1 +0,0 @@ |
|||||||
[108,3,96,252,94,52,97,146,193,61,252,4,209,156,21,178,42,234,170,70,97,252,167,156,146,209,57,48,52,224,211,72,40,108,141,225,165,106,19,22,48,134,115,13,111,173,228,116,229,5,197,167,246,245,139,19,60,75,183,152,49,124,190,33] |
|
@ -1 +0,0 @@ |
|||||||
[169,25,77,166,171,9,74,84,180,104,209,80,36,170,223,85,56,255,50,104,185,250,53,188,65,168,235,7,176,81,99,182,113,69,170,191,248,224,191,67,181,13,107,166,133,126,157,101,165,157,24,202,25,96,195,132,107,100,86,78,48,232,7,142] |
|
@ -1,14 +0,0 @@ |
|||||||
{ |
|
||||||
"solanadevnet": { |
|
||||||
"hex": "0x7145aabff8e0bf43b50d6ba6857e9d65a59d18ca1960c3846b64564e30e8078e", |
|
||||||
"base58": "8dAgevgBAnhvxoB5mWNUfmXi6H8WLC3ZaP8poaRHkzaR" |
|
||||||
}, |
|
||||||
"solanadevnet1": { |
|
||||||
"hex": "0x286c8de1a56a13163086730d6fade474e505c5a7f6f58b133c4bb798317cbe21", |
|
||||||
"base58": "3ioKCgR4pyrtkJvsB3zketopnR3mqjjBszSgtiQXQz7i" |
|
||||||
}, |
|
||||||
"fuji": { |
|
||||||
"hex": "0x00000000000000000000000011cf63c916263d6bbd710f43816ee6703e1c5da3", |
|
||||||
"base58": "111111111111FPh8wLMbV6vLtqUcvxKR496PAXL" |
|
||||||
} |
|
||||||
} |
|
@ -1,19 +0,0 @@ |
|||||||
{ |
|
||||||
"solanadevnet": { |
|
||||||
"type": "native", |
|
||||||
"decimals": 9 |
|
||||||
}, |
|
||||||
"solanadevnet1": { |
|
||||||
"type": "synthetic", |
|
||||||
"decimals": 9, |
|
||||||
"name": "Solana (solanadevnet)", |
|
||||||
"symbol": "SOL" |
|
||||||
}, |
|
||||||
"fuji": { |
|
||||||
"type": "synthetic", |
|
||||||
"decimals": 9, |
|
||||||
"name": "Solana (solanadevnet)", |
|
||||||
"symbol": "SOL", |
|
||||||
"foreignDeployment": "0x11CF63c916263d6BBD710F43816ee6703e1C5da3" |
|
||||||
} |
|
||||||
} |
|
@ -0,0 +1,350 @@ |
|||||||
|
{ |
||||||
|
"bsc": { |
||||||
|
"chainId": 56, |
||||||
|
"domainId": 56, |
||||||
|
"name": "bsc", |
||||||
|
"protocol": "ethereum", |
||||||
|
"displayName": "Binance Smart Chain", |
||||||
|
"displayNameShort": "Binance", |
||||||
|
"nativeToken": { |
||||||
|
"decimals": 18, |
||||||
|
"name": "BNB", |
||||||
|
"symbol": "BNB" |
||||||
|
}, |
||||||
|
"rpcUrls": [ |
||||||
|
{ |
||||||
|
"http": "https://bsc-dataseed.binance.org" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"http": "https://rpc.ankr.com/bsc" |
||||||
|
} |
||||||
|
], |
||||||
|
"blockExplorers": [ |
||||||
|
{ |
||||||
|
"name": "BscScan", |
||||||
|
"url": "https://bscscan.com", |
||||||
|
"apiUrl": "https://api.bscscan.com/api", |
||||||
|
"family": "etherscan" |
||||||
|
} |
||||||
|
], |
||||||
|
"blocks": { |
||||||
|
"confirmations": 1, |
||||||
|
"reorgPeriod": 15, |
||||||
|
"estimateBlockTime": 3 |
||||||
|
}, |
||||||
|
"gasCurrencyCoinGeckoId": "binancecoin", |
||||||
|
"gnosisSafeTransactionServiceUrl": "https://safe-transaction-bsc.safe.global/", |
||||||
|
"transactionOverrides": { |
||||||
|
"gasPrice": 7000000000 |
||||||
|
} |
||||||
|
}, |
||||||
|
"avalanche": { |
||||||
|
"chainId": 43114, |
||||||
|
"domainId": 43114, |
||||||
|
"name": "avalanche", |
||||||
|
"protocol": "ethereum", |
||||||
|
"displayName": "Avalanche", |
||||||
|
"nativeToken": { |
||||||
|
"decimals": 18, |
||||||
|
"name": "Avalanche", |
||||||
|
"symbol": "AVAX" |
||||||
|
}, |
||||||
|
"rpcUrls": [ |
||||||
|
{ |
||||||
|
"http": "https://api.avax.network/ext/bc/C/rpc", |
||||||
|
"pagination": { |
||||||
|
"maxBlockRange": 100000, |
||||||
|
"minBlockNumber": 6765067 |
||||||
|
} |
||||||
|
} |
||||||
|
], |
||||||
|
"blockExplorers": [ |
||||||
|
{ |
||||||
|
"name": "SnowTrace", |
||||||
|
"url": "https://snowtrace.io", |
||||||
|
"apiUrl": "https://api.snowtrace.io/api", |
||||||
|
"family": "other" |
||||||
|
} |
||||||
|
], |
||||||
|
"blocks": { |
||||||
|
"confirmations": 3, |
||||||
|
"reorgPeriod": 3, |
||||||
|
"estimateBlockTime": 2 |
||||||
|
}, |
||||||
|
"gasCurrencyCoinGeckoId": "avalanche-2", |
||||||
|
"gnosisSafeTransactionServiceUrl": "https://safe-transaction-avalanche.safe.global/" |
||||||
|
}, |
||||||
|
"polygon": { |
||||||
|
"chainId": 137, |
||||||
|
"domainId": 137, |
||||||
|
"name": "polygon", |
||||||
|
"protocol": "ethereum", |
||||||
|
"displayName": "Polygon", |
||||||
|
"nativeToken": { |
||||||
|
"name": "Ether", |
||||||
|
"symbol": "ETH", |
||||||
|
"decimals": 18 |
||||||
|
}, |
||||||
|
"rpcUrls": [ |
||||||
|
{ |
||||||
|
"http": "https://rpc-mainnet.matic.quiknode.pro", |
||||||
|
"pagination": { |
||||||
|
"maxBlockRange": 10000, |
||||||
|
"minBlockNumber": 19657100 |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"http": "https://polygon-rpc.com" |
||||||
|
} |
||||||
|
], |
||||||
|
"blockExplorers": [ |
||||||
|
{ |
||||||
|
"name": "PolygonScan", |
||||||
|
"url": "https://polygonscan.com", |
||||||
|
"apiUrl": "https://api.polygonscan.com/api", |
||||||
|
"family": "etherscan" |
||||||
|
} |
||||||
|
], |
||||||
|
"blocks": { |
||||||
|
"confirmations": 3, |
||||||
|
"reorgPeriod": 256, |
||||||
|
"estimateBlockTime": 2 |
||||||
|
}, |
||||||
|
"gasCurrencyCoinGeckoId": "matic-network", |
||||||
|
"gnosisSafeTransactionServiceUrl": "https://safe-transaction-polygon.safe.global/", |
||||||
|
"transactionOverrides": { |
||||||
|
"maxFeePerGas": 500000000000, |
||||||
|
"maxPriorityFeePerGas": 100000000000 |
||||||
|
} |
||||||
|
}, |
||||||
|
"celo": { |
||||||
|
"chainId": 42220, |
||||||
|
"domainId": 42220, |
||||||
|
"name": "celo", |
||||||
|
"protocol": "ethereum", |
||||||
|
"displayName": "Celo", |
||||||
|
"nativeToken": { |
||||||
|
"decimals": 18, |
||||||
|
"name": "CELO", |
||||||
|
"symbol": "CELO" |
||||||
|
}, |
||||||
|
"rpcUrls": [ |
||||||
|
{ |
||||||
|
"http": "https://forno.celo.org" |
||||||
|
} |
||||||
|
], |
||||||
|
"blockExplorers": [ |
||||||
|
{ |
||||||
|
"name": "CeloScan", |
||||||
|
"url": "https://celoscan.io", |
||||||
|
"apiUrl": "https://api.celoscan.io/api", |
||||||
|
"family": "etherscan" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "Blockscout", |
||||||
|
"url": "https://explorer.celo.org", |
||||||
|
"apiUrl": "https://explorer.celo.org/mainnet/api", |
||||||
|
"family": "blockscout" |
||||||
|
} |
||||||
|
], |
||||||
|
"blocks": { |
||||||
|
"confirmations": 1, |
||||||
|
"reorgPeriod": 0, |
||||||
|
"estimateBlockTime": 5 |
||||||
|
}, |
||||||
|
"gnosisSafeTransactionServiceUrl": "https://mainnet-tx-svc.celo-safe-prod.celo-networks-dev.org/" |
||||||
|
}, |
||||||
|
"arbitrum": { |
||||||
|
"chainId": 42161, |
||||||
|
"domainId": 42161, |
||||||
|
"name": "arbitrum", |
||||||
|
"protocol": "ethereum", |
||||||
|
"displayName": "Arbitrum", |
||||||
|
"nativeToken": { |
||||||
|
"name": "Ether", |
||||||
|
"symbol": "ETH", |
||||||
|
"decimals": 18 |
||||||
|
}, |
||||||
|
"rpcUrls": [ |
||||||
|
{ |
||||||
|
"http": "https://arb1.arbitrum.io/rpc" |
||||||
|
} |
||||||
|
], |
||||||
|
"blockExplorers": [ |
||||||
|
{ |
||||||
|
"name": "Arbiscan", |
||||||
|
"url": "https://arbiscan.io", |
||||||
|
"apiUrl": "https://api.arbiscan.io/api", |
||||||
|
"family": "etherscan" |
||||||
|
} |
||||||
|
], |
||||||
|
"blocks": { |
||||||
|
"confirmations": 1, |
||||||
|
"reorgPeriod": 0, |
||||||
|
"estimateBlockTime": 3 |
||||||
|
}, |
||||||
|
"gasCurrencyCoinGeckoId": "ethereum", |
||||||
|
"gnosisSafeTransactionServiceUrl": "https://safe-transaction-arbitrum.safe.global/" |
||||||
|
}, |
||||||
|
"optimism": { |
||||||
|
"chainId": 10, |
||||||
|
"domainId": 10, |
||||||
|
"name": "optimism", |
||||||
|
"protocol": "ethereum", |
||||||
|
"displayName": "Optimism", |
||||||
|
"nativeToken": { |
||||||
|
"name": "Ether", |
||||||
|
"symbol": "ETH", |
||||||
|
"decimals": 18 |
||||||
|
}, |
||||||
|
"rpcUrls": [ |
||||||
|
{ |
||||||
|
"http": "https://mainnet.optimism.io" |
||||||
|
} |
||||||
|
], |
||||||
|
"blockExplorers": [ |
||||||
|
{ |
||||||
|
"name": "Etherscan", |
||||||
|
"url": "https://optimistic.etherscan.io", |
||||||
|
"apiUrl": "https://api-optimistic.etherscan.io/api", |
||||||
|
"family": "etherscan" |
||||||
|
} |
||||||
|
], |
||||||
|
"blocks": { |
||||||
|
"confirmations": 1, |
||||||
|
"reorgPeriod": 0, |
||||||
|
"estimateBlockTime": 3 |
||||||
|
}, |
||||||
|
"gasCurrencyCoinGeckoId": "ethereum", |
||||||
|
"gnosisSafeTransactionServiceUrl": "https://safe-transaction-optimism.safe.global/" |
||||||
|
}, |
||||||
|
"ethereum": { |
||||||
|
"chainId": 1, |
||||||
|
"domainId": 1, |
||||||
|
"name": "ethereum", |
||||||
|
"protocol": "ethereum", |
||||||
|
"displayName": "Ethereum", |
||||||
|
"nativeToken": { |
||||||
|
"name": "Ether", |
||||||
|
"symbol": "ETH", |
||||||
|
"decimals": 18 |
||||||
|
}, |
||||||
|
"rpcUrls": [ |
||||||
|
{ |
||||||
|
"http": "https://mainnet.infura.io/v3/9aa3d95b3bc440fa88ea12eaa4456161" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"http": "https://cloudflare-eth.com" |
||||||
|
} |
||||||
|
], |
||||||
|
"blockExplorers": [ |
||||||
|
{ |
||||||
|
"name": "Etherscan", |
||||||
|
"url": "https://etherscan.io", |
||||||
|
"apiUrl": "https://api.etherscan.io/api", |
||||||
|
"family": "etherscan" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "Blockscout", |
||||||
|
"url": "https://blockscout.com/eth/mainnet", |
||||||
|
"apiUrl": "https://blockscout.com/eth/mainnet/api", |
||||||
|
"family": "blockscout" |
||||||
|
} |
||||||
|
], |
||||||
|
"blocks": { |
||||||
|
"confirmations": 3, |
||||||
|
"reorgPeriod": 14, |
||||||
|
"estimateBlockTime": 13 |
||||||
|
}, |
||||||
|
"gnosisSafeTransactionServiceUrl": "https://safe-transaction-mainnet.safe.global/", |
||||||
|
"transactionOverrides": { |
||||||
|
"maxFeePerGas": 150000000000, |
||||||
|
"maxPriorityFeePerGas": 5000000000 |
||||||
|
} |
||||||
|
}, |
||||||
|
"moonbeam": { |
||||||
|
"chainId": 1284, |
||||||
|
"domainId": 1284, |
||||||
|
"name": "moonbeam", |
||||||
|
"protocol": "ethereum", |
||||||
|
"displayName": "Moonbeam", |
||||||
|
"nativeToken": { |
||||||
|
"decimals": 18, |
||||||
|
"name": "GLMR", |
||||||
|
"symbol": "GLMR" |
||||||
|
}, |
||||||
|
"rpcUrls": [ |
||||||
|
{ |
||||||
|
"http": "https://rpc.api.moonbeam.network" |
||||||
|
} |
||||||
|
], |
||||||
|
"blockExplorers": [ |
||||||
|
{ |
||||||
|
"name": "MoonScan", |
||||||
|
"url": "https://moonscan.io", |
||||||
|
"apiUrl": "https://api-moonbeam.moonscan.io/api", |
||||||
|
"family": "etherscan" |
||||||
|
} |
||||||
|
], |
||||||
|
"blocks": { |
||||||
|
"confirmations": 2, |
||||||
|
"reorgPeriod": 2, |
||||||
|
"estimateBlockTime": 12 |
||||||
|
}, |
||||||
|
"gnosisSafeTransactionServiceUrl": "https://transaction.multisig.moonbeam.network" |
||||||
|
}, |
||||||
|
"gnosis": { |
||||||
|
"chainId": 100, |
||||||
|
"domainId": 100, |
||||||
|
"name": "gnosis", |
||||||
|
"protocol": "ethereum", |
||||||
|
"displayName": "Gnosis", |
||||||
|
"nativeToken": { |
||||||
|
"name": "xDai", |
||||||
|
"symbol": "xDai", |
||||||
|
"decimals": 18 |
||||||
|
}, |
||||||
|
"rpcUrls": [ |
||||||
|
{ |
||||||
|
"http": "https://rpc.gnosischain.com", |
||||||
|
"pagination": { |
||||||
|
"maxBlockRange": 10000, |
||||||
|
"minBlockNumber": 25997478 |
||||||
|
} |
||||||
|
} |
||||||
|
], |
||||||
|
"blockExplorers": [ |
||||||
|
{ |
||||||
|
"name": "GnosisScan", |
||||||
|
"url": "https://gnosisscan.io", |
||||||
|
"apiUrl": "https://api.gnosisscan.io/api", |
||||||
|
"family": "etherscan" |
||||||
|
} |
||||||
|
], |
||||||
|
"blocks": { |
||||||
|
"confirmations": 1, |
||||||
|
"reorgPeriod": 14, |
||||||
|
"estimateBlockTime": 5 |
||||||
|
}, |
||||||
|
"gasCurrencyCoinGeckoId": "xdai", |
||||||
|
"gnosisSafeTransactionServiceUrl": "https://safe-transaction-gnosis-chain.safe.global/" |
||||||
|
}, |
||||||
|
"solana": { |
||||||
|
"chainId": 1399811149, |
||||||
|
"name": "solana", |
||||||
|
"rpcUrls": [ |
||||||
|
{ |
||||||
|
"http": "https://api.mainnet-beta.solana.com" |
||||||
|
} |
||||||
|
] |
||||||
|
}, |
||||||
|
"nautilus": { |
||||||
|
"chainId": 22222, |
||||||
|
"name": "nautilus", |
||||||
|
"rpcUrls": [ |
||||||
|
{ |
||||||
|
"http": "https://api.nautilus.nautchain.xyz" |
||||||
|
} |
||||||
|
] |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,30 @@ |
|||||||
|
{ |
||||||
|
"solana": {}, |
||||||
|
"bsc": { |
||||||
|
"foreignDeployment": "0xB97d3bF2fC296c2cAC4056bBC8A783ff39408e20" |
||||||
|
}, |
||||||
|
"avalanche": { |
||||||
|
"foreignDeployment": "0x2A925CD8a5d919c5c6599633090c37fe38A561b6" |
||||||
|
}, |
||||||
|
"polygon": { |
||||||
|
"foreignDeployment": "0x6c0aC8cEA75232aa7BeD8cbe9C4f820E7a77a9C3" |
||||||
|
}, |
||||||
|
"celo": { |
||||||
|
"foreignDeployment": "0x4151773Db70C0b2D4c43Ea44A5FB5803ff1d3e0B" |
||||||
|
}, |
||||||
|
"arbitrum": { |
||||||
|
"foreignDeployment": "0x96271cA0ab9eeFB3Ca481749c0Ca4c705fD4F523" |
||||||
|
}, |
||||||
|
"optimism": { |
||||||
|
"foreignDeployment": "0xA6f0A37DFDe9C2c8F46F010989C47d9edB3a9FA8" |
||||||
|
}, |
||||||
|
"ethereum": { |
||||||
|
"foreignDeployment": "0x9311cEE522A7C122B843b66cC31C6a63e2F92641" |
||||||
|
}, |
||||||
|
"moonbeam": { |
||||||
|
"foreignDeployment": "0xAe067C08703508230357025B38c35Cd12793628c" |
||||||
|
}, |
||||||
|
"gnosis": { |
||||||
|
"foreignDeployment": "0x26f32245fCF5Ad53159E875d5Cae62aEcf19c2d4" |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,42 @@ |
|||||||
|
{ |
||||||
|
"moonbeam": { |
||||||
|
"hex": "0x000000000000000000000000ae067c08703508230357025b38c35cd12793628c", |
||||||
|
"base58": "1111111111113RcuHPfDctyAnFWHvj8tS1q8UHPh" |
||||||
|
}, |
||||||
|
"bsc": { |
||||||
|
"hex": "0x000000000000000000000000b97d3bf2fc296c2cac4056bbc8a783ff39408e20", |
||||||
|
"base58": "1111111111113atAoP8gQ2GYeue77ETUPAf8w9zw" |
||||||
|
}, |
||||||
|
"optimism": { |
||||||
|
"hex": "0x000000000000000000000000a6f0a37dfde9c2c8f46f010989c47d9edb3a9fa8", |
||||||
|
"base58": "1111111111113KtqevvpYv7NCiadmp6tRRfivB8K" |
||||||
|
}, |
||||||
|
"avalanche": { |
||||||
|
"hex": "0x0000000000000000000000002a925cd8a5d919c5c6599633090c37fe38a561b6", |
||||||
|
"base58": "111111111111bQB6b7XVDHSyvi7XmLrQMT8C3xH" |
||||||
|
}, |
||||||
|
"ethereum": { |
||||||
|
"hex": "0x0000000000000000000000009311cee522a7c122b843b66cc31c6a63e2f92641", |
||||||
|
"base58": "11111111111133qb6DzNiJ7whNaYGud2WqqtjxFS" |
||||||
|
}, |
||||||
|
"solana": { |
||||||
|
"hex": "0x3797d0096b18b5b645c346a66d7f18c6c5738782c6bce24da57a3462bdef82b1", |
||||||
|
"base58": "4k1gruSdH1r57V9QQK4aunzfMYzLFfF83jdYkkEwyem6" |
||||||
|
}, |
||||||
|
"celo": { |
||||||
|
"hex": "0x0000000000000000000000004151773db70c0b2d4c43ea44a5fb5803ff1d3e0b", |
||||||
|
"base58": "111111111111unDVQcjdeHntE83qvf1vsKCZ4av" |
||||||
|
}, |
||||||
|
"polygon": { |
||||||
|
"hex": "0x0000000000000000000000006c0ac8cea75232aa7bed8cbe9c4f820e7a77a9c3", |
||||||
|
"base58": "1111111111112WJXE3PCAsCXYZxU9Kh51sSZEa5G" |
||||||
|
}, |
||||||
|
"arbitrum": { |
||||||
|
"hex": "0x00000000000000000000000096271ca0ab9eefb3ca481749c0ca4c705fd4f523", |
||||||
|
"base58": "11111111111136L61X7cdT9tPZ4GKBtzJtrjFAd8" |
||||||
|
}, |
||||||
|
"gnosis": { |
||||||
|
"hex": "0x00000000000000000000000026f32245fcf5ad53159e875d5cae62aecf19c2d4", |
||||||
|
"base58": "111111111111YURfyMRiiTWy8X6pYHAqmYPmBpf" |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,32 @@ |
|||||||
|
{ |
||||||
|
"solana": { |
||||||
|
"interchainSecurityModule": "BYTsxBuKVbwgsZFswzB91nrxveQySghwXzaKqn8exNnC" |
||||||
|
}, |
||||||
|
"gnosis": { |
||||||
|
"foreignDeployment": "0x99ca8c74cE7Cfa9d72A51fbb05F9821f5f826b3a" |
||||||
|
}, |
||||||
|
"bsc": { |
||||||
|
"foreignDeployment": "0xe5554478F167936dB253f79f57c41770bfa00Bae" |
||||||
|
}, |
||||||
|
"avalanche": { |
||||||
|
"foreignDeployment": "0xe1De9910fe71cC216490AC7FCF019e13a34481D7" |
||||||
|
}, |
||||||
|
"polygon": { |
||||||
|
"foreignDeployment": "0xAb65C41a1BC580a52f0b166879122EFdce0cB868" |
||||||
|
}, |
||||||
|
"celo": { |
||||||
|
"foreignDeployment": "0xfE29f6a4468536029Fc9c97d3a9669b9fe38E114" |
||||||
|
}, |
||||||
|
"arbitrum": { |
||||||
|
"foreignDeployment": "0x414B67F62b143d6db6E9b633168Dd6fd4DA20642" |
||||||
|
}, |
||||||
|
"optimism": { |
||||||
|
"foreignDeployment": "0xB4caf2CA864B413DAA502fA18A8D48cD0740fC52" |
||||||
|
}, |
||||||
|
"ethereum": { |
||||||
|
"foreignDeployment": "0xed31c20c5517EaC05decD5F6dCd01Fe6d16fD09D" |
||||||
|
}, |
||||||
|
"moonbeam": { |
||||||
|
"foreignDeployment": "0x3eB9eE2CFC8DCB6F58B5869D33336CFcBf1dC354" |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,42 @@ |
|||||||
|
{ |
||||||
|
"solana": { |
||||||
|
"hex": "0x29dacc0e7124ea39b1fd43ab0fd30e038cf405c0229890229d0086d0b6516f9c", |
||||||
|
"base58": "3pPDp16iVTJFge2sm85Q61hW61UN5xNqeG24gqFhzLFV" |
||||||
|
}, |
||||||
|
"avalanche": { |
||||||
|
"hex": "0x000000000000000000000000e1de9910fe71cc216490ac7fcf019e13a34481d7", |
||||||
|
"base58": "11111111111149We9K5tM8ijcyNy9zDMG9RyDBCJ" |
||||||
|
}, |
||||||
|
"arbitrum": { |
||||||
|
"hex": "0x000000000000000000000000414b67f62b143d6db6e9b633168dd6fd4da20642", |
||||||
|
"base58": "111111111111um79Yc6Evs5e1m2fdD2x7T1cpXb" |
||||||
|
}, |
||||||
|
"moonbeam": { |
||||||
|
"hex": "0x0000000000000000000000003eb9ee2cfc8dcb6f58b5869d33336cfcbf1dc354", |
||||||
|
"base58": "111111111111sgjzaeuHfqhExkdPQ1gJdhcSr4j" |
||||||
|
}, |
||||||
|
"optimism": { |
||||||
|
"hex": "0x000000000000000000000000b4caf2ca864b413daa502fa18a8d48cd0740fc52", |
||||||
|
"base58": "1111111111113X64nhkfMi9X5MbxKsiDTeeTmjsw" |
||||||
|
}, |
||||||
|
"ethereum": { |
||||||
|
"hex": "0x000000000000000000000000ed31c20c5517eac05decd5f6dcd01fe6d16fd09d", |
||||||
|
"base58": "1111111111114JfPmRiKEsR445qonVzCpsAvXCR2" |
||||||
|
}, |
||||||
|
"gnosis": { |
||||||
|
"hex": "0x00000000000000000000000099ca8c74ce7cfa9d72a51fbb05f9821f5f826b3a", |
||||||
|
"base58": "11111111111139Gc7eyQjpZrmWkkYQRyA2Grcvmf" |
||||||
|
}, |
||||||
|
"bsc": { |
||||||
|
"hex": "0x000000000000000000000000e5554478f167936db253f79f57c41770bfa00bae", |
||||||
|
"base58": "1111111111114CJxuV4VoAh5NsJy9qCGHqryoTCy" |
||||||
|
}, |
||||||
|
"polygon": { |
||||||
|
"hex": "0x000000000000000000000000ab65c41a1bc580a52f0b166879122efdce0cb868", |
||||||
|
"base58": "1111111111113PVkHAU9H7moDSoQvhC3Y2wgmovX" |
||||||
|
}, |
||||||
|
"celo": { |
||||||
|
"hex": "0x000000000000000000000000fe29f6a4468536029fc9c97d3a9669b9fe38e114", |
||||||
|
"base58": "1111111111114YNh3uhCWh2NjyPttobeNRyuDHYo" |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,106 @@ |
|||||||
|
{ |
||||||
|
"celo": { |
||||||
|
"type": 3, |
||||||
|
"threshold": 4, |
||||||
|
"validators": [ |
||||||
|
"0x1f20274b1210046769d48174c2f0e7c25ca7d5c5", |
||||||
|
"0x3bc014bafa43f93d534aed34f750997cdffcf007", |
||||||
|
"0xd79d506d741fa735938f7b7847a926e34a6fe6b0", |
||||||
|
"0xe4a258bc61e65914c2a477b2a8a433ab4ebdf44b", |
||||||
|
"0x6aea63b0be4679c1385c26a92a3ff8aa6a8379f2", |
||||||
|
"0xc0085e1a49bcc69e534272adb82c74c0e007e1ca" |
||||||
|
] |
||||||
|
}, |
||||||
|
"ethereum": { |
||||||
|
"type": 3, |
||||||
|
"threshold": 4, |
||||||
|
"validators": [ |
||||||
|
"0x4c327ccb881a7542be77500b2833dc84c839e7b7", |
||||||
|
"0x84cb373148ef9112b277e68acf676fefa9a9a9a0", |
||||||
|
"0x0d860c2b28bec3af4fd3a5997283e460ff6f2789", |
||||||
|
"0xd4c1211f0eefb97a846c4e6d6589832e52fc03db", |
||||||
|
"0x600c90404d5c9df885404d2cc5350c9b314ea3a2", |
||||||
|
"0x892DC66F5B2f8C438E03f6323394e34A9C24F2D6" |
||||||
|
] |
||||||
|
}, |
||||||
|
"avalanche": { |
||||||
|
"type": 3, |
||||||
|
"threshold": 4, |
||||||
|
"validators": [ |
||||||
|
"0xa7aa52623fe3d78c343008c95894be669e218b8d", |
||||||
|
"0xb6004433fb04f643e2d48ae765c0e7f890f0bc0c", |
||||||
|
"0xa07e213e0985b21a6128e6c22ab5fb73948b0cc2", |
||||||
|
"0x73853ed9a5f6f2e4c521970a94d43469e3cdaea6", |
||||||
|
"0xbd2e136cda02ba627ca882e49b184cbe976081c8", |
||||||
|
"0x1418126f944a44dad9edbab32294a8c890e7a9e3" |
||||||
|
] |
||||||
|
}, |
||||||
|
"polygon": { |
||||||
|
"type": 3, |
||||||
|
"threshold": 4, |
||||||
|
"validators": [ |
||||||
|
"0x59a001c3451e7f9f3b4759ea215382c1e9aa5fc1", |
||||||
|
"0x009fb042d28944017177920c1d40da02bfebf474", |
||||||
|
"0xba4b13e23705a5919c1901150d9697e8ffb3ea71", |
||||||
|
"0x2faa4071b718972f9b4beec1d8cbaa4eb6cca6c6", |
||||||
|
"0x5ae9b0f833dfe09ef455562a1f603f1634504dd6", |
||||||
|
"0x6a163d312f7352a95c9b81dca15078d5bf77a442" |
||||||
|
] |
||||||
|
}, |
||||||
|
"bsc": { |
||||||
|
"type": 3, |
||||||
|
"threshold": 4, |
||||||
|
"validators": [ |
||||||
|
"0xcc84b1eb711e5076b2755cf4ad1d2b42c458a45e", |
||||||
|
"0xefe34eae2bca1846b895d2d0762ec21796aa196a", |
||||||
|
"0x662674e80e189b0861d6835c287693f50ee0c2ff", |
||||||
|
"0x8a0f59075af466841808c529624807656309c9da", |
||||||
|
"0xdd2ff046ccd748a456b4757a73d47f165469669f", |
||||||
|
"0x034c4924c30ec4aa1b7f3ad58548988f0971e1bf" |
||||||
|
] |
||||||
|
}, |
||||||
|
"arbitrum": { |
||||||
|
"type": 3, |
||||||
|
"threshold": 4, |
||||||
|
"validators": [ |
||||||
|
"0xbcb815f38d481a5eba4d7ac4c9e74d9d0fc2a7e7", |
||||||
|
"0xd839424e2e5ace0a81152298dc2b1e3bb3c7fb20", |
||||||
|
"0xb8085c954b75b7088bcce69e61d12fcef797cd8d", |
||||||
|
"0x9856dcb10fd6e5407fa74b5ab1d3b96cc193e9b7", |
||||||
|
"0x505dff4e0827aa5065f5e001db888e0569d46490", |
||||||
|
"0x25c6779d4610f940bf2488732e10bcffb9d36f81" |
||||||
|
] |
||||||
|
}, |
||||||
|
"optimism": { |
||||||
|
"type": 3, |
||||||
|
"threshold": 4, |
||||||
|
"validators": [ |
||||||
|
"0x9f2296d5cfc6b5176adc7716c7596898ded13d35", |
||||||
|
"0x9c10bbe8efa03a8f49dfdb5c549258e3a8dca097", |
||||||
|
"0x62144d4a52a0a0335ea5bb84392ef9912461d9dd", |
||||||
|
"0xaff4718d5d637466ad07441ee3b7c4af8e328dbd", |
||||||
|
"0xc64d1efeab8ae222bc889fe669f75d21b23005d9", |
||||||
|
"0xfa174eb2b4921bb652bc1ada3e8b00e7e280bf3c" |
||||||
|
] |
||||||
|
}, |
||||||
|
"moonbeam": { |
||||||
|
"type": 3, |
||||||
|
"threshold": 3, |
||||||
|
"validators": [ |
||||||
|
"0x237243d32d10e3bdbbf8dbcccc98ad44c1c172ea", |
||||||
|
"0x9509c8cf0a06955f27342262af501b74874e98fb", |
||||||
|
"0xb7113c999e4d587b162dd1a28c73f3f51c6bdcdc", |
||||||
|
"0x26725501597d47352a23cd26f122709f69ad53bc" |
||||||
|
] |
||||||
|
}, |
||||||
|
"gnosis": { |
||||||
|
"type": 3, |
||||||
|
"threshold": 3, |
||||||
|
"validators": [ |
||||||
|
"0xd0529ec8df08d0d63c0f023786bfa81e4bb51fd6", |
||||||
|
"0x8a72ff8571c53c62c7ca02e8c97a443cd5674383", |
||||||
|
"0x4075c2f6bd6d9562067cfe551d49c2bcafa7d692", |
||||||
|
"0xa18580444eaeb1c5957e7b66a6bf84b6519f904d" |
||||||
|
] |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,18 @@ |
|||||||
|
{ |
||||||
|
"bsc": { |
||||||
|
"type": 3, |
||||||
|
"threshold": 1, |
||||||
|
"validators": [ |
||||||
|
"0x0000000000000000000000000000000000000001" |
||||||
|
] |
||||||
|
}, |
||||||
|
"nautilus": { |
||||||
|
"type": 3, |
||||||
|
"threshold": 2, |
||||||
|
"validators": [ |
||||||
|
"0x9c920af9467595a23cb3433adefc3854d498a437", |
||||||
|
"0x87611503e37ce041527c11c24263e8760fccf81f", |
||||||
|
"0x573443248cf9929af0001b88f62131f2de29fe9f" |
||||||
|
] |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,3 @@ |
|||||||
|
{ |
||||||
|
"program_id": "9k74DkJvS2x9QhG4XfnKsLkqaCDyVfaj8s6FyJyhAeEP" |
||||||
|
} |
@ -0,0 +1,65 @@ |
|||||||
|
{ |
||||||
|
"celo": { |
||||||
|
"type": 3, |
||||||
|
"threshold": 1, |
||||||
|
"validators": [ |
||||||
|
"0xe7a82e210f512f8e9900d6bc2acbf7981c63e66e" |
||||||
|
] |
||||||
|
}, |
||||||
|
"ethereum": { |
||||||
|
"type": 3, |
||||||
|
"threshold": 1, |
||||||
|
"validators": [ |
||||||
|
"0xaea1adb1c687b061e5b60b9da84cb69e7b5fab44" |
||||||
|
] |
||||||
|
}, |
||||||
|
"avalanche": { |
||||||
|
"type": 3, |
||||||
|
"threshold": 1, |
||||||
|
"validators": [ |
||||||
|
"0x706976391e23dea28152e0207936bd942aba01ce" |
||||||
|
] |
||||||
|
}, |
||||||
|
"polygon": { |
||||||
|
"type": 3, |
||||||
|
"threshold": 1, |
||||||
|
"validators": [ |
||||||
|
"0xef372f6ff7775989b3ac884506ee31c79638c989" |
||||||
|
] |
||||||
|
}, |
||||||
|
"bsc": { |
||||||
|
"type": 3, |
||||||
|
"threshold": 1, |
||||||
|
"validators": [ |
||||||
|
"0x0823081031a4a6f97c6083775c191d17ca96d0ab" |
||||||
|
] |
||||||
|
}, |
||||||
|
"arbitrum": { |
||||||
|
"type": 3, |
||||||
|
"threshold": 1, |
||||||
|
"validators": [ |
||||||
|
"0x1a95b35fb809d57faf1117c1cc29a6c5df289df1" |
||||||
|
] |
||||||
|
}, |
||||||
|
"optimism": { |
||||||
|
"type": 3, |
||||||
|
"threshold": 1, |
||||||
|
"validators": [ |
||||||
|
"0x60e938bf280bbc21bacfd8bf435459d9003a8f98" |
||||||
|
] |
||||||
|
}, |
||||||
|
"moonbeam": { |
||||||
|
"type": 3, |
||||||
|
"threshold": 1, |
||||||
|
"validators": [ |
||||||
|
"0x0df7140811e309dc69638352545151ebb9d5e0fd" |
||||||
|
] |
||||||
|
}, |
||||||
|
"gnosis": { |
||||||
|
"type": 3, |
||||||
|
"threshold": 1, |
||||||
|
"validators": [ |
||||||
|
"0x15f48e78092a4f79febface509cfd76467c6cdbb" |
||||||
|
] |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,3 @@ |
|||||||
|
{ |
||||||
|
"program_id": "BYTsxBuKVbwgsZFswzB91nrxveQySghwXzaKqn8exNnC" |
||||||
|
} |
@ -1,29 +0,0 @@ |
|||||||
{ |
|
||||||
"solana": { |
|
||||||
"chainId": 1399811149, |
|
||||||
"name": "solana", |
|
||||||
"publicRpcUrls": [ |
|
||||||
{ |
|
||||||
"http": "https://api.mainnet-beta.solana.com" |
|
||||||
} |
|
||||||
] |
|
||||||
}, |
|
||||||
"bsc": { |
|
||||||
"chainId": 56, |
|
||||||
"name": "bsc", |
|
||||||
"publicRpcUrls": [ |
|
||||||
{ |
|
||||||
"http": "https://bsc-dataseed.binance.org" |
|
||||||
} |
|
||||||
] |
|
||||||
}, |
|
||||||
"nautilus": { |
|
||||||
"chainId": 22222, |
|
||||||
"name": "nautilus", |
|
||||||
"publicRpcUrls": [ |
|
||||||
{ |
|
||||||
"http": "https://api.nautilus.nautchain.xyz" |
|
||||||
} |
|
||||||
] |
|
||||||
} |
|
||||||
} |
|
@ -0,0 +1,335 @@ |
|||||||
|
{ |
||||||
|
"alfajores": { |
||||||
|
"chainId": 44787, |
||||||
|
"domainId": 44787, |
||||||
|
"name": "alfajores", |
||||||
|
"protocol": "ethereum", |
||||||
|
"displayName": "Alfajores", |
||||||
|
"nativeToken": { |
||||||
|
"decimals": 18, |
||||||
|
"name": "CELO", |
||||||
|
"symbol": "CELO" |
||||||
|
}, |
||||||
|
"rpcUrls": [ |
||||||
|
{ |
||||||
|
"http": "https://alfajores-forno.celo-testnet.org" |
||||||
|
} |
||||||
|
], |
||||||
|
"blockExplorers": [ |
||||||
|
{ |
||||||
|
"name": "CeloScan", |
||||||
|
"url": "https://alfajores.celoscan.io", |
||||||
|
"apiUrl": "https://api-alfajores.celoscan.io/api", |
||||||
|
"family": "etherscan" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "Blockscout", |
||||||
|
"url": "https://explorer.celo.org/alfajores", |
||||||
|
"apiUrl": "https://explorer.celo.org/alfajores/api", |
||||||
|
"family": "blockscout" |
||||||
|
} |
||||||
|
], |
||||||
|
"blocks": { |
||||||
|
"confirmations": 1, |
||||||
|
"reorgPeriod": 0, |
||||||
|
"estimateBlockTime": 5 |
||||||
|
}, |
||||||
|
"isTestnet": true |
||||||
|
}, |
||||||
|
"fuji": { |
||||||
|
"chainId": 43113, |
||||||
|
"domainId": 43113, |
||||||
|
"name": "fuji", |
||||||
|
"protocol": "ethereum", |
||||||
|
"displayName": "Fuji", |
||||||
|
"nativeToken": { |
||||||
|
"decimals": 18, |
||||||
|
"name": "Avalanche", |
||||||
|
"symbol": "AVAX" |
||||||
|
}, |
||||||
|
"rpcUrls": [ |
||||||
|
{ |
||||||
|
"http": "https://api.avax-test.network/ext/bc/C/rpc", |
||||||
|
"pagination": { |
||||||
|
"maxBlockRange": 2048 |
||||||
|
} |
||||||
|
} |
||||||
|
], |
||||||
|
"blockExplorers": [ |
||||||
|
{ |
||||||
|
"name": "SnowTrace", |
||||||
|
"url": "https://testnet.snowtrace.io", |
||||||
|
"apiUrl": "https://api-testnet.snowtrace.io/api", |
||||||
|
"family": "etherscan" |
||||||
|
} |
||||||
|
], |
||||||
|
"blocks": { |
||||||
|
"confirmations": 3, |
||||||
|
"reorgPeriod": 3, |
||||||
|
"estimateBlockTime": 2 |
||||||
|
}, |
||||||
|
"isTestnet": true |
||||||
|
}, |
||||||
|
"mumbai": { |
||||||
|
"chainId": 80001, |
||||||
|
"domainId": 80001, |
||||||
|
"name": "mumbai", |
||||||
|
"protocol": "ethereum", |
||||||
|
"displayName": "Mumbai", |
||||||
|
"nativeToken": { |
||||||
|
"name": "MATIC", |
||||||
|
"symbol": "MATIC", |
||||||
|
"decimals": 18 |
||||||
|
}, |
||||||
|
"rpcUrls": [ |
||||||
|
{ |
||||||
|
"http": "https://rpc.ankr.com/polygon_mumbai", |
||||||
|
"pagination": { |
||||||
|
"maxBlockRange": 10000, |
||||||
|
"minBlockNumber": 22900000 |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"http": "https://matic-mumbai.chainstacklabs.com" |
||||||
|
} |
||||||
|
], |
||||||
|
"blockExplorers": [ |
||||||
|
{ |
||||||
|
"name": "PolygonScan", |
||||||
|
"url": "https://mumbai.polygonscan.com", |
||||||
|
"apiUrl": "https://api-testnet.polygonscan.com/api", |
||||||
|
"family": "etherscan" |
||||||
|
} |
||||||
|
], |
||||||
|
"blocks": { |
||||||
|
"confirmations": 3, |
||||||
|
"reorgPeriod": 32, |
||||||
|
"estimateBlockTime": 5 |
||||||
|
}, |
||||||
|
"isTestnet": true |
||||||
|
}, |
||||||
|
"bsctestnet": { |
||||||
|
"chainId": 97, |
||||||
|
"domainId": 97, |
||||||
|
"name": "bsctestnet", |
||||||
|
"protocol": "ethereum", |
||||||
|
"displayName": "BSC Testnet", |
||||||
|
"nativeToken": { |
||||||
|
"decimals": 18, |
||||||
|
"name": "BNB", |
||||||
|
"symbol": "BNB" |
||||||
|
}, |
||||||
|
"rpcUrls": [ |
||||||
|
{ |
||||||
|
"http": "https://data-seed-prebsc-1-s3.binance.org:8545" |
||||||
|
} |
||||||
|
], |
||||||
|
"blockExplorers": [ |
||||||
|
{ |
||||||
|
"name": "BscScan", |
||||||
|
"url": "https://testnet.bscscan.com", |
||||||
|
"apiUrl": "https://api-testnet.bscscan.com/api", |
||||||
|
"family": "etherscan" |
||||||
|
} |
||||||
|
], |
||||||
|
"blocks": { |
||||||
|
"confirmations": 1, |
||||||
|
"reorgPeriod": 9, |
||||||
|
"estimateBlockTime": 3 |
||||||
|
}, |
||||||
|
"isTestnet": true |
||||||
|
}, |
||||||
|
"goerli": { |
||||||
|
"chainId": 5, |
||||||
|
"domainId": 5, |
||||||
|
"name": "goerli", |
||||||
|
"protocol": "ethereum", |
||||||
|
"displayName": "Goerli", |
||||||
|
"nativeToken": { |
||||||
|
"name": "Ether", |
||||||
|
"symbol": "ETH", |
||||||
|
"decimals": 18 |
||||||
|
}, |
||||||
|
"rpcUrls": [ |
||||||
|
{ |
||||||
|
"http": "https://goerli.infura.io/v3/9aa3d95b3bc440fa88ea12eaa4456161" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"http": "https://rpc.ankr.com/eth_goerli" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"http": "https://eth-goerli.public.blastapi.io" |
||||||
|
} |
||||||
|
], |
||||||
|
"blockExplorers": [ |
||||||
|
{ |
||||||
|
"name": "Etherscan", |
||||||
|
"url": "https://goerli.etherscan.io", |
||||||
|
"apiUrl": "https://api-goerli.etherscan.io/api", |
||||||
|
"family": "etherscan" |
||||||
|
} |
||||||
|
], |
||||||
|
"blocks": { |
||||||
|
"confirmations": 1, |
||||||
|
"reorgPeriod": 2, |
||||||
|
"estimateBlockTime": 13 |
||||||
|
}, |
||||||
|
"isTestnet": true |
||||||
|
}, |
||||||
|
"moonbasealpha": { |
||||||
|
"chainId": 1287, |
||||||
|
"domainId": 1287, |
||||||
|
"name": "moonbasealpha", |
||||||
|
"protocol": "ethereum", |
||||||
|
"displayName": "Moonbase Alpha", |
||||||
|
"displayNameShort": "Moonbase", |
||||||
|
"nativeToken": { |
||||||
|
"decimals": 18, |
||||||
|
"name": "DEV", |
||||||
|
"symbol": "DEV" |
||||||
|
}, |
||||||
|
"rpcUrls": [ |
||||||
|
{ |
||||||
|
"http": "https://rpc.api.moonbase.moonbeam.network" |
||||||
|
} |
||||||
|
], |
||||||
|
"blockExplorers": [ |
||||||
|
{ |
||||||
|
"name": "MoonScan", |
||||||
|
"url": "https://moonbase.moonscan.io", |
||||||
|
"apiUrl": "https://api-moonbase.moonscan.io/api", |
||||||
|
"family": "etherscan" |
||||||
|
} |
||||||
|
], |
||||||
|
"blocks": { |
||||||
|
"confirmations": 1, |
||||||
|
"reorgPeriod": 1, |
||||||
|
"estimateBlockTime": 12 |
||||||
|
}, |
||||||
|
"isTestnet": true |
||||||
|
}, |
||||||
|
"optimismgoerli": { |
||||||
|
"chainId": 420, |
||||||
|
"domainId": 420, |
||||||
|
"name": "optimismgoerli", |
||||||
|
"protocol": "ethereum", |
||||||
|
"displayName": "Optimism Goerli", |
||||||
|
"displayNameShort": "Opt. Goerli", |
||||||
|
"nativeToken": { |
||||||
|
"name": "Ether", |
||||||
|
"symbol": "ETH", |
||||||
|
"decimals": 18 |
||||||
|
}, |
||||||
|
"rpcUrls": [ |
||||||
|
{ |
||||||
|
"http": "https://goerli.optimism.io" |
||||||
|
} |
||||||
|
], |
||||||
|
"blockExplorers": [ |
||||||
|
{ |
||||||
|
"name": "Etherscan", |
||||||
|
"url": "https://goerli-optimism.etherscan.io", |
||||||
|
"apiUrl": "https://api-goerli-optimism.etherscan.io/api", |
||||||
|
"family": "etherscan" |
||||||
|
} |
||||||
|
], |
||||||
|
"blocks": { |
||||||
|
"confirmations": 1, |
||||||
|
"reorgPeriod": 1, |
||||||
|
"estimateBlockTime": 3 |
||||||
|
}, |
||||||
|
"isTestnet": true |
||||||
|
}, |
||||||
|
"arbitrumgoerli": { |
||||||
|
"chainId": 421613, |
||||||
|
"domainId": 421613, |
||||||
|
"name": "arbitrumgoerli", |
||||||
|
"protocol": "ethereum", |
||||||
|
"displayName": "Arbitrum Goerli", |
||||||
|
"displayNameShort": "Arb. Goerli", |
||||||
|
"nativeToken": { |
||||||
|
"name": "Ether", |
||||||
|
"symbol": "ETH", |
||||||
|
"decimals": 18 |
||||||
|
}, |
||||||
|
"rpcUrls": [ |
||||||
|
{ |
||||||
|
"http": "https://goerli-rollup.arbitrum.io/rpc" |
||||||
|
} |
||||||
|
], |
||||||
|
"blockExplorers": [ |
||||||
|
{ |
||||||
|
"name": "Arbiscan", |
||||||
|
"url": "https://goerli.arbiscan.io", |
||||||
|
"apiUrl": "https://api-goerli.arbiscan.io/api", |
||||||
|
"family": "etherscan" |
||||||
|
} |
||||||
|
], |
||||||
|
"blocks": { |
||||||
|
"confirmations": 1, |
||||||
|
"reorgPeriod": 1, |
||||||
|
"estimateBlockTime": 3 |
||||||
|
}, |
||||||
|
"isTestnet": true |
||||||
|
}, |
||||||
|
"sepolia": { |
||||||
|
"chainId": 11155111, |
||||||
|
"domainId": 11155111, |
||||||
|
"name": "sepolia", |
||||||
|
"protocol": "ethereum", |
||||||
|
"displayName": "Sepolia", |
||||||
|
"nativeToken": { |
||||||
|
"name": "Ether", |
||||||
|
"symbol": "ETH", |
||||||
|
"decimals": 18 |
||||||
|
}, |
||||||
|
"rpcUrls": [ |
||||||
|
{ |
||||||
|
"http": "https://endpoints.omniatech.io/v1/eth/sepolia/public" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"http": "https://rpc.sepolia.org" |
||||||
|
} |
||||||
|
], |
||||||
|
"blockExplorers": [ |
||||||
|
{ |
||||||
|
"name": "Etherscan", |
||||||
|
"url": "https://sepolia.etherscan.io", |
||||||
|
"apiUrl": "https://api-sepolia.etherscan.io/api", |
||||||
|
"family": "etherscan" |
||||||
|
} |
||||||
|
], |
||||||
|
"blocks": { |
||||||
|
"confirmations": 1, |
||||||
|
"reorgPeriod": 2, |
||||||
|
"estimateBlockTime": 13 |
||||||
|
}, |
||||||
|
"isTestnet": true |
||||||
|
}, |
||||||
|
"solanadevnet": { |
||||||
|
"chainId": 1399811151, |
||||||
|
"name": "solanadevnet", |
||||||
|
"rpcUrls": [ |
||||||
|
{ |
||||||
|
"http": "https://api.devnet.solana.com" |
||||||
|
} |
||||||
|
] |
||||||
|
}, |
||||||
|
"proteustestnet": { |
||||||
|
"chainId": 88002, |
||||||
|
"domainId": 88002, |
||||||
|
"name": "proteustestnet", |
||||||
|
"protocol": "ethereum", |
||||||
|
"displayName": "Proteus Testnet", |
||||||
|
"nativeToken": { |
||||||
|
"name": "Zebec", |
||||||
|
"symbol": "ZBC", |
||||||
|
"decimals": 18 |
||||||
|
}, |
||||||
|
"rpcUrls": [ |
||||||
|
{ |
||||||
|
"http": "https://api.proteus.nautchain.xyz/solana" |
||||||
|
} |
||||||
|
] |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,32 @@ |
|||||||
|
{ |
||||||
|
"solanadevnet": { |
||||||
|
"interchainSecurityModule": "64xkGhsZbxgP5rBJfpPcpmzkzTGkpSVHiDLcMKS5gmQw" |
||||||
|
}, |
||||||
|
"alfajores": { |
||||||
|
"foreignDeployment": "0x477D860f8F41bC69dDD32821F2Bf2C2Af0243F16" |
||||||
|
}, |
||||||
|
"fuji": { |
||||||
|
"foreignDeployment": "0x5da3b8d6F73dF6003A490072106730218c475AAd" |
||||||
|
}, |
||||||
|
"mumbai": { |
||||||
|
"foreignDeployment": "0x1A4d8a5eD6C93Af828655e15C44eeE2c2851F0D6" |
||||||
|
}, |
||||||
|
"bsctestnet": { |
||||||
|
"foreignDeployment": "0xE09BF59dCA6e622efC33f6fbd8EF85dE45233388" |
||||||
|
}, |
||||||
|
"goerli": { |
||||||
|
"foreignDeployment": "0x405BFdEcB33230b4Ad93C29ba4499b776CfBa189" |
||||||
|
}, |
||||||
|
"moonbasealpha": { |
||||||
|
"foreignDeployment": "0x89e02C3C7b97bCBa63279E10E2a44e6cEF69E6B2" |
||||||
|
}, |
||||||
|
"optimismgoerli": { |
||||||
|
"foreignDeployment": "0x3582d1238cBC812165981E4fFaB0E8D9a4518910" |
||||||
|
}, |
||||||
|
"arbitrumgoerli": { |
||||||
|
"foreignDeployment": "0x339B46496D60b1b6B42e9715DeD8B3D2154dA0Bb" |
||||||
|
}, |
||||||
|
"sepolia": { |
||||||
|
"foreignDeployment": "0x5d56B8a669F50193b54319442c6EEE5edD662381" |
||||||
|
} |
||||||
|
} |
@ -0,0 +1 @@ |
|||||||
|
[42,226,42,33,87,42,251,0,57,248,173,166,139,84,91,50,218,150,183,254,74,195,88,116,92,195,145,231,63,39,9,98,171,58,146,166,209,139,158,82,151,114,58,235,5,25,129,244,219,192,239,35,53,229,191,115,243,59,174,210,94,26,161,101] |
@ -0,0 +1,42 @@ |
|||||||
|
{ |
||||||
|
"bsctestnet": { |
||||||
|
"hex": "0x000000000000000000000000e09bf59dca6e622efc33f6fbd8ef85de45233388", |
||||||
|
"base58": "11111111111148VaL9DFuVc9DbDjRR7c3qyCEjyy" |
||||||
|
}, |
||||||
|
"optimismgoerli": { |
||||||
|
"hex": "0x0000000000000000000000003582d1238cbc812165981e4ffab0e8d9a4518910", |
||||||
|
"base58": "111111111111kEreeMSXc3Nh2JoYtisyZj8pb6X" |
||||||
|
}, |
||||||
|
"fuji": { |
||||||
|
"hex": "0x0000000000000000000000005da3b8d6f73df6003a490072106730218c475aad", |
||||||
|
"base58": "1111111111112JfXZf7EYaEMM1st6wFZbcLN2uwA" |
||||||
|
}, |
||||||
|
"solanadevnet": { |
||||||
|
"hex": "0xab3a92a6d18b9e5297723aeb051981f4dbc0ef2335e5bf73f33baed25e1aa165", |
||||||
|
"base58": "CXQX54kdkU5GqdRJjCmHpwHfEMgFb5SeBmMWntP2Ds7J" |
||||||
|
}, |
||||||
|
"mumbai": { |
||||||
|
"hex": "0x0000000000000000000000001a4d8a5ed6c93af828655e15c44eee2c2851f0d6", |
||||||
|
"base58": "111111111111NFiXSaSzEqfGUNtwSd5dSDgCymP" |
||||||
|
}, |
||||||
|
"alfajores": { |
||||||
|
"hex": "0x000000000000000000000000477d860f8f41bc69ddd32821f2bf2c2af0243f16", |
||||||
|
"base58": "111111111111zmUjMVNXAe5bcqPR8cvaPz5SrQu" |
||||||
|
}, |
||||||
|
"goerli": { |
||||||
|
"hex": "0x000000000000000000000000405bfdecb33230b4ad93c29ba4499b776cfba189", |
||||||
|
"base58": "111111111111u1H27LrKRuu1G7bDpPWUXKphQSt" |
||||||
|
}, |
||||||
|
"sepolia": { |
||||||
|
"hex": "0x0000000000000000000000005d56b8a669f50193b54319442c6eee5edd662381", |
||||||
|
"base58": "1111111111112JRRxgtLh6eyMDsTHUehn6bJcPJ8" |
||||||
|
}, |
||||||
|
"arbitrumgoerli": { |
||||||
|
"hex": "0x000000000000000000000000339b46496d60b1b6b42e9715ded8b3d2154da0bb", |
||||||
|
"base58": "111111111111ihbsGG5PRTKTSYSGewGtDFs2vfc" |
||||||
|
}, |
||||||
|
"moonbasealpha": { |
||||||
|
"hex": "0x00000000000000000000000089e02c3c7b97bcba63279e10e2a44e6cef69e6b2", |
||||||
|
"base58": "1111111111112vQhuwgKwhQ7SM1HZEm6yXQkzCau" |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,32 @@ |
|||||||
|
{ |
||||||
|
"solanadevnet": { |
||||||
|
"interchainSecurityModule": "2NE6Y1rXp1Kpp6vBNqDHYL7HNk7iqh8BKmvCoZtUcZLn" |
||||||
|
}, |
||||||
|
"alfajores": { |
||||||
|
"foreignDeployment": "0x40Adcb03F3C58170b4751c4140636FC6085Ff475" |
||||||
|
}, |
||||||
|
"fuji": { |
||||||
|
"foreignDeployment": "0xAc003FcDD0EE223664F2A000B5A59D082745700b" |
||||||
|
}, |
||||||
|
"mumbai": { |
||||||
|
"foreignDeployment": "0xaB0892029C3E7dD4c0235590dc296E618A7b4d03" |
||||||
|
}, |
||||||
|
"bsctestnet": { |
||||||
|
"foreignDeployment": "0xd259b0e793535325786675542aB296c451535c27" |
||||||
|
}, |
||||||
|
"goerli": { |
||||||
|
"foreignDeployment": "0x03e9531ae74e8F0f96DE26788a22d35bdaD24185" |
||||||
|
}, |
||||||
|
"moonbasealpha": { |
||||||
|
"foreignDeployment": "0xE9D6317a10860340f035f3d09052D9d376855bE8" |
||||||
|
}, |
||||||
|
"optimismgoerli": { |
||||||
|
"foreignDeployment": "0x057d38d184d74192B96840D8FbB37e584dDb569A" |
||||||
|
}, |
||||||
|
"arbitrumgoerli": { |
||||||
|
"foreignDeployment": "0xaAF1BF6f2BfaE290ea8615066fd167e396a2f578" |
||||||
|
}, |
||||||
|
"sepolia": { |
||||||
|
"foreignDeployment": "0x6AD4DEBA8A147d000C09de6465267a9047d1c217" |
||||||
|
} |
||||||
|
} |
@ -0,0 +1 @@ |
|||||||
|
[158,232,241,234,223,84,236,122,65,31,146,220,11,236,43,97,184,113,181,80,237,157,204,188,166,199,112,171,77,38,68,13,187,162,244,131,230,66,68,157,10,57,239,229,249,96,63,124,85,148,35,172,235,211,200,84,208,117,96,204,208,67,146,40] |
@ -0,0 +1,42 @@ |
|||||||
|
{ |
||||||
|
"sepolia": { |
||||||
|
"hex": "0x0000000000000000000000006ad4deba8a147d000c09de6465267a9047d1c217", |
||||||
|
"base58": "1111111111112VKnX2KMsqSTDw9YoXRsZJTwTcUW" |
||||||
|
}, |
||||||
|
"goerli": { |
||||||
|
"hex": "0x00000000000000000000000003e9531ae74e8f0f96de26788a22d35bdad24185", |
||||||
|
"base58": "1111111111114AKBbRbDjAP93LQgmXJPvfVU7SC" |
||||||
|
}, |
||||||
|
"solanadevnet": { |
||||||
|
"hex": "0xbba2f483e642449d0a39efe5f9603f7c559423acebd3c854d07560ccd0439228", |
||||||
|
"base58": "DdTMkk9nuqH5LnD56HLkPiKMV3yB3BNEYSQfgmJHa5i7" |
||||||
|
}, |
||||||
|
"optimismgoerli": { |
||||||
|
"hex": "0x000000000000000000000000057d38d184d74192b96840d8fbb37e584ddb569a", |
||||||
|
"base58": "1111111111115SFp65pWdvPTRK5fmHa3sc4Eq6Z" |
||||||
|
}, |
||||||
|
"fuji": { |
||||||
|
"hex": "0x000000000000000000000000ac003fcdd0ee223664f2a000b5a59d082745700b", |
||||||
|
"base58": "1111111111113Pz2bmxxVNgkKkZPpxgouHiZAjTx" |
||||||
|
}, |
||||||
|
"moonbasealpha": { |
||||||
|
"hex": "0x000000000000000000000000e9d6317a10860340f035f3d09052d9d376855be8", |
||||||
|
"base58": "1111111111114Fx2onL6wvVgGmyjgzGhy48HzCZM" |
||||||
|
}, |
||||||
|
"arbitrumgoerli": { |
||||||
|
"hex": "0x000000000000000000000000aaf1bf6f2bfae290ea8615066fd167e396a2f578", |
||||||
|
"base58": "1111111111113P8WPEsejkHP1Zysy1xXafVFFnaT" |
||||||
|
}, |
||||||
|
"bsctestnet": { |
||||||
|
"hex": "0x000000000000000000000000d259b0e793535325786675542ab296c451535c27", |
||||||
|
"base58": "1111111111113vyKMMTb6aSQDhDLqEvqcPBcTtRC" |
||||||
|
}, |
||||||
|
"alfajores": { |
||||||
|
"hex": "0x00000000000000000000000040adcb03f3c58170b4751c4140636fc6085ff475", |
||||||
|
"base58": "111111111111uGFbQYrmpk8K5cfeu9x438LAGiQ" |
||||||
|
}, |
||||||
|
"mumbai": { |
||||||
|
"hex": "0x000000000000000000000000ab0892029c3e7dd4c0235590dc296e618a7b4d03", |
||||||
|
"base58": "1111111111113PCgiXuWFu2FmvhykJp51x5y5jyC" |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,92 @@ |
|||||||
|
{ |
||||||
|
"alfajores": { |
||||||
|
"type": 3, |
||||||
|
"threshold": 2, |
||||||
|
"validators": [ |
||||||
|
"0xe6072396568e73ce6803b12b7e04164e839f1e54", |
||||||
|
"0x9f177f51289b22515f41f95872e1511391b8e105", |
||||||
|
"0x15f77400845eb1c971ad08de050861d5508cad6c" |
||||||
|
] |
||||||
|
}, |
||||||
|
"fuji": { |
||||||
|
"type": 3, |
||||||
|
"threshold": 2, |
||||||
|
"validators": [ |
||||||
|
"0x9fa19ead5ec76e437948b35e227511b106293c40", |
||||||
|
"0x227e7d6507762ece0c94678f8c103eff9d682476", |
||||||
|
"0x2379e43740e4aa4fde48cf4f00a3106df1d8420d" |
||||||
|
] |
||||||
|
}, |
||||||
|
"mumbai": { |
||||||
|
"type": 3, |
||||||
|
"threshold": 2, |
||||||
|
"validators": [ |
||||||
|
"0x0a664ea799447da6b15645cf8b9e82072a68343f", |
||||||
|
"0x6ae6f12929a960aba24ba74ea310e3d37d0ac045", |
||||||
|
"0x51f70c047cd73bc7873273707501568857a619c4" |
||||||
|
] |
||||||
|
}, |
||||||
|
"bsctestnet": { |
||||||
|
"type": 3, |
||||||
|
"threshold": 2, |
||||||
|
"validators": [ |
||||||
|
"0x23338c8714976dd4a57eaeff17cbd26d7e275c08", |
||||||
|
"0x85a618d7450ebc37e0d682371f08dac94eec7a76", |
||||||
|
"0x95b76562e4ba1791a27ba4236801271c9115b141" |
||||||
|
] |
||||||
|
}, |
||||||
|
"goerli": { |
||||||
|
"type": 3, |
||||||
|
"threshold": 2, |
||||||
|
"validators": [ |
||||||
|
"0xf43fbd072fd38e1121d4b3b0b8a35116bbb01ea9", |
||||||
|
"0xa33020552a21f35e75bd385c6ab95c3dfa82d930", |
||||||
|
"0x0bba4043ff242f8bf3f39bafa8930a84d644d947" |
||||||
|
] |
||||||
|
}, |
||||||
|
"sepolia": { |
||||||
|
"type": 3, |
||||||
|
"threshold": 2, |
||||||
|
"validators": [ |
||||||
|
"0xbc748ee311f5f2d1975d61cdf531755ce8ce3066", |
||||||
|
"0xc4233b2bfe5aec08964a94b403052abb3eafcf07", |
||||||
|
"0x6b36286c19f5c10bdc139ea9ee7f82287303f61d" |
||||||
|
] |
||||||
|
}, |
||||||
|
"moonbasealpha": { |
||||||
|
"type": 3, |
||||||
|
"threshold": 2, |
||||||
|
"validators": [ |
||||||
|
"0x890c2aeac157c3f067f3e42b8afc797939c59a32", |
||||||
|
"0x1b06d6fe69b972ed7420c83599d5a5c0fc185904", |
||||||
|
"0xe70b85206a968a99a597581f0fa09c99e7681093" |
||||||
|
] |
||||||
|
}, |
||||||
|
"optimismgoerli": { |
||||||
|
"type": 3, |
||||||
|
"threshold": 2, |
||||||
|
"validators": [ |
||||||
|
"0xbb8d77eefbecc55db6e5a19b0fc3dc290776f189", |
||||||
|
"0x69792508b4ddaa3ca52241ccfcd1e0b119a1ee65", |
||||||
|
"0x11ddb46c6b653e0cdd7ad5bee32ae316e18f8453" |
||||||
|
] |
||||||
|
}, |
||||||
|
"arbitrumgoerli": { |
||||||
|
"type": 3, |
||||||
|
"threshold": 2, |
||||||
|
"validators": [ |
||||||
|
"0xce798fa21e323f6b24d9838a10ffecdefdfc4f30", |
||||||
|
"0xa792d39dca4426927e0f00c1618d61c9cb41779d", |
||||||
|
"0xdf181fcc11dfac5d01467e4547101a856dd5aa04" |
||||||
|
] |
||||||
|
}, |
||||||
|
"proteustestnet": { |
||||||
|
"type": 3, |
||||||
|
"threshold": 2, |
||||||
|
"validators": [ |
||||||
|
"0x79fc73656abb9eeaa5ee853c4569124f5bdaf9d8", |
||||||
|
"0x72840388d5ab57323bc4f6e6d3ddedfd5cc911f0", |
||||||
|
"0xd4b2a50c53fc6614bb3cd3198e0fdc03f5da973f" |
||||||
|
] |
||||||
|
} |
||||||
|
} |
@ -0,0 +1 @@ |
|||||||
|
[187,239,78,162,24,178,190,184,243,9,66,169,19,139,40,129,55,222,218,2,184,14,122,68,163,6,144,157,76,14,169,237,20,75,176,226,241,81,96,106,31,68,222,130,94,67,105,175,112,84,241,60,117,11,107,135,95,48,20,213,115,123,100,3] |
@ -0,0 +1,65 @@ |
|||||||
|
{ |
||||||
|
"alfajores": { |
||||||
|
"type": 3, |
||||||
|
"threshold": 1, |
||||||
|
"validators": [ |
||||||
|
"0x45e5c228b38e1cf09e9a3423ed0cf4862c4bf3de" |
||||||
|
] |
||||||
|
}, |
||||||
|
"fuji": { |
||||||
|
"type": 3, |
||||||
|
"threshold": 1, |
||||||
|
"validators": [ |
||||||
|
"0xd81ba169170a9b582812cf0e152d2c168572e21f" |
||||||
|
] |
||||||
|
}, |
||||||
|
"mumbai": { |
||||||
|
"type": 3, |
||||||
|
"threshold": 1, |
||||||
|
"validators": [ |
||||||
|
"0xb537c4ce34e1cad718be52aa30b095e416eae46a" |
||||||
|
] |
||||||
|
}, |
||||||
|
"bsctestnet": { |
||||||
|
"type": 3, |
||||||
|
"threshold": 1, |
||||||
|
"validators": [ |
||||||
|
"0x77f80ef5b18977e15d81aea8dd3a88e7df4bc0eb" |
||||||
|
] |
||||||
|
}, |
||||||
|
"goerli": { |
||||||
|
"type": 3, |
||||||
|
"threshold": 1, |
||||||
|
"validators": [ |
||||||
|
"0x9597ddb4ad2af237665559574b820596bb77ae7a" |
||||||
|
] |
||||||
|
}, |
||||||
|
"sepolia": { |
||||||
|
"type": 3, |
||||||
|
"threshold": 1, |
||||||
|
"validators": [ |
||||||
|
"0x183f15924f3a464c54c9393e8d268eb44d2b208c" |
||||||
|
] |
||||||
|
}, |
||||||
|
"moonbasealpha": { |
||||||
|
"type": 3, |
||||||
|
"threshold": 1, |
||||||
|
"validators": [ |
||||||
|
"0xbeaf158f85d7b64ced36b8aea0bbc4cd0f2d1a5d" |
||||||
|
] |
||||||
|
}, |
||||||
|
"optimismgoerli": { |
||||||
|
"type": 3, |
||||||
|
"threshold": 1, |
||||||
|
"validators": [ |
||||||
|
"0x1d6798671ac532f2bf30c3a5230697a4695705e4" |
||||||
|
] |
||||||
|
}, |
||||||
|
"arbitrumgoerli": { |
||||||
|
"type": 3, |
||||||
|
"threshold": 1, |
||||||
|
"validators": [ |
||||||
|
"0x6d13367c7cd713a4ea79a2552adf824bf1ecdd5e" |
||||||
|
] |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,3 @@ |
|||||||
|
{ |
||||||
|
"program_id": "2NE6Y1rXp1Kpp6vBNqDHYL7HNk7iqh8BKmvCoZtUcZLn" |
||||||
|
} |
@ -1 +1 @@ |
|||||||
[63,21,4,198,48,27,204,153,114,92,118,116,234,163,49,14,128,10,0,19,56,226,121,151,6,205,21,108,169,125,212,113,29,16,150,112,133,212,123,146,110,230,188,148,124,117,183,159,93,85,69,97,122,78,86,187,44,166,129,154,160,73,41,186] |
[247,149,169,2,196,128,74,124,111,206,244,112,63,16,180,19,219,212,45,229,21,114,33,11,202,148,12,47,22,26,192,78,75,78,53,149,190,51,57,253,29,141,136,215,159,45,181,164,239,148,140,163,30,108,158,76,94,113,11,4,142,0,192,20] |
@ -1,7 +1,7 @@ |
|||||||
{ |
{ |
||||||
"mailbox": "4v25Dz9RccqUrTzmfHzJMsjd1iVoNrWzeJ4o6GYuJrVn", |
"mailbox": "4v25Dz9RccqUrTzmfHzJMsjd1iVoNrWzeJ4o6GYuJrVn", |
||||||
"validator_announce": "CMHKvdq4CopDf7qXnDCaTybS15QekQeRt4oUB219yxsp", |
"validator_announce": "CMHKvdq4CopDf7qXnDCaTybS15QekQeRt4oUB219yxsp", |
||||||
"multisig_ism_message_id": "2xTVcwDWZgBu69aawCdYHXqH7xQP36iBQ7rN2px1g7ms", |
"multisig_ism_message_id": "64xkGhsZbxgP5rBJfpPcpmzkzTGkpSVHiDLcMKS5gmQw", |
||||||
"igp_program_id": "HyPQPLfGXDTAQTxzGp7r1uy18KxS89GKgreSHpjeuYDn", |
"igp_program_id": "HyPQPLfGXDTAQTxzGp7r1uy18KxS89GKgreSHpjeuYDn", |
||||||
"overhead_igp_account": "AR4hjWPqXEobLvzmv8MTh5k4Se49iTDzbvNX4DpdQGJZ", |
"overhead_igp_account": "AR4hjWPqXEobLvzmv8MTh5k4Se49iTDzbvNX4DpdQGJZ", |
||||||
"igp_account": "7hMPEGdgBQFsjEz3aaNwZp8WMFHs615zAM3erXBDJuJR" |
"igp_account": "7hMPEGdgBQFsjEz3aaNwZp8WMFHs615zAM3erXBDJuJR" |
||||||
|
@ -1,29 +0,0 @@ |
|||||||
{ |
|
||||||
"solanadevnet": { |
|
||||||
"chainId": 1399811151, |
|
||||||
"name": "solanadevnet", |
|
||||||
"publicRpcUrls": [ |
|
||||||
{ |
|
||||||
"http": "https://api.devnet.solana.com" |
|
||||||
} |
|
||||||
] |
|
||||||
}, |
|
||||||
"bsctestnet": { |
|
||||||
"chainId": 97, |
|
||||||
"name": "bsctestnet", |
|
||||||
"publicRpcUrls": [ |
|
||||||
{ |
|
||||||
"http": "https://rpc.ankr.com/bsc_testnet_chapel" |
|
||||||
} |
|
||||||
] |
|
||||||
}, |
|
||||||
"proteustestnet": { |
|
||||||
"chainId": 88002, |
|
||||||
"name": "proteustestnet", |
|
||||||
"publicRpcUrls": [ |
|
||||||
{ |
|
||||||
"http": "https://api.proteus.nautchain.xyz/solana" |
|
||||||
} |
|
||||||
] |
|
||||||
} |
|
||||||
} |
|
@ -1,14 +1,14 @@ |
|||||||
{ |
{ |
||||||
"bsctestnet": { |
"solanadevnet": { |
||||||
"hex": "0x00000000000000000000000031b5234a896fbc4b3e2f7237592d054716762131", |
"hex": "0x05b6502b1d91c60ca0c0d0ab20a16ec40c66f2559becc7888a4fc3c0cefff9a5", |
||||||
"base58": "111111111111hAc1aTgvQGRBFHrYpXpfUqGyqgk" |
"base58": "PJH5QAbxAqrrnSXfH3GHR8icua8CDFZmo97z91xmpvx" |
||||||
}, |
}, |
||||||
"proteustestnet": { |
"proteustestnet": { |
||||||
"hex": "0x00000000000000000000000034a9af13c5555bad0783c220911b9ef59cfdbcef", |
"hex": "0x00000000000000000000000034a9af13c5555bad0783c220911b9ef59cfdbcef", |
||||||
"base58": "111111111111jZ775N1rpEpJ2M8RAzLNNr9Lh7U" |
"base58": "111111111111jZ775N1rpEpJ2M8RAzLNNr9Lh7U" |
||||||
}, |
}, |
||||||
"solanadevnet": { |
"bsctestnet": { |
||||||
"hex": "0x05b6502b1d91c60ca0c0d0ab20a16ec40c66f2559becc7888a4fc3c0cefff9a5", |
"hex": "0x00000000000000000000000031b5234a896fbc4b3e2f7237592d054716762131", |
||||||
"base58": "PJH5QAbxAqrrnSXfH3GHR8icua8CDFZmo97z91xmpvx" |
"base58": "111111111111hAc1aTgvQGRBFHrYpXpfUqGyqgk" |
||||||
} |
} |
||||||
} |
} |
@ -0,0 +1,30 @@ |
|||||||
|
cargo-features = ["workspace-inheritance"] |
||||||
|
|
||||||
|
[package] |
||||||
|
name = "hyperlane-sealevel-hello-world" |
||||||
|
version = "0.1.0" |
||||||
|
edition = "2021" |
||||||
|
|
||||||
|
[features] |
||||||
|
no-entrypoint = [] |
||||||
|
test-client = ["dep:solana-program-test", "dep:solana-sdk", "dep:hyperlane-test-utils", "dep:spl-noop"] |
||||||
|
|
||||||
|
[dependencies] |
||||||
|
borsh.workspace = true |
||||||
|
solana-program-test = { workspace = true, optional = true } |
||||||
|
solana-program.workspace = true |
||||||
|
solana-sdk = { workspace = true, optional = true } |
||||||
|
spl-noop = { workspace = true, optional = true } |
||||||
|
|
||||||
|
access-control = { path = "../../libraries/access-control" } |
||||||
|
account-utils = { path = "../../libraries/account-utils" } |
||||||
|
hyperlane-core = { path = "../../../hyperlane-core" } |
||||||
|
hyperlane-sealevel-mailbox = { path = "../mailbox", features = ["no-entrypoint"] } |
||||||
|
hyperlane-sealevel-igp = { path = "../hyperlane-sealevel-igp", features = ["no-entrypoint"] } |
||||||
|
hyperlane-sealevel-connection-client = { path = "../../libraries/hyperlane-sealevel-connection-client" } |
||||||
|
hyperlane-sealevel-message-recipient-interface = { path = "../../libraries/message-recipient-interface" } |
||||||
|
hyperlane-test-utils = { path = "../../libraries/test-utils", optional = true } |
||||||
|
serializable-account-meta = { path = "../../libraries/serializable-account-meta" } |
||||||
|
|
||||||
|
[lib] |
||||||
|
crate-type = ["cdylib", "lib"] |
@ -0,0 +1,104 @@ |
|||||||
|
//! HelloWorld accounts.
|
||||||
|
use std::collections::HashMap; |
||||||
|
|
||||||
|
use access_control::AccessControl; |
||||||
|
use account_utils::{AccountData, SizedData}; |
||||||
|
use borsh::{BorshDeserialize, BorshSerialize}; |
||||||
|
use hyperlane_core::H256; |
||||||
|
use hyperlane_sealevel_connection_client::{ |
||||||
|
router::{HyperlaneRouter, RemoteRouterConfig}, |
||||||
|
HyperlaneConnectionClient, |
||||||
|
}; |
||||||
|
use hyperlane_sealevel_igp::accounts::InterchainGasPaymasterType; |
||||||
|
|
||||||
|
use solana_program::{program_error::ProgramError, pubkey::Pubkey}; |
||||||
|
|
||||||
|
/// The storage account.
|
||||||
|
pub type HelloWorldStorageAccount = AccountData<HelloWorldStorage>; |
||||||
|
|
||||||
|
/// The storage account's data.
|
||||||
|
#[derive(BorshSerialize, BorshDeserialize, Debug, Default)] |
||||||
|
pub struct HelloWorldStorage { |
||||||
|
/// The local domain.
|
||||||
|
pub local_domain: u32, |
||||||
|
/// The mailbox.
|
||||||
|
pub mailbox: Pubkey, |
||||||
|
/// The ISM.
|
||||||
|
pub ism: Option<Pubkey>, |
||||||
|
/// The IGP.
|
||||||
|
pub igp: Option<(Pubkey, InterchainGasPaymasterType)>, |
||||||
|
/// The owner.
|
||||||
|
pub owner: Option<Pubkey>, |
||||||
|
/// A counter of how many messages have been sent from this contract.
|
||||||
|
pub sent: u64, |
||||||
|
/// A counter of how many messages have been received by this contract.
|
||||||
|
pub received: u64, |
||||||
|
/// Keyed by domain, a counter of how many messages that have been sent
|
||||||
|
/// from this contract to the domain.
|
||||||
|
pub sent_to: HashMap<u32, u64>, |
||||||
|
/// Keyed by domain, a counter of how many messages that have been received
|
||||||
|
/// by this contract from the domain.
|
||||||
|
pub received_from: HashMap<u32, u64>, |
||||||
|
/// Keyed by domain, the router for the remote domain.
|
||||||
|
pub routers: HashMap<u32, H256>, |
||||||
|
} |
||||||
|
|
||||||
|
impl SizedData for HelloWorldStorage { |
||||||
|
fn size(&self) -> usize { |
||||||
|
// local domain
|
||||||
|
std::mem::size_of::<u32>() + |
||||||
|
// mailbox
|
||||||
|
32 + |
||||||
|
// ism
|
||||||
|
1 + 32 + |
||||||
|
// igp
|
||||||
|
1 + 32 + 1 + 32 + |
||||||
|
// owner
|
||||||
|
1 + 32 + |
||||||
|
// sent
|
||||||
|
std::mem::size_of::<u64>() + |
||||||
|
// received
|
||||||
|
std::mem::size_of::<u64>() + |
||||||
|
// sent_to
|
||||||
|
(self.sent_to.len() * (std::mem::size_of::<u32>() + std::mem::size_of::<u64>())) + |
||||||
|
// received_from
|
||||||
|
(self.received_from.len() * (std::mem::size_of::<u32>() + std::mem::size_of::<u64>())) + |
||||||
|
// routers
|
||||||
|
(self.routers.len() * (std::mem::size_of::<u32>() + 32)) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl AccessControl for HelloWorldStorage { |
||||||
|
fn owner(&self) -> Option<&Pubkey> { |
||||||
|
self.owner.as_ref() |
||||||
|
} |
||||||
|
|
||||||
|
fn set_owner(&mut self, new_owner: Option<Pubkey>) -> Result<(), ProgramError> { |
||||||
|
self.owner = new_owner; |
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl HyperlaneRouter for HelloWorldStorage { |
||||||
|
fn router(&self, origin: u32) -> Option<&H256> { |
||||||
|
self.routers.get(&origin) |
||||||
|
} |
||||||
|
|
||||||
|
fn enroll_remote_router(&mut self, config: RemoteRouterConfig) { |
||||||
|
self.routers.insert(config.domain, config.router.unwrap()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl HyperlaneConnectionClient for HelloWorldStorage { |
||||||
|
fn mailbox(&self) -> &Pubkey { |
||||||
|
&self.mailbox |
||||||
|
} |
||||||
|
|
||||||
|
fn interchain_gas_paymaster(&self) -> Option<&(Pubkey, InterchainGasPaymasterType)> { |
||||||
|
self.igp.as_ref() |
||||||
|
} |
||||||
|
|
||||||
|
fn interchain_security_module(&self) -> Option<&Pubkey> { |
||||||
|
self.ism.as_ref() |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,146 @@ |
|||||||
|
//! HelloWorld instructions.
|
||||||
|
|
||||||
|
use borsh::{BorshDeserialize, BorshSerialize}; |
||||||
|
use hyperlane_sealevel_connection_client::router::RemoteRouterConfig; |
||||||
|
use hyperlane_sealevel_igp::accounts::InterchainGasPaymasterType; |
||||||
|
use solana_program::{ |
||||||
|
instruction::{AccountMeta, Instruction}, |
||||||
|
program_error::ProgramError, |
||||||
|
pubkey::Pubkey, |
||||||
|
}; |
||||||
|
|
||||||
|
use crate::program_storage_pda_seeds; |
||||||
|
|
||||||
|
/// Init instruction data.
|
||||||
|
#[derive(BorshSerialize, BorshDeserialize, Debug)] |
||||||
|
pub struct Init { |
||||||
|
/// The local domain.
|
||||||
|
pub local_domain: u32, |
||||||
|
/// The mailbox.
|
||||||
|
pub mailbox: Pubkey, |
||||||
|
/// The ISM.
|
||||||
|
pub ism: Option<Pubkey>, |
||||||
|
/// The IGP.
|
||||||
|
pub igp: Option<(Pubkey, InterchainGasPaymasterType)>, |
||||||
|
/// The owner.
|
||||||
|
pub owner: Option<Pubkey>, |
||||||
|
} |
||||||
|
|
||||||
|
/// A HelloWorld message.
|
||||||
|
#[derive(BorshSerialize, BorshDeserialize, Debug)] |
||||||
|
pub struct HelloWorldMessage { |
||||||
|
/// The destination domain.
|
||||||
|
pub destination: u32, |
||||||
|
/// The message.
|
||||||
|
pub message: String, |
||||||
|
} |
||||||
|
|
||||||
|
/// Instructions for the program.
|
||||||
|
#[derive(BorshSerialize, BorshDeserialize, Debug)] |
||||||
|
pub enum HelloWorldInstruction { |
||||||
|
/// Initializes the program.
|
||||||
|
Init(Init), |
||||||
|
/// Dispatches a message using the dispatch authority.
|
||||||
|
SendHelloWorld(HelloWorldMessage), |
||||||
|
/// Sets the ISM.
|
||||||
|
SetInterchainSecurityModule(Option<Pubkey>), |
||||||
|
/// Enrolls remote routers
|
||||||
|
EnrollRemoteRouters(Vec<RemoteRouterConfig>), |
||||||
|
} |
||||||
|
|
||||||
|
/// Gets an instruction to initialize the program.
|
||||||
|
pub fn init_instruction( |
||||||
|
program_id: Pubkey, |
||||||
|
payer: Pubkey, |
||||||
|
local_domain: u32, |
||||||
|
mailbox: Pubkey, |
||||||
|
ism: Option<Pubkey>, |
||||||
|
igp: Option<(Pubkey, InterchainGasPaymasterType)>, |
||||||
|
owner: Option<Pubkey>, |
||||||
|
) -> Result<Instruction, ProgramError> { |
||||||
|
let (program_storage_account, _program_storage_bump) = |
||||||
|
Pubkey::try_find_program_address(program_storage_pda_seeds!(), &program_id) |
||||||
|
.ok_or(ProgramError::InvalidSeeds)?; |
||||||
|
|
||||||
|
let init = Init { |
||||||
|
local_domain, |
||||||
|
mailbox, |
||||||
|
ism, |
||||||
|
igp, |
||||||
|
owner, |
||||||
|
}; |
||||||
|
|
||||||
|
// Accounts:
|
||||||
|
// 0. [executable] System program.
|
||||||
|
// 1. [signer] Payer.
|
||||||
|
// 2. [writeable] Storage PDA.
|
||||||
|
let accounts = vec![ |
||||||
|
AccountMeta::new_readonly(solana_program::system_program::id(), false), |
||||||
|
AccountMeta::new_readonly(payer, true), |
||||||
|
AccountMeta::new(program_storage_account, false), |
||||||
|
]; |
||||||
|
|
||||||
|
let instruction = Instruction { |
||||||
|
program_id, |
||||||
|
data: HelloWorldInstruction::Init(init).try_to_vec()?, |
||||||
|
accounts, |
||||||
|
}; |
||||||
|
|
||||||
|
Ok(instruction) |
||||||
|
} |
||||||
|
|
||||||
|
/// Gets an instruction to enroll remote routers.
|
||||||
|
pub fn enroll_remote_routers_instruction( |
||||||
|
program_id: Pubkey, |
||||||
|
owner: Pubkey, |
||||||
|
configs: Vec<RemoteRouterConfig>, |
||||||
|
) -> Result<Instruction, ProgramError> { |
||||||
|
let (program_storage_account, _program_storage_bump) = |
||||||
|
Pubkey::try_find_program_address(program_storage_pda_seeds!(), &program_id) |
||||||
|
.ok_or(ProgramError::InvalidSeeds)?; |
||||||
|
|
||||||
|
// Accounts:
|
||||||
|
// 0. [executable] System program.
|
||||||
|
// 1. [signer] Payer.
|
||||||
|
// 2. [writeable] Storage PDA.
|
||||||
|
let accounts = vec![ |
||||||
|
AccountMeta::new_readonly(solana_program::system_program::id(), false), |
||||||
|
AccountMeta::new(program_storage_account, false), |
||||||
|
AccountMeta::new(owner, true), |
||||||
|
]; |
||||||
|
|
||||||
|
let instruction = Instruction { |
||||||
|
program_id, |
||||||
|
data: HelloWorldInstruction::EnrollRemoteRouters(configs).try_to_vec()?, |
||||||
|
accounts, |
||||||
|
}; |
||||||
|
|
||||||
|
Ok(instruction) |
||||||
|
} |
||||||
|
|
||||||
|
/// Gets an instruction to set the interchain security module.
|
||||||
|
pub fn set_interchain_security_module_instruction( |
||||||
|
program_id: Pubkey, |
||||||
|
owner: Pubkey, |
||||||
|
ism: Option<Pubkey>, |
||||||
|
) -> Result<Instruction, ProgramError> { |
||||||
|
let (program_storage_account, _program_storage_bump) = |
||||||
|
Pubkey::try_find_program_address(program_storage_pda_seeds!(), &program_id) |
||||||
|
.ok_or(ProgramError::InvalidSeeds)?; |
||||||
|
|
||||||
|
// Accounts:
|
||||||
|
// 0. [writeable] Storage PDA account.
|
||||||
|
// 1. [signer] Owner.
|
||||||
|
let accounts = vec![ |
||||||
|
AccountMeta::new(program_storage_account, false), |
||||||
|
AccountMeta::new(owner, true), |
||||||
|
]; |
||||||
|
|
||||||
|
let instruction = Instruction { |
||||||
|
program_id, |
||||||
|
data: HelloWorldInstruction::SetInterchainSecurityModule(ism).try_to_vec()?, |
||||||
|
accounts, |
||||||
|
}; |
||||||
|
|
||||||
|
Ok(instruction) |
||||||
|
} |
@ -0,0 +1,9 @@ |
|||||||
|
//! A HelloWorld program that sends and receives messages to & from other routers.
|
||||||
|
|
||||||
|
#![deny(warnings)] |
||||||
|
#![deny(missing_docs)] |
||||||
|
#![deny(unsafe_code)] |
||||||
|
|
||||||
|
pub mod accounts; |
||||||
|
pub mod instruction; |
||||||
|
pub mod processor; |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue