Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
260120.0
260203.0
6 changes: 6 additions & 0 deletions crates/admin_cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use {
mod deploy;
mod migration;
mod operator;
mod ownership;
mod settings;
mod view;

Expand Down Expand Up @@ -41,6 +42,10 @@ enum Command {
/// Cluster settings management
#[command(subcommand)]
Settings(settings::Command),

/// Cluster ownership management
#[command(subcommand)]
Ownership(ownership::Command),
}

#[derive(Debug, Args)]
Expand Down Expand Up @@ -98,6 +103,7 @@ async fn main() -> anyhow::Result<()> {
Command::Operator(cmd) => operator::execute(cmd).await,
Command::Migration(cmd) => migration::execute(cmd).await,
Command::Settings(cmd) => settings::execute(cmd).await,
Command::Ownership(cmd) => ownership::execute(cmd).await,
}
}

Expand Down
68 changes: 68 additions & 0 deletions crates/admin_cli/src/ownership.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
use {
crate::ClusterArgs,
anyhow::Context,
clap::{Args, Subcommand},
wcn_cluster::smart_contract::{AccountAddress, Write as _},
};

#[derive(Debug, Subcommand)]
pub(super) enum Command {
/// Transfer ownership of the WCN Cluster
Transfer(TransferArgs),

/// Accept ownership of the WCN Cluster
Accept(ClusterArgs),
}

#[derive(Debug, Args)]
pub(super) struct TransferArgs {
#[command(flatten)]
cluster_args: ClusterArgs,

/// Address of the new owner of the WCN Cluster
#[arg(long)]
new_owner: AccountAddress,
}

pub(super) async fn execute(cmd: Command) -> anyhow::Result<()> {
match cmd {
Command::Transfer(args) => transfer_ownership(args).await,
Command::Accept(args) => accept_ownership(args).await,
}
}

async fn transfer_ownership(args: TransferArgs) -> anyhow::Result<()> {
let cluster = args.cluster_args.connect().await?;

println!("Transferring ownership to {}", args.new_owner);

if crate::ask_approval()? {
cluster
.transfer_ownership(args.new_owner)
.await
.context("Cluster::transfer_ownership")?;
}

println!(
"To complete the transfer the new owner is required to call `wcn_admin ownership accept` \
command"
);

Ok(())
}

async fn accept_ownership(args: ClusterArgs) -> anyhow::Result<()> {
let cluster = args.connect().await?;

cluster
.accept_ownership()
.await
.context("Cluster::accept_ownership")?;

println!(
"OK. {} is the new owner",
cluster.smart_contract().signer().unwrap()
);

Ok(())
}
28 changes: 28 additions & 0 deletions crates/cluster/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -491,6 +491,31 @@ where
Ok(())
}

/// Calls [`SmartContract::transfer_ownership`].
pub async fn transfer_ownership(
&self,
new_owner: smart_contract::AccountAddress,
) -> Result<(), TransferOwnershipError> {
self.using_view(move |view| {
view.ownership()
.require_owner(self.smart_contract_signer()?)?;

Ok::<_, TransferOwnershipError>(())
})?;

self.inner
.smart_contract
.transfer_ownership(new_owner)
.await?;

Ok(())
}

/// Calls [`SmartContract::accept_ownership`].
pub async fn accept_ownership(&self) -> Result<(), smart_contract::WriteError> {
self.inner.smart_contract.accept_ownership().await
}

fn smart_contract_signer(
&self,
) -> Result<&smart_contract::AccountAddress, NoSmartContractSingerError> {
Expand Down Expand Up @@ -759,6 +784,9 @@ pub enum UpdateSettingsError {
/// [`Cluster::transfer_ownership`] error.
#[derive(Debug, thiserror::Error)]
pub enum TransferOwnershipError {
#[error(transparent)]
NoSigner(#[from] NoSmartContractSingerError),

#[error(transparent)]
NotOwner(#[from] ownership::NotOwnerError),

Expand Down
8 changes: 8 additions & 0 deletions crates/cluster/src/smart_contract/evm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,14 @@ impl smart_contract::Write for SmartContract {
async fn update_settings(&self, new_settings: Settings) -> WriteResult<()> {
check_receipt(self.alloy.updateSettings(new_settings.into())).await
}

async fn transfer_ownership(&self, new_owner: AccountAddress) -> WriteResult<()> {
check_receipt(self.alloy.transferOwnership(new_owner.into())).await
}

async fn accept_ownership(&self) -> WriteResult<()> {
check_receipt(self.alloy.acceptOwnership()).await
}
}

async fn check_receipt<D>(call: CallBuilder<&DynProvider, D>) -> WriteResult<()>
Expand Down
13 changes: 13 additions & 0 deletions crates/cluster/src/smart_contract/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,19 @@ pub trait Write {
/// The implementation MUST emit [`settings::Updated`] event on
/// success.
fn update_settings(&self, new_settings: Settings) -> impl Future<Output = WriteResult<()>>;

/// Transfers ownership of the [`Cluster`] to the specified
/// [`AccountAddress`].
///
/// The new owner is required to confirm the transfer using
/// [`SmartContract::accept_ownership`].
fn transfer_ownership(
&self,
new_owner: AccountAddress,
) -> impl Future<Output = WriteResult<()>>;

/// Accepts ownership of the [`Cluster`].
fn accept_ownership(&self) -> impl Future<Output = WriteResult<()>>;
}

/// Read [`SmartContract`] calls.
Expand Down
8 changes: 8 additions & 0 deletions crates/cluster/src/smart_contract/testing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,14 @@ impl super::Write for FakeSmartContract {
})
.await
}

async fn transfer_ownership(&self, _new_owner: AccountAddress) -> WriteResult<()> {
Ok(())
}

async fn accept_ownership(&self) -> WriteResult<()> {
Ok(())
}
}

impl super::Read for FakeSmartContract {
Expand Down