introduced specialised subcommand to importer-cli to import mixnet/vesting contracts
This commit is contained in:
Generated
+2
@@ -3315,8 +3315,10 @@ dependencies = [
|
||||
"dirs 5.0.1",
|
||||
"importer-contract",
|
||||
"nym-bin-common",
|
||||
"nym-mixnet-contract-common",
|
||||
"nym-network-defaults",
|
||||
"nym-validator-client",
|
||||
"nym-vesting-contract-common",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tokio",
|
||||
|
||||
@@ -24,3 +24,6 @@ importer-contract = { path = "../importer-contract" }
|
||||
nym-validator-client = { path = "../../../../common/client-libs/validator-client" }
|
||||
nym-bin-common = { path = "../../../../common/bin-common", features = ["basic_tracing"] }
|
||||
nym-network-defaults = { path = "../../../../common/network-defaults" }
|
||||
|
||||
nym-mixnet-contract-common = { path = "../../../../common/cosmwasm-smart-contracts/mixnet-contract" }
|
||||
nym-vesting-contract-common = { path = "../../../../common/cosmwasm-smart-contracts/vesting-contract" }
|
||||
+160
-1
@@ -1,4 +1,163 @@
|
||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use clap::ArgGroup;
|
||||
use crate::commands::prepare::create_importer_contract;
|
||||
use crate::commands::set_state::set_importer_state;
|
||||
use crate::commands::swap_contract::swap_contract;
|
||||
use crate::helpers::{mixnet_contract_path, vesting_contract_path};
|
||||
use clap::Args;
|
||||
use importer_contract::ExecuteMsg;
|
||||
use nym_mixnet_contract_common::{Addr, ContractState};
|
||||
use nym_validator_client::nyxd::{AccountId, CosmWasmClient};
|
||||
use nym_validator_client::DirectSigningHttpRpcNyxdClient;
|
||||
use serde::Serialize;
|
||||
use std::path::PathBuf;
|
||||
use tracing::info;
|
||||
|
||||
#[derive(Args, Clone)]
|
||||
pub struct InitialiseMixnetVestingWithStatesArgs {
|
||||
/// Path to the .wasm file with the importer contract
|
||||
/// If not provided, the CLI will attempt to traverse the parent directories until it finds
|
||||
/// "target/wasm32-unknown-unknown/release/importer_contract.wasm"
|
||||
#[clap(long)]
|
||||
pub importer_contract_path: Option<PathBuf>,
|
||||
|
||||
/// Path to the file containing state dump of the mixnet contract
|
||||
#[clap(long)]
|
||||
pub mixnet_state: PathBuf,
|
||||
|
||||
/// Path to the file containing state dump of the vesting contract
|
||||
#[clap(long)]
|
||||
pub vesting_state: PathBuf,
|
||||
|
||||
/// Path to mixnet contract that will be uploaded and applied to the imported state
|
||||
/// If not provided, the CLI will attempt to traverse the parent directories until it finds
|
||||
/// "target/wasm32-unknown-unknown/release/mixnet_contract.wasm"
|
||||
#[clap(long)]
|
||||
pub mixnet_contract_path: Option<PathBuf>,
|
||||
|
||||
/// Path to the vesting contract that will be uploaded and applied to the imported state
|
||||
/// If not provided, the CLI will attempt to traverse the parent directories until it finds
|
||||
/// "target/wasm32-unknown-unknown/release/vesting_contract.wasm"
|
||||
#[clap(long)]
|
||||
pub vesting_contract_path: Option<PathBuf>,
|
||||
}
|
||||
|
||||
pub async fn update_kv<T>(
|
||||
client: &DirectSigningHttpRpcNyxdClient,
|
||||
contract: &AccountId,
|
||||
key: &[u8],
|
||||
value: &T,
|
||||
) -> anyhow::Result<()>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
let msg = ExecuteMsg::from(vec![(key.to_vec(), serde_json::to_vec(value)?)]);
|
||||
client
|
||||
.execute(contract, &msg, None, "updating kv...", Vec::new())
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
pub async fn execute_initialise_mixnet_vesting_with_states(
|
||||
args: InitialiseMixnetVestingWithStatesArgs,
|
||||
client: DirectSigningHttpRpcNyxdClient,
|
||||
) -> anyhow::Result<()> {
|
||||
let mixnet_contract = mixnet_contract_path(args.mixnet_contract_path)?;
|
||||
let vesting_contract = vesting_contract_path(args.vesting_contract_path)?;
|
||||
|
||||
info!(
|
||||
"using the following mixnet contract: {}",
|
||||
mixnet_contract.display()
|
||||
);
|
||||
info!(
|
||||
"using the following vesting contract: {}",
|
||||
vesting_contract.display()
|
||||
);
|
||||
|
||||
let admin = client.address();
|
||||
|
||||
// 1. import mixnet state
|
||||
info!("importing the mixnet contract state...");
|
||||
let mixnet_importer_address =
|
||||
create_importer_contract(args.importer_contract_path.clone(), &client).await?;
|
||||
set_importer_state(
|
||||
args.mixnet_state,
|
||||
Some(mixnet_importer_address.clone()),
|
||||
&client,
|
||||
)
|
||||
.await?;
|
||||
|
||||
// 2. import vesting state
|
||||
info!("importing the vesting contract state...");
|
||||
let vesting_importer_address =
|
||||
create_importer_contract(args.importer_contract_path, &client).await?;
|
||||
set_importer_state(
|
||||
args.vesting_state,
|
||||
Some(vesting_importer_address.clone()),
|
||||
&client,
|
||||
)
|
||||
.await?;
|
||||
|
||||
// 3. adjust few state entries
|
||||
// update vesting admin:
|
||||
info!("adjusting internal contract states...");
|
||||
let new_vesting_admin = Addr::unchecked(admin.as_ref());
|
||||
update_kv(
|
||||
&client,
|
||||
&vesting_importer_address,
|
||||
b"adm",
|
||||
&new_vesting_admin,
|
||||
)
|
||||
.await?;
|
||||
|
||||
// update mixnet contract address in the vesting contract
|
||||
let new_mixnet_contract_address = Addr::unchecked(mixnet_importer_address.as_ref());
|
||||
update_kv(
|
||||
&client,
|
||||
&vesting_importer_address,
|
||||
b"mix",
|
||||
&new_mixnet_contract_address,
|
||||
)
|
||||
.await?;
|
||||
|
||||
// update admins and vesting contract addresses in the mixnet contract
|
||||
let raw_contract_state = client
|
||||
.query_contract_raw(&mixnet_importer_address, b"state".to_vec())
|
||||
.await?;
|
||||
let mut contract_state: ContractState = serde_json::from_slice(&raw_contract_state)?;
|
||||
contract_state.vesting_contract_address = Addr::unchecked(vesting_importer_address.as_ref());
|
||||
contract_state.owner = Some(Addr::unchecked(admin.as_ref()));
|
||||
contract_state.rewarding_validator_address = Addr::unchecked(admin.as_ref());
|
||||
update_kv(&client, &mixnet_importer_address, b"state", &contract_state).await?;
|
||||
|
||||
let contract_admin = Some(Addr::unchecked(admin.as_ref()));
|
||||
update_kv(&client, &mixnet_importer_address, b"admin", &contract_admin).await?;
|
||||
|
||||
// 4. apply the correct contract codes
|
||||
info!("swapping the mixnet contract to the correct .wasm...");
|
||||
swap_contract(
|
||||
None,
|
||||
Some(mixnet_contract),
|
||||
Some(mixnet_importer_address.clone()),
|
||||
None,
|
||||
&client,
|
||||
)
|
||||
.await?;
|
||||
|
||||
info!("swapping the vesting contract to the correct .wasm...");
|
||||
swap_contract(
|
||||
None,
|
||||
Some(vesting_contract),
|
||||
Some(vesting_importer_address.clone()),
|
||||
None,
|
||||
&client,
|
||||
)
|
||||
.await?;
|
||||
|
||||
info!("the contracts are ready");
|
||||
info!("MIXNET: {mixnet_importer_address} VESTING: {vesting_importer_address}");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use crate::commands::initialise_mixnet_vesting_with_states::{
|
||||
execute_initialise_mixnet_vesting_with_states, InitialiseMixnetVestingWithStatesArgs,
|
||||
};
|
||||
use crate::commands::initialise_with_state::{initialise_with_state, InitialiseWithStateArgs};
|
||||
use crate::commands::prepare::{execute_prepare_contract, PrepareArgs};
|
||||
use crate::commands::set_state::{execute_set_state, SetStateArgs};
|
||||
@@ -50,6 +53,10 @@ pub(crate) enum Commands {
|
||||
|
||||
/// Combines the functionalities of `prepare-contract`, `set-state` and `swap-contract`
|
||||
InitialiseWithState(InitialiseWithStateArgs),
|
||||
|
||||
/// Specialised variant of `initialise-with-state` for the mixnet and vesting contracts that sets
|
||||
/// internal state keys
|
||||
InitialiseMixnetVestingWithStates(InitialiseMixnetVestingWithStatesArgs),
|
||||
}
|
||||
|
||||
impl Cli {
|
||||
@@ -73,6 +80,9 @@ impl Cli {
|
||||
Commands::SetState(args) => execute_set_state(args, client).await,
|
||||
Commands::SwapContract(args) => execute_swap_contract(args, client).await,
|
||||
Commands::InitialiseWithState(args) => initialise_with_state(args, client).await,
|
||||
Commands::InitialiseMixnetVestingWithStates(args) => {
|
||||
execute_initialise_mixnet_vesting_with_states(args, client).await
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,15 +3,63 @@
|
||||
|
||||
use crate::state::CachedState;
|
||||
use anyhow::bail;
|
||||
use nym_validator_client::nyxd::cosmwasm_client::types::Model;
|
||||
use nym_validator_client::nyxd::AccountId;
|
||||
use serde::de::DeserializeOwned;
|
||||
use serde::Serialize;
|
||||
use std::env::current_dir;
|
||||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
use tracing::debug;
|
||||
|
||||
pub fn importer_contract_path(explicit: Option<PathBuf>) -> anyhow::Result<PathBuf> {
|
||||
contract_path("importer_contract.wasm", explicit)
|
||||
}
|
||||
|
||||
pub fn mixnet_contract_path(explicit: Option<PathBuf>) -> anyhow::Result<PathBuf> {
|
||||
contract_path("mixnet_contract.wasm", explicit)
|
||||
}
|
||||
|
||||
pub fn vesting_contract_path(explicit: Option<PathBuf>) -> anyhow::Result<PathBuf> {
|
||||
contract_path("vesting_contract.wasm", explicit)
|
||||
}
|
||||
|
||||
fn find_contract_in(root: PathBuf, target_name: &str) -> anyhow::Result<Option<PathBuf>> {
|
||||
for content in root.read_dir()? {
|
||||
let dir_entry = content?;
|
||||
|
||||
let path = dir_entry.path();
|
||||
debug!("checking {:?}", fs::canonicalize(path.clone()));
|
||||
|
||||
let Ok(name) = dir_entry.file_name().into_string() else {
|
||||
continue;
|
||||
};
|
||||
|
||||
if name == "target" {
|
||||
let maybe_contract_path = dir_entry
|
||||
.path()
|
||||
.join("wasm32-unknown-unknown")
|
||||
.join("release")
|
||||
.join(target_name);
|
||||
|
||||
if maybe_contract_path.exists() {
|
||||
return Ok(Some(maybe_contract_path));
|
||||
}
|
||||
}
|
||||
|
||||
if path.is_dir() {
|
||||
if let Some(found) = find_contract_in(path, target_name)? {
|
||||
return Ok(Some(found));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
// this only works if the cli is called from somewhere within the nym directory
|
||||
// (which realistically is going to be the case most of the time)
|
||||
pub fn importer_contract_path(explicit: Option<PathBuf>) -> anyhow::Result<PathBuf> {
|
||||
pub fn contract_path(target_name: &str, explicit: Option<PathBuf>) -> anyhow::Result<PathBuf> {
|
||||
if let Some(explicit) = explicit {
|
||||
return Ok(explicit);
|
||||
}
|
||||
@@ -29,16 +77,24 @@ pub fn importer_contract_path(explicit: Option<PathBuf>) -> anyhow::Result<PathB
|
||||
.path()
|
||||
.join("wasm32-unknown-unknown")
|
||||
.join("release")
|
||||
.join("importer_contract.wasm");
|
||||
.join(target_name);
|
||||
|
||||
if maybe_contract_path.exists() {
|
||||
return Ok(maybe_contract_path);
|
||||
}
|
||||
}
|
||||
|
||||
// SPECIAL CASE:
|
||||
// if there's a `contracts` directory, do traverse its children
|
||||
if name == "contracts" {
|
||||
if let Some(contract) = find_contract_in(dir_entry.path(), target_name)? {
|
||||
return Ok(contract);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bail!("could not find importer_contract.wasm")
|
||||
bail!("could not find {target_name}")
|
||||
}
|
||||
|
||||
pub fn importer_contract_address(explicit: Option<AccountId>) -> anyhow::Result<AccountId> {
|
||||
@@ -49,3 +105,26 @@ pub fn importer_contract_address(explicit: Option<AccountId>) -> anyhow::Result<
|
||||
let state = CachedState::load()?;
|
||||
Ok(state.importer_address)
|
||||
}
|
||||
|
||||
pub fn find_value<T>(raw_state: &[Model], key: &[u8]) -> anyhow::Result<Option<T>>
|
||||
where
|
||||
T: DeserializeOwned,
|
||||
{
|
||||
let Some(entry) = raw_state.iter().find(|kv| kv.key == key) else {
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
Ok(Some(serde_json::from_slice(&entry.value)?))
|
||||
}
|
||||
|
||||
pub fn update_value<T>(raw_state: &mut [Model], key: &[u8], value: &T) -> anyhow::Result<()>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
let Some(entry) = raw_state.iter_mut().find(|kv| kv.key == key) else {
|
||||
bail!("couldn't find corresponding state entry")
|
||||
};
|
||||
|
||||
entry.value = serde_json::to_vec(value)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user