diff --git a/helium-lib/src/boosting.rs b/helium-lib/src/boosting.rs new file mode 100644 index 00000000..ad472f9b --- /dev/null +++ b/helium-lib/src/boosting.rs @@ -0,0 +1,67 @@ +use chrono::{DateTime, Utc}; +use helium_anchor_gen::hexboosting::accounts::StartBoostV0; + +use crate::{ + anchor_lang::{InstructionData, ToAccountMetas}, + client::SolanaRpcClient, + error::Error, + hexboosting, + keypair::Keypair, + keypair::Pubkey, + solana_sdk::{instruction::Instruction, signature::Signer, transaction::Transaction}, +}; + +pub trait StartBoostingHex { + fn start_authority(&self) -> Pubkey; + fn boost_config(&self) -> Pubkey; + fn boosted_hex(&self) -> Pubkey; + fn activation_ts(&self) -> DateTime; +} + +pub async fn start_boost>( + client: &C, + keypair: &Keypair, + updates: impl IntoIterator, +) -> Result { + fn mk_accounts( + start_authority: Pubkey, + boost_config: Pubkey, + boosted_hex: Pubkey, + ) -> StartBoostV0 { + StartBoostV0 { + start_authority, + boost_config, + boosted_hex, + } + } + + let mut ixs = vec![]; + for update in updates { + let accounts = mk_accounts( + update.start_authority(), + update.boost_config(), + update.boosted_hex(), + ); + let ix = Instruction { + program_id: hexboosting::id(), + accounts: accounts.to_account_metas(None), + data: hexboosting::instruction::StartBoostV0 { + _args: hexboosting::StartBoostArgsV0 { + start_ts: update.activation_ts().timestamp(), + }, + } + .data(), + }; + ixs.push(ix); + } + + let recent_blockhash = client.as_ref().get_latest_blockhash().await?; + let tx = Transaction::new_signed_with_payer( + &ixs, + Some(&keypair.pubkey()), + &[keypair], + recent_blockhash, + ); + + Ok(tx) +} diff --git a/helium-lib/src/dao.rs b/helium-lib/src/dao.rs index 1438ae77..4989d406 100644 --- a/helium-lib/src/dao.rs +++ b/helium-lib/src/dao.rs @@ -2,6 +2,7 @@ use crate::{ data_credits, entity_key::AsEntityKey, helium_entity_manager, helium_sub_daos, keypair::Pubkey, lazy_distributor, programs::TOKEN_METADATA_PROGRAM_ID, token::Token, }; +use chrono::Timelike; use sha2::{Digest, Sha256}; #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, serde::Serialize, serde::Deserialize)] @@ -97,6 +98,17 @@ impl Dao { ); key } + + pub fn dc_account_payer() -> Pubkey { + let (key, _) = Pubkey::find_program_address(&[b"account_payer"], &data_credits::id()); + key + } + + pub fn dc_key() -> Pubkey { + let (key, _) = + Pubkey::find_program_address(&[b"dc", Token::Dc.mint().as_ref()], &data_credits::id()); + key + } } #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, serde::Serialize, serde::Deserialize)] @@ -151,12 +163,6 @@ impl SubDao { key } - pub fn dc_key() -> Pubkey { - let (key, _) = - Pubkey::find_program_address(&[b"dc", Token::Dc.mint().as_ref()], &data_credits::id()); - key - } - pub fn delegated_dc_key(&self, router_key: &str) -> Pubkey { let hash = Sha256::digest(router_key); let (key, _) = Pubkey::find_program_address( @@ -231,4 +237,19 @@ impl SubDao { ); key } + + pub fn epoch_info_key(&self) -> Pubkey { + const EPOCH_LENGTH: u32 = 60 * 60 * 24; + let epoch = chrono::Utc::now().second() / EPOCH_LENGTH; + + let (key, _) = Pubkey::find_program_address( + &[ + "sub_dao_epoch_info".as_bytes(), + self.key().as_ref(), + &epoch.to_le_bytes(), + ], + &helium_sub_daos::ID, + ); + key + } } diff --git a/helium-lib/src/dc.rs b/helium-lib/src/dc.rs index eb19c53b..7e140e60 100644 --- a/helium-lib/src/dc.rs +++ b/helium-lib/src/dc.rs @@ -1,3 +1,9 @@ +use anchor_client::anchor_lang::AccountDeserialize; +use helium_anchor_gen::{ + data_credits::accounts::BurnDelegatedDataCreditsV0, + helium_sub_daos::{self, DaoV0, SubDaoV0}, +}; + use crate::{ anchor_lang::{InstructionData, ToAccountMetas}, anchor_spl, circuit_breaker, @@ -6,6 +12,7 @@ use crate::{ data_credits, error::{DecodeError, Error}, keypair::{Keypair, Pubkey}, + priority_fee, solana_sdk::{instruction::Instruction, signer::Signer, transaction::Transaction}, token::{Token, TokenAmount}, }; @@ -37,7 +44,7 @@ pub async fn mint>( hnt_price_oracle: Pubkey, ) -> impl ToAccountMetas { data_credits::accounts::MintDataCreditsV0 { - data_credits: SubDao::dc_key(), + data_credits: Dao::dc_key(), owner, hnt_mint: *Token::Hnt.mint(), dc_mint: *Token::Dc.mint(), @@ -55,7 +62,7 @@ pub async fn mint>( let hnt_price_oracle = client .as_ref() - .anchor_account::(&SubDao::dc_key()) + .anchor_account::(&Dao::dc_key()) .await? .hnt_price_oracle; @@ -89,7 +96,7 @@ pub async fn delegate>( fn mk_accounts(delegated_dc_key: Pubkey, subdao: SubDao, owner: Pubkey) -> impl ToAccountMetas { data_credits::accounts::DelegateDataCreditsV0 { delegated_data_credits: delegated_dc_key, - data_credits: SubDao::dc_key(), + data_credits: Dao::dc_key(), dc_mint: *Token::Dc.mint(), dao: Dao::Hnt.key(), sub_dao: subdao.key(), @@ -136,7 +143,7 @@ pub async fn burn>( data_credits::accounts::BurnWithoutTrackingV0BurnAccounts { burner: Token::Dc.associated_token_adress(&owner), dc_mint: *Token::Dc.mint(), - data_credits: SubDao::dc_key(), + data_credits: Dao::dc_key(), token_program: anchor_spl::token::ID, system_program: solana_sdk::system_program::ID, associated_token_program: anchor_spl::associated_token::ID, @@ -162,3 +169,76 @@ pub async fn burn>( ); Ok(tx) } + +pub async fn burn_delegated>( + client: &C, + sub_dao: SubDao, + keypair: &Keypair, + amount: u64, + router_key: Pubkey, +) -> Result { + fn mk_accounts( + sub_dao: SubDao, + router_key: Pubkey, + dc_burn_authority: Pubkey, + registrar: Pubkey, + ) -> BurnDelegatedDataCreditsV0 { + let delegated_data_credits = SubDao::Iot.delegated_dc_key(&router_key.to_string()); + let escrow_account = SubDao::Iot.escrow_key(&delegated_data_credits); + + BurnDelegatedDataCreditsV0 { + sub_dao_epoch_info: sub_dao.epoch_info_key(), + delegated_data_credits, + escrow_account, + + dao: Dao::Hnt.key(), + sub_dao: sub_dao.key(), + + account_payer: Dao::dc_account_payer(), + data_credits: Dao::dc_key(), + dc_burn_authority, + dc_mint: *Token::Dc.mint(), + registrar, + + token_program: anchor_spl::token::ID, + helium_sub_daos_program: helium_sub_daos::id(), + system_program: solana_sdk::system_program::ID, + } + } + + let (dc_burn_authority, registrar) = { + let account_data = client.as_ref().get_account_data(&SubDao::Iot.key()).await?; + let sub_dao = SubDaoV0::try_deserialize(&mut account_data.as_ref())?; + + let account_data = client.as_ref().get_account_data(&Dao::Hnt.key()).await?; + let dao = DaoV0::try_deserialize(&mut account_data.as_ref())?; + + (sub_dao.dc_burn_authority, dao.registrar) + }; + + let accounts = mk_accounts(sub_dao, router_key, dc_burn_authority, registrar); + let burn_ix = solana_sdk::instruction::Instruction { + program_id: data_credits::id(), + accounts: accounts.to_account_metas(None), + data: data_credits::instruction::BurnDelegatedDataCreditsV0 { + _args: data_credits::BurnDelegatedDataCreditsArgsV0 { amount }, + } + .data(), + }; + + let ixs = [ + priority_fee::compute_price_instruction(300_000), + priority_fee::compute_price_instruction_for_accounts(client, &burn_ix.accounts).await?, + burn_ix, + ]; + + let recent_blockhash = client.as_ref().get_latest_blockhash().await?; + + let tx = Transaction::new_signed_with_payer( + &ixs, + Some(&keypair.pubkey()), + &[keypair], + recent_blockhash, + ); + Ok(tx) +} diff --git a/helium-lib/src/hotspot.rs b/helium-lib/src/hotspot.rs index 2b11c2f3..09b0f614 100644 --- a/helium-lib/src/hotspot.rs +++ b/helium-lib/src/hotspot.rs @@ -404,7 +404,7 @@ pub async fn direct_update + AsRef>( dao: Dao::Hnt.key(), sub_dao: subdao.key(), dc_mint: *Token::Dc.mint(), - dc: SubDao::dc_key(), + dc: Dao::dc_key(), compression_program: SPL_ACCOUNT_COMPRESSION_PROGRAM_ID, data_credits_program: data_credits::id(), token_program: anchor_spl::token::ID, @@ -579,7 +579,7 @@ pub mod dataonly { key_to_asset: dao.entity_key_to_kta_key(&entity_key), sub_dao: SubDao::Iot.key(), dc_mint: *Token::Dc.mint(), - dc: SubDao::dc_key(), + dc: Dao::dc_key(), compression_program: SPL_ACCOUNT_COMPRESSION_PROGRAM_ID, data_credits_program: data_credits::id(), helium_sub_daos_program: helium_sub_daos::id(), diff --git a/helium-lib/src/keypair.rs b/helium-lib/src/keypair.rs index f328c949..ee524fc4 100644 --- a/helium-lib/src/keypair.rs +++ b/helium-lib/src/keypair.rs @@ -99,6 +99,12 @@ impl TryFrom<&[u8; 64]> for Keypair { } } +impl From for Keypair { + fn from(keypair: solana_sdk::signer::keypair::Keypair) -> Self { + Self(keypair) + } +} + impl Keypair { pub fn generate() -> Self { Keypair(solana_sdk::signer::keypair::Keypair::new()) diff --git a/helium-lib/src/lib.rs b/helium-lib/src/lib.rs index 2446e0af..3a4aa543 100644 --- a/helium-lib/src/lib.rs +++ b/helium-lib/src/lib.rs @@ -2,6 +2,7 @@ pub mod asset; pub mod b64; pub mod client; +pub mod boosting; pub mod dao; pub mod dc; pub mod entity_key; @@ -20,7 +21,7 @@ pub use anchor_client::solana_client; pub use anchor_spl; pub use helium_anchor_gen::{ anchor_lang, circuit_breaker, data_credits, helium_entity_manager, helium_sub_daos, - lazy_distributor, + hexboosting, lazy_distributor, }; pub use solana_sdk; pub use solana_sdk::bs58;