diff --git a/Cargo.lock b/Cargo.lock index 0429ed0f..7aea3b76 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2697,7 +2697,7 @@ dependencies = [ [[package]] name = "ipc_actors_abis" version = "0.1.0" -source = "git+https://github.com/consensus-shipyard/ipc-solidity-actors.git?branch=dev#cec4e7ede1e16589b86da91b18d197601c90d14b" +source = "git+https://github.com/consensus-shipyard/ipc-solidity-actors.git?branch=dev#b4c23f216b813f10dfa6fa54ea4cb248012cf312" dependencies = [ "anyhow", "ethers", diff --git a/ipc/cli/src/commands/crossmsg/fund.rs b/ipc/cli/src/commands/crossmsg/fund.rs index 392b499a..7c7c7d31 100644 --- a/ipc/cli/src/commands/crossmsg/fund.rs +++ b/ipc/cli/src/commands/crossmsg/fund.rs @@ -73,3 +73,45 @@ pub(crate) struct FundArgs { #[arg(help = "The amount to fund in FIL, in whole FIL")] pub amount: f64, } + +pub struct PreFund; + +#[async_trait] +impl CommandLineHandler for PreFund { + type Arguments = PreFundArgs; + + async fn handle(global: &GlobalArguments, arguments: &Self::Arguments) -> anyhow::Result<()> { + log::debug!("pre-fund subnet with args: {:?}", arguments); + + let mut provider = get_ipc_provider(global)?; + let subnet = SubnetID::from_str(&arguments.subnet)?; + let from = match &arguments.from { + Some(address) => Some(require_fil_addr_from_str(address)?), + None => None, + }; + provider + .pre_fund( + subnet.clone(), + from, + f64_to_token_amount(arguments.initial_balance)?, + ) + .await?; + println!("address pre-funded successfully"); + + Ok(()) + } +} + +#[derive(Debug, Args)] +#[command( + name = "pre-fund", + about = "Add some funds in genesis to an address in a child-subnet" +)] +pub struct PreFundArgs { + #[arg(long, short, help = "The address funded in the subnet")] + pub from: Option, + #[arg(long, short, help = "The subnet to add balance to")] + pub subnet: String, + #[arg(help = "Add an initial balance for the address in genesis in the subnet")] + pub initial_balance: f64, +} diff --git a/ipc/cli/src/commands/crossmsg/mod.rs b/ipc/cli/src/commands/crossmsg/mod.rs index e8281a33..b02b1a92 100644 --- a/ipc/cli/src/commands/crossmsg/mod.rs +++ b/ipc/cli/src/commands/crossmsg/mod.rs @@ -1,5 +1,7 @@ // Copyright 2022-2023 Protocol Labs // SPDX-License-Identifier: MIT +use self::fund::{PreFund, PreFundArgs}; +use self::release::{PreRelease, PreReleaseArgs}; use self::topdown_cross::{ListTopdownMsgs, ListTopdownMsgsArgs}; use crate::commands::crossmsg::fund::Fund; use crate::commands::crossmsg::propagate::Propagate; @@ -28,7 +30,9 @@ impl CrossMsgsCommandsArgs { pub async fn handle(&self, global: &GlobalArguments) -> anyhow::Result<()> { match &self.command { Commands::Fund(args) => Fund::handle(global, args).await, + Commands::PreFund(args) => PreFund::handle(global, args).await, Commands::Release(args) => Release::handle(global, args).await, + Commands::PreRelease(args) => PreRelease::handle(global, args).await, Commands::Propagate(args) => Propagate::handle(global, args).await, Commands::ListTopdownMsgs(args) => ListTopdownMsgs::handle(global, args).await, } @@ -38,7 +42,9 @@ impl CrossMsgsCommandsArgs { #[derive(Debug, Subcommand)] pub(crate) enum Commands { Fund(FundArgs), + PreFund(PreFundArgs), Release(ReleaseArgs), + PreRelease(PreReleaseArgs), Propagate(PropagateArgs), ListTopdownMsgs(ListTopdownMsgsArgs), } diff --git a/ipc/cli/src/commands/crossmsg/release.rs b/ipc/cli/src/commands/crossmsg/release.rs index c14d31d7..d6f0a9e3 100644 --- a/ipc/cli/src/commands/crossmsg/release.rs +++ b/ipc/cli/src/commands/crossmsg/release.rs @@ -79,3 +79,41 @@ pub(crate) struct ReleaseArgs { #[arg(help = "The amount to release in FIL, in whole FIL")] pub amount: f64, } + +pub struct PreRelease; + +#[async_trait] +impl CommandLineHandler for PreRelease { + type Arguments = PreReleaseArgs; + + async fn handle(global: &GlobalArguments, arguments: &Self::Arguments) -> anyhow::Result<()> { + log::debug!("pre-release subnet with args: {:?}", arguments); + + let mut provider = get_ipc_provider(global)?; + let subnet = SubnetID::from_str(&arguments.subnet)?; + let from = match &arguments.from { + Some(address) => Some(require_fil_addr_from_str(address)?), + None => None, + }; + provider + .pre_release(subnet.clone(), from, f64_to_token_amount(arguments.amount)?) + .await?; + println!("address pre-release successfully"); + + Ok(()) + } +} + +#[derive(Debug, Args)] +#[command( + name = "pre-release", + about = "Release some funds from the genesis balance of the child subnet" +)] +pub struct PreReleaseArgs { + #[arg(long, short, help = "The address funded in the subnet")] + pub from: Option, + #[arg(long, short, help = "The subnet to release balance from")] + pub subnet: String, + #[arg(help = "Amount to release from the genesis balance of a child subnet")] + pub amount: f64, +} diff --git a/ipc/cli/src/commands/subnet/join.rs b/ipc/cli/src/commands/subnet/join.rs index 277b1705..203a5cf5 100644 --- a/ipc/cli/src/commands/subnet/join.rs +++ b/ipc/cli/src/commands/subnet/join.rs @@ -32,7 +32,7 @@ impl CommandLineHandler for JoinSubnet { if let Some(initial_balance) = arguments.initial_balance { println!("pre-funding address with {initial_balance}"); provider - .prefund_subnet(subnet.clone(), from, f64_to_token_amount(initial_balance)?) + .pre_fund(subnet.clone(), from, f64_to_token_amount(initial_balance)?) .await?; } let epoch = provider @@ -147,45 +147,3 @@ pub struct UnstakeSubnetArgs { )] pub collateral: f64, } - -pub struct PreFundSubnet; - -#[async_trait] -impl CommandLineHandler for PreFundSubnet { - type Arguments = PreFundSubnetArgs; - - async fn handle(global: &GlobalArguments, arguments: &Self::Arguments) -> anyhow::Result<()> { - log::debug!("pre-fund subnet with args: {:?}", arguments); - - let mut provider = get_ipc_provider(global)?; - let subnet = SubnetID::from_str(&arguments.subnet)?; - let from = match &arguments.from { - Some(address) => Some(require_fil_addr_from_str(address)?), - None => None, - }; - provider - .prefund_subnet( - subnet.clone(), - from, - f64_to_token_amount(arguments.initial_balance)?, - ) - .await?; - println!("address pre-funded successfully"); - - Ok(()) - } -} - -#[derive(Debug, Args)] -#[command( - name = "pre-fund", - about = "Add some funds in genesis to an address in a child-subnet" -)] -pub struct PreFundSubnetArgs { - #[arg(long, short, help = "The address funded in the subnet")] - pub from: Option, - #[arg(long, short, help = "The subnet to add balance to")] - pub subnet: String, - #[arg(help = "Add an initial balance for the address in genesis in the subnet")] - pub initial_balance: f64, -} diff --git a/ipc/cli/src/commands/subnet/mod.rs b/ipc/cli/src/commands/subnet/mod.rs index ec5b0b27..c2f00ad7 100644 --- a/ipc/cli/src/commands/subnet/mod.rs +++ b/ipc/cli/src/commands/subnet/mod.rs @@ -13,10 +13,7 @@ use crate::{CommandLineHandler, GlobalArguments}; use clap::{Args, Subcommand}; use self::bootstrap::{AddBootstrap, AddBootstrapArgs, ListBootstraps, ListBootstrapsArgs}; -use self::join::{ - PreFundSubnet, PreFundSubnetArgs, StakeSubnet, StakeSubnetArgs, UnstakeSubnet, - UnstakeSubnetArgs, -}; +use self::join::{StakeSubnet, StakeSubnetArgs, UnstakeSubnet, UnstakeSubnetArgs}; use self::leave::{Claim, ClaimArgs}; use self::rpc::{ChainIdSubnet, ChainIdSubnetArgs}; @@ -58,7 +55,6 @@ impl SubnetCommandsArgs { Commands::AddBootstrap(args) => AddBootstrap::handle(global, args).await, Commands::ListBootstraps(args) => ListBootstraps::handle(global, args).await, Commands::GenesisEpoch(args) => GenesisEpoch::handle(global, args).await, - Commands::PreFund(args) => PreFundSubnet::handle(global, args).await, } } } @@ -79,5 +75,4 @@ pub(crate) enum Commands { AddBootstrap(AddBootstrapArgs), ListBootstraps(ListBootstrapsArgs), GenesisEpoch(GenesisEpochArgs), - PreFund(PreFundSubnetArgs), } diff --git a/ipc/provider/src/lib.rs b/ipc/provider/src/lib.rs index 5e105015..6c75a6a1 100644 --- a/ipc/provider/src/lib.rs +++ b/ipc/provider/src/lib.rs @@ -298,7 +298,7 @@ impl IpcProvider { .await } - pub async fn prefund_subnet( + pub async fn pre_fund( &mut self, subnet: SubnetID, from: Option
, @@ -316,6 +316,24 @@ impl IpcProvider { conn.manager().pre_fund(subnet, sender, balance).await } + pub async fn pre_release( + &mut self, + subnet: SubnetID, + from: Option
, + amount: TokenAmount, + ) -> anyhow::Result<()> { + let parent = subnet.parent().ok_or_else(|| anyhow!("no parent found"))?; + let conn = match self.connection(&parent) { + None => return Err(anyhow!("target parent subnet not found")), + Some(conn) => conn, + }; + + let subnet_config = conn.subnet(); + let sender = self.check_sender(subnet_config, from)?; + + conn.manager().pre_release(subnet, sender, amount).await + } + pub async fn stake( &mut self, subnet: SubnetID, diff --git a/ipc/provider/src/manager/evm/manager.rs b/ipc/provider/src/manager/evm/manager.rs index 538ddd0e..1f6ba8e6 100644 --- a/ipc/provider/src/manager/evm/manager.rs +++ b/ipc/provider/src/manager/evm/manager.rs @@ -333,6 +333,33 @@ impl SubnetManager for EthSubnetManager { Ok(()) } + async fn pre_release( + &self, + subnet: SubnetID, + from: Address, + amount: TokenAmount, + ) -> Result<()> { + let address = contract_address_from_subnet(&subnet)?; + log::info!("pre-release funds from {subnet:} at contract: {address:}"); + + let amount = amount + .atto() + .to_u128() + .ok_or_else(|| anyhow!("invalid pre-release amount"))?; + + let signer = Arc::new(self.get_signer(&from)?); + let contract = + subnet_actor_manager_facet::SubnetActorManagerFacet::new(address, signer.clone()); + + call_with_premium_estimation(signer, contract.pre_release(amount.into())) + .await? + .send() + .await? + .await?; + + Ok(()) + } + async fn stake(&self, subnet: SubnetID, from: Address, collateral: TokenAmount) -> Result<()> { let collateral = collateral .atto() diff --git a/ipc/provider/src/manager/subnet.rs b/ipc/provider/src/manager/subnet.rs index e4b71870..fb86a917 100644 --- a/ipc/provider/src/manager/subnet.rs +++ b/ipc/provider/src/manager/subnet.rs @@ -41,6 +41,10 @@ pub trait SubnetManager: Send + Sync + TopDownCheckpointQuery + BottomUpCheckpoi /// it available in the subnet at genesis. async fn pre_fund(&self, subnet: SubnetID, from: Address, balance: TokenAmount) -> Result<()>; + /// Releases initial funds from an address for a subnet that has not yet been bootstrapped + async fn pre_release(&self, subnet: SubnetID, from: Address, amount: TokenAmount) + -> Result<()>; + /// Allows validators that have already joined the subnet to stake more collateral /// and increase their power in the subnet. async fn stake(&self, subnet: SubnetID, from: Address, collateral: TokenAmount) -> Result<()>;