-
Notifications
You must be signed in to change notification settings - Fork 305
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
pcli: add balance migration command (#4842)
initial attempt at implementing a balance migration function for pcli - does not currently handle non-zero fees correctly, but that seems to be the only remaining thing to correctly implement - [x] If this code contains consensus-breaking changes, I have added the "consensus-breaking" label. Otherwise, I declare my belief that there are not consensus-breaking changes, for the following reason: > client/planner only changes Co-authored-by: Lucas Meier <[email protected]> Co-authored-by: Conor Schaefer <[email protected]>
- Loading branch information
1 parent
7601c8c
commit 9443d98
Showing
3 changed files
with
111 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
use crate::App; | ||
use anyhow::{Context, Result}; | ||
use penumbra_keys::FullViewingKey; | ||
use penumbra_proto::view::v1::GasPricesRequest; | ||
use penumbra_view::ViewClient; | ||
use penumbra_wallet::plan::Planner; | ||
use rand_core::OsRng; | ||
use std::{io::Write, str::FromStr}; | ||
use termion::input::TermRead; | ||
|
||
#[derive(Debug, clap::Parser)] | ||
pub enum MigrateCmd { | ||
/// Migrate your entire balance to another wallet. | ||
/// | ||
/// All assets from all accounts in the source wallet will be sent to the destination wallet. | ||
/// A FullViewingKey must be provided for the destination wallet. | ||
/// All funds will be deposited in the account 0 of the destination wallet, | ||
/// minus any gas prices for the migration transaction. | ||
#[clap(name = "balance")] | ||
Balance, | ||
} | ||
|
||
impl MigrateCmd { | ||
#[tracing::instrument(skip(self, app))] | ||
pub async fn exec(&self, app: &mut App) -> Result<()> { | ||
let gas_prices = app | ||
.view | ||
.as_mut() | ||
.context("view service must be initialized")? | ||
.gas_prices(GasPricesRequest {}) | ||
.await? | ||
.into_inner() | ||
.gas_prices | ||
.expect("gas prices must be available") | ||
.try_into()?; | ||
|
||
print!("Enter FVK: "); | ||
std::io::stdout().flush()?; | ||
let to: String = std::io::stdin().lock().read_line()?.unwrap_or_default(); | ||
|
||
match self { | ||
MigrateCmd::Balance => { | ||
let source_fvk = app.config.full_viewing_key.clone(); | ||
|
||
let dest_fvk = to.parse::<FullViewingKey>().map_err(|_| { | ||
anyhow::anyhow!("The provided string is not a valid FullViewingKey.") | ||
})?; | ||
|
||
let mut planner = Planner::new(OsRng); | ||
|
||
let (dest_address, _) = FullViewingKey::payment_address( | ||
&FullViewingKey::from_str(&to[..])?, | ||
Default::default(), | ||
); | ||
|
||
planner | ||
.set_gas_prices(gas_prices) | ||
.set_fee_tier(Default::default()) | ||
.change_address(dest_address); | ||
|
||
// Return all unspent notes from the view service | ||
let notes = app | ||
.view | ||
.as_mut() | ||
.context("view service must be initialized")? | ||
.unspent_notes_by_account_and_asset() | ||
.await?; | ||
|
||
for notes in notes.into_values() { | ||
for notes in notes.into_values() { | ||
for note in notes { | ||
planner.spend(note.note, note.position); | ||
} | ||
} | ||
} | ||
|
||
let memo = format!("Migrating balance from {} to {}", source_fvk, dest_fvk); | ||
let plan = planner | ||
.memo(memo) | ||
.plan( | ||
app.view | ||
.as_mut() | ||
.context("view service must be initialized")?, | ||
Default::default(), | ||
) | ||
.await | ||
.context("can't build send transaction")?; | ||
|
||
if plan.actions.is_empty() { | ||
anyhow::bail!("migration plan contained zero actions: is the source wallet already empty?"); | ||
} | ||
app.build_and_submit_transaction(plan).await?; | ||
|
||
Result::Ok(()) | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters