From 339b24405c88f421f47e4193811a17490e9cb4f3 Mon Sep 17 00:00:00 2001 From: Marc Nijdam Date: Sun, 5 Jan 2025 10:56:30 -0700 Subject: [PATCH] Add hnt claiming support * Adds support for claiming HNT rewards for hotspots (or any rewardable asset). * removes the need for a separate recipient init check when constructing a claim transaction **Note** This is a breaking change for the cli wallet. the subdao (mobile/iot) parameter for any reward related commands (hotspots/assets) is now a long argument and not providing it assumes that HNT rewards are being asked for or claimed --- helium-lib/src/dao.rs | 97 ++++++------ helium-lib/src/reward.rs | 183 +++++++++++++--------- helium-wallet/src/cmd/assets/rewards.rs | 56 ++----- helium-wallet/src/cmd/burn.rs | 5 +- helium-wallet/src/cmd/hotspots/rewards.rs | 15 +- 5 files changed, 185 insertions(+), 171 deletions(-) diff --git a/helium-lib/src/dao.rs b/helium-lib/src/dao.rs index 7b362190..ee655555 100644 --- a/helium-lib/src/dao.rs +++ b/helium-lib/src/dao.rs @@ -5,10 +5,35 @@ use crate::{ use chrono::Timelike; use sha2::{Digest, Sha256}; -#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, serde::Serialize, serde::Deserialize)] +pub trait RewardableDao { + fn token(&self) -> Token; + fn lazy_distributor_key(&self) -> Pubkey { + let (key, _) = Pubkey::find_program_address( + &[b"lazy_distributor", self.token().mint().as_ref()], + &lazy_distributor::id(), + ); + key + } + fn receipient_key_from_kta(&self, kta: &helium_entity_manager::KeyToAssetV0) -> Pubkey { + let (key, _) = Pubkey::find_program_address( + &[ + b"recipient", + self.lazy_distributor_key().as_ref(), + kta.asset.as_ref(), + ], + &lazy_distributor::id(), + ); + key + } +} + +#[derive( + Debug, Clone, Copy, Eq, PartialEq, Hash, serde::Serialize, serde::Deserialize, Default, +)] #[cfg_attr(feature = "clap", derive(clap::ValueEnum))] #[serde(rename_all = "lowercase")] pub enum Dao { + #[default] Hnt, } @@ -116,6 +141,12 @@ impl Dao { } } +impl RewardableDao for Dao { + fn token(&self) -> Token { + Token::Hnt + } +} + #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, serde::Serialize, serde::Deserialize)] #[cfg_attr(feature = "clap", derive(clap::ValueEnum))] #[serde(rename_all = "lowercase")] @@ -140,32 +171,11 @@ impl SubDao { } pub fn key(&self) -> Pubkey { - let mint = self.mint(); - let (subdao_key, _) = - Pubkey::find_program_address(&[b"sub_dao", mint.as_ref()], &helium_sub_daos::id()); - subdao_key - } - - pub fn mint(&self) -> &Pubkey { - match self { - Self::Iot => Token::Iot.mint(), - Self::Mobile => Token::Mobile.mint(), - } - } - - pub fn token(&self) -> Token { - match self { - Self::Iot => Token::Iot, - Self::Mobile => Token::Mobile, - } - } - - pub fn lazy_distributor(&self) -> Pubkey { - let (key, _) = Pubkey::find_program_address( - &[b"lazy_distributor", self.mint().as_ref()], - &lazy_distributor::id(), + let (subdao_key, _) = Pubkey::find_program_address( + &[b"sub_dao", self.token().mint().as_ref()], + &helium_sub_daos::id(), ); - key + subdao_key } pub fn delegated_dc_key(&self, router_key: &str) -> Pubkey { @@ -211,26 +221,6 @@ impl SubDao { key } - pub fn lazy_distributor_key(&self) -> Pubkey { - let (key, _) = Pubkey::find_program_address( - &[b"lazy_distributor", self.mint().as_ref()], - &lazy_distributor::id(), - ); - key - } - - pub fn receipient_key_from_kta(&self, kta: &helium_entity_manager::KeyToAssetV0) -> Pubkey { - let (key, _) = Pubkey::find_program_address( - &[ - b"recipient", - self.lazy_distributor_key().as_ref(), - kta.asset.as_ref(), - ], - &lazy_distributor::id(), - ); - key - } - pub fn config_key(&self) -> Pubkey { let prefix = match self { Self::Iot => "iot_config", @@ -258,3 +248,18 @@ impl SubDao { key } } + +impl RewardableDao for SubDao { + fn token(&self) -> Token { + match self { + Self::Iot => Token::Iot, + Self::Mobile => Token::Mobile, + } + } +} + +impl RewardableDao for Option { + fn token(&self) -> Token { + self.map(|subdao| subdao.token()).unwrap_or(Token::Hnt) + } +} diff --git a/helium-lib/src/reward.rs b/helium-lib/src/reward.rs index 3a447672..0942c5b7 100644 --- a/helium-lib/src/reward.rs +++ b/helium-lib/src/reward.rs @@ -2,7 +2,7 @@ use crate::{ anchor_lang::{InstructionData, ToAccountMetas}, asset, circuit_breaker, client::{DasClient, GetAnchorAccount, SolanaRpcClient}, - dao::{Dao, SubDao}, + dao::{Dao, RewardableDao}, entity_key::{self, AsEntityKey, KeySerialization}, error::{DecodeError, EncodeError, Error}, helium_entity_manager, @@ -48,12 +48,12 @@ pub struct OracleReward { pub reward: TokenAmount, } -pub async fn lazy_distributor( +pub async fn lazy_distributor( client: &C, - subdao: &SubDao, + dao: &D, ) -> Result { client - .anchor_account::(&subdao.lazy_distributor()) + .anchor_account::(&dao.lazy_distributor_key()) .await } @@ -91,11 +91,11 @@ fn time_decay_previous_value( .ok() } -pub async fn max_claim( +pub async fn max_claim( client: &C, - subdao: &SubDao, + dao: &D, ) -> Result { - let ld_account = lazy_distributor(client, subdao).await?; + let ld_account = lazy_distributor(client, dao).await?; let circuit_breaker_account: circuit_breaker::AccountWindowedCircuitBreakerV0 = client .anchor_account(&lazy_distributor_circuit_breaker(&ld_account)) .await?; @@ -113,19 +113,19 @@ pub async fn max_claim( Utc::now().timestamp(), ) .ok_or_else(|| DecodeError::other("failed to calculate decayed rewards"))?; - Ok(subdao.token().amount(threshold - remaining)) + Ok(dao.token().amount(threshold - remaining)) } -async fn set_current_rewards_instruction( - subdao: &SubDao, +async fn set_current_rewards_instruction( + dao: &D, kta_key: Pubkey, kta: &helium_entity_manager::KeyToAssetV0, reward: &OracleReward, ) -> Result { let accounts = rewards_oracle::accounts::SetCurrentRewardsWrapperV1 { oracle: reward.oracle.key, - lazy_distributor: subdao.lazy_distributor(), - recipient: subdao.receipient_key_from_kta(kta), + lazy_distributor: dao.lazy_distributor_key(), + recipient: dao.receipient_key_from_kta(kta), lazy_distributor_program: lazy_distributor::id(), system_program: solana_sdk::system_program::id(), key_to_asset: kta_key, @@ -147,31 +147,33 @@ async fn set_current_rewards_instruction( Ok(ix) } -pub async fn distribute_rewards_instruction + GetAnchorAccount>( +pub async fn distribute_rewards_instruction< + C: AsRef + GetAnchorAccount, + D: RewardableDao, +>( client: &C, - subdao: &SubDao, + dao: &D, kta: &helium_entity_manager::KeyToAssetV0, + asset: &asset::Asset, + asset_proof: &asset::AssetProof, payer: Pubkey, ) -> Result { - let ld_account = lazy_distributor(client, subdao).await?; - let (asset, asset_proof) = asset::for_kta_with_proof(client, kta).await?; + let ld_account = lazy_distributor(client, dao).await?; let accounts = lazy_distributor::accounts::DistributeCompressionRewardsV0 { DistributeCompressionRewardsV0common: lazy_distributor::accounts::DistributeCompressionRewardsV0Common { payer, - lazy_distributor: subdao.lazy_distributor(), + lazy_distributor: dao.lazy_distributor_key(), associated_token_program: spl_associated_token_account::id(), - rewards_mint: *subdao.mint(), + rewards_mint: *dao.token().mint(), rewards_escrow: ld_account.rewards_escrow, system_program: solana_sdk::system_program::ID, token_program: anchor_spl::token::ID, circuit_breaker_program: circuit_breaker::id(), owner: asset.ownership.owner, circuit_breaker: lazy_distributor_circuit_breaker(&ld_account), - recipient: subdao.receipient_key_from_kta(kta), - destination_account: subdao - .token() - .associated_token_adress(&asset.ownership.owner), + recipient: dao.receipient_key_from_kta(kta), + destination_account: dao.token().associated_token_adress(&asset.ownership.owner), }, compression_program: SPL_ACCOUNT_COMPRESSION_PROGRAM_ID, merkle_tree: asset.compression.tree, @@ -195,9 +197,12 @@ pub async fn distribute_rewards_instruction + GetAnchorAccou Ok(ix) } -pub async fn claim + AsRef + GetAnchorAccount>( +pub async fn claim< + C: AsRef + AsRef + GetAnchorAccount, + D: RewardableDao, +>( client: &C, - subdao: &SubDao, + dao: &D, amount: Option, encoded_entity_key: &entity_key::EncodedEntityKey, keypair: &Keypair, @@ -205,7 +210,7 @@ pub async fn claim + AsRef + GetAnchorAccou ) -> Result, Error> { let Some((mut txn, block_height)) = claim_transaction( client, - subdao, + dao, amount, encoded_entity_key, &keypair.pubkey(), @@ -220,9 +225,12 @@ pub async fn claim + AsRef + GetAnchorAccou Ok(Some((txn, block_height))) } -pub async fn claim_transaction + AsRef + GetAnchorAccount>( +pub async fn claim_transaction< + C: AsRef + AsRef + GetAnchorAccount, + D: RewardableDao, +>( client: &C, - subdao: &SubDao, + dao: &D, amount: Option, encoded_entity_key: &entity_key::EncodedEntityKey, payer: &Pubkey, @@ -231,7 +239,7 @@ pub async fn claim_transaction + AsRef + Ge let entity_key_string = encoded_entity_key.to_string(); let pending = pending( client, - subdao, + dao, &[encoded_entity_key.to_string()], encoded_entity_key.encoding.into(), ) @@ -243,9 +251,9 @@ pub async fn claim_transaction + AsRef + Ge let Some(pending_reward) = pending.get(&entity_key_string) else { return Ok(None); }; - let max_claim = max_claim(client, subdao).await?; + let max_claim = max_claim(client, dao).await?; - let mut lifetime_rewards = lifetime(client, subdao, &[entity_key_string.clone()]) + let mut lifetime_rewards = lifetime(client, dao, &[entity_key_string.clone()]) .and_then(|mut lifetime_map| async move { lifetime_map .remove(&entity_key_string) @@ -263,33 +271,47 @@ pub async fn claim_transaction + AsRef + Ge let entity_key = encoded_entity_key.as_entity_key()?; let kta_key = Dao::Hnt.entity_key_to_kta_key(&entity_key); let kta = kta::for_entity_key(&entity_key).await?; + let (asset, asset_proof) = asset::for_kta_with_proof(client, &kta).await?; + let (init_ix, init_budget) = if recipient::for_kta(client, dao, &kta).await?.is_none() { + let ix = recipient::init_instruction(dao, &kta, &asset, &asset_proof, payer).await?; + (Some(ix), recipient::INIT_INSTRUCTION_BUDGET) + } else { + (None, 1) + }; let set_current_ix = - set_current_rewards_instruction(subdao, kta_key, &kta, &lifetime_rewards).await?; - let distribute_ix = distribute_rewards_instruction(client, subdao, &kta, *payer).await?; - let mut ixs_accounts = set_current_ix.accounts.clone(); + set_current_rewards_instruction(dao, kta_key, &kta, &lifetime_rewards).await?; + let distribute_ix = + distribute_rewards_instruction(client, dao, &kta, &asset, &asset_proof, *payer).await?; + let mut ixs_accounts = vec![]; + if let Some(ix) = &init_ix { + ixs_accounts.extend_from_slice(&ix.accounts); + } + ixs_accounts.extend_from_slice(&set_current_ix.accounts); ixs_accounts.extend_from_slice(&distribute_ix.accounts); - let ixs = &[ - priority_fee::compute_budget_instruction(200_000), + let mut ixs = vec![ + priority_fee::compute_budget_instruction(init_budget + 200_000), priority_fee::compute_price_instruction_for_accounts( client, &ixs_accounts, opts.min_priority_fee, ) .await?, - set_current_ix, - distribute_ix, ]; + if let Some(ix) = init_ix { + ixs.push(ix); + } + ixs.extend_from_slice(&[set_current_ix, distribute_ix]); - let (txn, latest_block_height) = mk_transaction_with_blockhash(client, ixs, payer).await?; + let (txn, latest_block_height) = mk_transaction_with_blockhash(client, &ixs, payer).await?; let signed_txn = oracle_sign(&lifetime_rewards.oracle.url, txn).await?; Ok(Some((signed_txn, latest_block_height))) } -pub async fn pending( +pub async fn pending( client: &C, - subdao: &SubDao, + dao: &D, entity_key_strings: &[String], entity_key_encoding: KeySerialization, ) -> Result, Error> { @@ -303,7 +325,7 @@ pub async fn pending( Some(sorted_oracle_rewards.remove(sorted_oracle_rewards.len() / 2)) } - let bulk_rewards = lifetime(client, subdao, entity_key_strings).await?; + let bulk_rewards = lifetime(client, dao, entity_key_strings).await?; // collect entity keys to request all ktas at once let entity_keys: Vec> = entity_key_strings .iter() @@ -325,33 +347,37 @@ pub async fn pending( .into_iter() .multiunzip(); // Get all recipients for rewarded assets - let recipients = recipient::for_ktas(client, subdao, &rewarded_ktas).await?; + let recipients = recipient::for_ktas(client, dao, &rewarded_ktas).await?; // And adjust the oracle reward by the already claimed rewards in the recipient if available let entity_key_rewards = izip!(rewarded_entity_key_strings, rewards, recipients) - .map(|(entity_key_string, mut reward, maybe_recipient)| { + .filter_map(|(entity_key_string, mut reward, maybe_recipient)| { if let Some(recipient) = maybe_recipient { reward.reward.amount = reward.reward.amount.saturating_sub(recipient.total_rewards); } - (entity_key_string, reward) + // Filter out 0 rewards + if reward.reward.amount == 0 { + None + } else { + Some((entity_key_string, reward)) + } }) .collect(); Ok(entity_key_rewards) } -pub async fn lifetime( +pub async fn lifetime( client: &C, - subdao: &SubDao, + dao: &D, entity_key_strings: &[String], ) -> Result>, Error> { - let ld_account = lazy_distributor(client, subdao).await?; + let ld_account = lazy_distributor(client, dao).await?; stream::iter(ld_account.oracles) .enumerate() .map(Ok) .try_fold( HashMap::new(), |mut result, (index, oracle): (usize, lazy_distributor::OracleConfigV0)| async move { - let bulk_rewards = - bulk_from_oracle(subdao, &oracle.url, entity_key_strings).await?; + let bulk_rewards = bulk_from_oracle(dao, &oracle.url, entity_key_strings).await?; bulk_rewards .into_iter() .for_each(|(entity_key, token_amount)| { @@ -397,8 +423,8 @@ async fn oracle_sign(oracle: &str, txn: Transaction) -> Result( + dao: &D, oracle: &str, entity_keys: &[String], ) -> Result, Error> { @@ -428,7 +454,7 @@ async fn bulk_from_oracle( .current_rewards .into_iter() .map(|(entity_key_string, value)| { - value_to_token_amount(subdao, value).map(|amount| (entity_key_string, amount)) + value_to_token_amount(dao, value).map(|amount| (entity_key_string, amount)) }) .try_collect() } @@ -436,45 +462,45 @@ async fn bulk_from_oracle( pub mod recipient { use super::*; - pub async fn for_kta( + pub async fn for_kta( client: &C, - subdao: &SubDao, + dao: &D, kta: &helium_entity_manager::KeyToAssetV0, ) -> Result, Error> { - let recipient_key = subdao.receipient_key_from_kta(kta); + let recipient_key = dao.receipient_key_from_kta(kta); Ok(client.anchor_account(&recipient_key).await.ok()) } - pub async fn for_ktas( + pub async fn for_ktas( client: &C, - subdao: &SubDao, + dao: &D, ktas: &[helium_entity_manager::KeyToAssetV0], ) -> Result>, Error> { let recipient_keys: Vec = ktas .iter() - .map(|kta| subdao.receipient_key_from_kta(kta)) + .map(|kta| dao.receipient_key_from_kta(kta)) .collect(); client.anchor_accounts(&recipient_keys).await } - pub async fn init_instruction( - subdao: &SubDao, + pub async fn init_instruction( + dao: &D, kta: &helium_entity_manager::KeyToAssetV0, asset: &asset::Asset, asset_proof: &asset::AssetProof, payer: &Pubkey, ) -> Result { - fn mk_accounts( + fn mk_accounts( payer: Pubkey, owner: Pubkey, tree: Pubkey, - subdao: &SubDao, + dao: &D, kta: &helium_entity_manager::KeyToAssetV0, ) -> impl ToAccountMetas { lazy_distributor::accounts::InitializeCompressionRecipientV0 { payer, - lazy_distributor: subdao.lazy_distributor(), - recipient: subdao.receipient_key_from_kta(kta), + lazy_distributor: dao.lazy_distributor_key(), + recipient: dao.receipient_key_from_kta(kta), merkle_tree: tree, owner, delegate: owner, @@ -487,7 +513,7 @@ pub mod recipient { *payer, asset.ownership.owner, asset.compression.tree, - subdao, + dao, kta, ) .to_account_metas(None); @@ -509,9 +535,15 @@ pub mod recipient { Ok(ix) } - pub async fn init + AsRef>( + pub const INIT_INSTRUCTION_BUDGET: u32 = 150_000; + + pub async fn init< + E: AsEntityKey, + C: AsRef + AsRef, + D: RewardableDao, + >( client: &C, - subdao: &SubDao, + dao: &D, entity_key: &E, keypair: &Keypair, opts: &TransactionOpts, @@ -519,10 +551,9 @@ pub mod recipient { let kta = kta::for_entity_key(entity_key).await?; let (asset, asset_proof) = asset::for_kta_with_proof(client, &kta).await?; - let ix = init_instruction(subdao, &kta, &asset, &asset_proof, &keypair.pubkey()).await?; - + let ix = init_instruction(dao, &kta, &asset, &asset_proof, &keypair.pubkey()).await?; let ixs = &[ - priority_fee::compute_budget_instruction(150_000), + priority_fee::compute_budget_instruction(INIT_INSTRUCTION_BUDGET), priority_fee::compute_price_instruction_for_accounts( client, &ix.accounts, @@ -531,11 +562,17 @@ pub mod recipient { .await?, ix, ]; - mk_transaction_with_blockhash(client, ixs, &keypair.pubkey()).await + let (mut txn, block_height) = + mk_transaction_with_blockhash(client, ixs, &keypair.pubkey()).await?; + txn.try_sign(&[keypair], *txn.get_recent_blockhash())?; + Ok((txn, block_height)) } } -fn value_to_token_amount(subdao: &SubDao, value: serde_json::Value) -> Result { +fn value_to_token_amount( + dao: &D, + value: serde_json::Value, +) -> Result { let value = match value { serde_json::Value::String(s) => s .parse::() @@ -546,5 +583,5 @@ fn value_to_token_amount(subdao: &SubDao, value: serde_json::Value) -> Result return Err(DecodeError::other(format!("invalid reward value {value}")).into()), }; - Ok(TokenAmount::from_u64(subdao.token(), value)) + Ok(TokenAmount::from_u64(dao.token(), value)) } diff --git a/helium-wallet/src/cmd/assets/rewards.rs b/helium-wallet/src/cmd/assets/rewards.rs index e300a809..ca2954e3 100644 --- a/helium-wallet/src/cmd/assets/rewards.rs +++ b/helium-wallet/src/cmd/assets/rewards.rs @@ -1,6 +1,10 @@ use crate::cmd::*; use anyhow::Context; -use helium_lib::{dao::SubDao, entity_key, kta, reward, token::TokenAmount}; +use helium_lib::{ + dao::{RewardableDao, SubDao}, + entity_key, reward, + token::TokenAmount, +}; #[derive(Debug, Clone, clap::Args)] pub struct Cmd { @@ -37,7 +41,8 @@ impl RewardsCommand { /// List current (total lifetime) rewards issued for a given entity key pub struct ClaimCmd { /// Subdao for command - pub subdao: SubDao, + #[arg(long)] + pub subdao: Option, #[clap(flatten)] pub entity_key: entity_key::EncodedEntityKey, /// The optional amount to claim @@ -45,11 +50,6 @@ pub struct ClaimCmd { /// If not specific the full pending amount is claimed, limited by the maximum /// claim amount for the subdao pub amount: Option, - /// Do not check and initialize the on chain recipient - /// - /// For known assets that have been previously initialized this will speed up the claim - #[arg(long)] - pub skip_init: bool, /// Commit the claim transaction. #[command(flatten)] pub commit: CommitOpts, @@ -60,30 +60,8 @@ impl ClaimCmd { let password = get_wallet_password(false)?; let keypair = opts.load_keypair(password.as_bytes())?; let client = opts.client()?; - let hotspot_kta = kta::for_entity_key(&self.entity_key.as_entity_key()?).await?; let transaction_opts = self.commit.transaction_opts(); - let mut init_response = None; - if !self.skip_init { - let recipient = reward::recipient::for_kta(&client, &self.subdao, &hotspot_kta).await?; - if recipient.is_none() { - let (tx, _) = reward::recipient::init( - &client, - &self.subdao, - &self.entity_key.as_entity_key()?, - &keypair, - &transaction_opts, - ) - .await?; - init_response = Some( - self.commit - .maybe_commit(&tx, &client) - .await - .context("while initializing reward recipient")?, - ); - } - } - let token_amount = self .amount .map(|amount| TokenAmount::from_f64(self.subdao.token(), amount).amount); @@ -105,16 +83,7 @@ impl ClaimCmd { .maybe_commit(&tx, &client) .await .context("while claiming rewards")?; - let json = if let Some(init_response) = init_response { - json!({ - "init": init_response, - "claim": claim_response, - }) - } else { - claim_response.to_json() - }; - - print_json(&json) + print_json(&claim_response.to_json()) } } @@ -125,7 +94,8 @@ impl ClaimCmd { /// decayed amount bed on previous claims pub struct MaxClaimCmd { /// Subdao for command - subdao: SubDao, + #[arg(long)] + subdao: Option, } impl MaxClaimCmd { @@ -141,7 +111,8 @@ impl MaxClaimCmd { /// List claimable pending rewards for a given asset pub struct PendingCmd { /// Subdao for command - subdao: SubDao, + #[arg(long)] + subdao: Option, #[clap(flatten)] entity_key: entity_key::EncodedEntityKey, @@ -168,7 +139,8 @@ impl PendingCmd { /// This includes both claimed and unclaimed rewards pub struct LifetimeCmd { /// Subdao for command - subdao: SubDao, + #[arg(long)] + subdao: Option, #[clap(flatten)] entity_key: entity_key::EncodedEntityKey, diff --git a/helium-wallet/src/cmd/burn.rs b/helium-wallet/src/cmd/burn.rs index 4cc4ed17..daf3ee24 100644 --- a/helium-wallet/src/cmd/burn.rs +++ b/helium-wallet/src/cmd/burn.rs @@ -1,5 +1,8 @@ use crate::cmd::*; -use helium_lib::{dao::SubDao, token}; +use helium_lib::{ + dao::{RewardableDao, SubDao}, + token, +}; #[derive(Debug, Clone, clap::Args)] /// Burn tokens diff --git a/helium-wallet/src/cmd/hotspots/rewards.rs b/helium-wallet/src/cmd/hotspots/rewards.rs index 00625be3..bd64c13e 100644 --- a/helium-wallet/src/cmd/hotspots/rewards.rs +++ b/helium-wallet/src/cmd/hotspots/rewards.rs @@ -60,7 +60,8 @@ async fn collect_hotspots>( /// List pending rewards for given Hotspots pub struct PendingCmd { /// Subdao for command - subdao: SubDao, + #[arg(long)] + subdao: Option, /// Hotspots to lookup hotspots: Option>, /// Wallet to look up hotspots for @@ -97,7 +98,8 @@ impl PendingCmd { /// This includes both claimed and unclaimed rewards pub struct LifetimeCmd { /// Subdao for command - subdao: SubDao, + #[arg(long)] + subdao: Option, /// Hotspots to lookup hotspots: Option>, /// Wallet to look up hotspots for @@ -126,7 +128,8 @@ impl LifetimeCmd { /// Claim rewards for one or all Hotspots in a wallet pub struct ClaimCmd { /// Subdao for command - subdao: SubDao, + #[arg(long)] + subdao: Option, /// Hotspot public key to send claim for hotspot: helium_crypto::PublicKey, /// The optional amount to claim @@ -134,11 +137,6 @@ pub struct ClaimCmd { /// If not specific the full pending amount is claimed, limited by the maximum /// claim amount for the subdao pub amount: Option, - /// Do not check and initialize the on chain recipient - /// - /// For known assets that have been previously initialized this will speed up the claim - #[arg(long)] - skip_init: bool, /// Commit the claim transaction. #[command(flatten)] commit: CommitOpts, @@ -150,7 +148,6 @@ impl From<&ClaimCmd> for crate::cmd::assets::rewards::ClaimCmd { subdao: value.subdao, entity_key: EncodedEntityKey::from(&value.hotspot), amount: value.amount, - skip_init: value.skip_init, commit: value.commit.clone(), } }