Skip to content

Commit

Permalink
pcli: add delegate-many transaction command reading from a CSV file
Browse files Browse the repository at this point in the history
Example CSV file:

```
penumbravalid10n2srs5257a6nxq9x3fhcsqyc0wh8q2lp7f80qd7wlmzdm6znypse23mmh,0.123
penumbravalid1aglayhqq2ec5yfgx8ljqrd9ypnma5uu46hsd0d77dakgu4nywuyqk29d0m,0.201
penumbravalid1lr6rqawqmwetsr8dvdefrpeh7zuamj2ka9jgmesn2xxfgf49hsys79rz9j,0.256
```

Transaction: f7d386906f5fabc88a5eb051d31bfd45cb51049a7f92f231ed33be3ef6314151
  • Loading branch information
hdevalence committed Jan 24, 2025
1 parent 871551b commit d57f8fb
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 0 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/bin/pcli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ clap = {workspace = true, features = ["derive", "env"]}
colored = "2.1.0"
colored_json = "4.1"
comfy-table = "5"
csv = "1"
decaf377 = {workspace = true, default-features = true}
decaf377-rdsa = {workspace = true}
dialoguer = "0.10.4"
Expand Down
74 changes: 74 additions & 0 deletions crates/bin/pcli/src/command/tx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,21 @@ pub enum TxCmd {
#[clap(short, long, default_value_t)]
fee_tier: FeeTier,
},
/// Delegate to many validators in a single transaction.
#[clap(display_order = 200)]
DelegateMany {
/// A path to a CSV file of (validator identity, UM amount) pairs.
///
/// The amount is in UM, not upenumbra.
#[clap(long, display_order = 100)]
csv_path: String,
/// Only spend funds originally received by the given account.
#[clap(long, default_value = "0", display_order = 300)]
source: u32,
/// The selected fee tier to multiply the fee amount by.
#[clap(short, long, default_value_t)]
fee_tier: FeeTier,
},
/// Withdraw stake from a validator's delegation pool.
#[clap(display_order = 200)]
Undelegate {
Expand Down Expand Up @@ -342,6 +357,7 @@ impl TxCmd {
TxCmd::Sweep { .. } => false,
TxCmd::Swap { .. } => false,
TxCmd::Delegate { .. } => false,
TxCmd::DelegateMany { .. } => false,
TxCmd::Undelegate { .. } => false,
TxCmd::UndelegateClaim { .. } => false,
TxCmd::Vote { .. } => false,
Expand Down Expand Up @@ -604,6 +620,64 @@ impl TxCmd {

app.build_and_submit_transaction(plan).await?;
}
TxCmd::DelegateMany {
csv_path,
source,
fee_tier,
} => {
let mut stake_client = StakeQueryServiceClient::new(app.pd_channel().await?);

let mut sct_client = SctQueryServiceClient::new(app.pd_channel().await?);
let latest_sync_height = app.view().status().await?.full_sync_height;
let epoch = sct_client
.epoch_by_height(EpochByHeightRequest {
height: latest_sync_height,
})
.await?
.into_inner()
.epoch
.expect("epoch must be available")
.into();

let mut planner = Planner::new(OsRng);
planner
.set_gas_prices(gas_prices)
.set_fee_tier((*fee_tier).into());

let file = File::open(csv_path).context("can't open CSV file")?;
let mut reader = csv::ReaderBuilder::new()
.has_headers(false) // Don't skip any rows
.from_reader(file);
for result in reader.records() {
let record = result?;
let validator_identity: IdentityKey = record[0].parse()?;

let rate_data: RateData = stake_client
.current_validator_rate(tonic::Request::new(validator_identity.into()))
.await?
.into_inner()
.try_into()?;

let typed_amount_str = format!("{}penumbra", &record[1]);

let unbonded_amount = {
let Value { amount, asset_id } = typed_amount_str.parse::<Value>()?;
if asset_id != *STAKING_TOKEN_ASSET_ID {
anyhow::bail!("staking can only be done with the staking token");
}
amount
};

planner.delegate(epoch, unbonded_amount, rate_data);
}

let plan = planner
.plan(app.view(), AddressIndex::new(*source))
.await
.context("can't plan delegation, try running pcli tx sweep and try again")?;

app.build_and_submit_transaction(plan).await?;
}
TxCmd::Undelegate {
amount,
source,
Expand Down

0 comments on commit d57f8fb

Please sign in to comment.