From c6d87b7a9dd6c31a57f379aa51ccee0e65eaaf33 Mon Sep 17 00:00:00 2001 From: Noah Prince Date: Fri, 28 Jun 2024 10:43:41 -0700 Subject: [PATCH] Reapply "Feat/632 hip 109 (#634)" This reverts commit ca0139e10d16d39fe425d5fa6ad3dcb6225c61df. --- Cargo.lock | 2 +- packages/hexboosting-sdk/src/pdas.ts | 17 +++++++++++- packages/hexboosting-sdk/src/resolvers.ts | 10 ++++++- programs/hexboosting/Cargo.toml | 2 +- .../hexboosting/src/instructions/boost_v0.rs | 13 ++++++---- .../src/instructions/close_boost_v0.rs | 4 +-- .../src/instructions/start_boost_v0.rs | 4 +-- programs/hexboosting/src/state.rs | 26 ++++++++++++++++++- tests/hexboosting.ts | 26 ++++++++++++------- utils/bulk-claim-rewards/Cargo.lock | 2 +- utils/bulk-claim-rewards/src/claim_rewards.rs | 1 + 11 files changed, 83 insertions(+), 24 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2719d6796..d7ad9f9bd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2002,7 +2002,7 @@ dependencies = [ [[package]] name = "hexboosting" -version = "0.0.6" +version = "0.1.0" dependencies = [ "anchor-lang", "anchor-spl", diff --git a/packages/hexboosting-sdk/src/pdas.ts b/packages/hexboosting-sdk/src/pdas.ts index 639157a38..19b336b81 100644 --- a/packages/hexboosting-sdk/src/pdas.ts +++ b/packages/hexboosting-sdk/src/pdas.ts @@ -2,15 +2,30 @@ import { PublicKey } from "@solana/web3.js"; import { PROGRAM_ID } from "./constants"; import BN from "bn.js"; +enum DeviceType { + cbrsIndoor, + cbrsOutdoor, + wifiIndoor, + wifiOutdoor, +} + export function boostedHexKey( boostConfig: PublicKey, + deviceType: any, location: BN, programId: PublicKey = PROGRAM_ID ) { const locBuffer = Buffer.alloc(8); locBuffer.writeBigUint64LE(BigInt(location.toString())); + const deviceTypeName = Object.keys(deviceType)[0]; + let deviceTypeValue = DeviceType[deviceTypeName]; return PublicKey.findProgramAddressSync( - [Buffer.from("boosted_hex", "utf-8"), boostConfig.toBuffer(), locBuffer], + [ + Buffer.from("boosted_hex", "utf-8"), + boostConfig.toBuffer(), + Buffer.from([deviceTypeValue]), + locBuffer, + ], programId ); } diff --git a/packages/hexboosting-sdk/src/resolvers.ts b/packages/hexboosting-sdk/src/resolvers.ts index d0eb7e978..67bd4cc61 100644 --- a/packages/hexboosting-sdk/src/resolvers.ts +++ b/packages/hexboosting-sdk/src/resolvers.ts @@ -6,13 +6,21 @@ import { } from "@helium/anchor-resolvers"; import { subDaoKey } from "@helium/helium-sub-daos-sdk"; import { PublicKey } from "@solana/web3.js"; +import { boostedHexKey } from "./pdas"; export const hexboostingResolvers = combineResolvers( heliumCommonResolver, - resolveIndividual(async ({ path, accounts }) => { + resolveIndividual(async ({ path, accounts, args }) => { if (path[path.length - 1] === "subDao" && accounts.dntMint) { return subDaoKey(accounts.dntMint as PublicKey)[0]; } + if (path[path.length - 1] === "boostedHex" && accounts.boostConfig && args[0].deviceType && args[0].location) { + return boostedHexKey( + accounts.boostConfig as PublicKey, + args[0].deviceType, + args[0].location + )[0] + } }), ataResolver({ instruction: "boostV0", diff --git a/programs/hexboosting/Cargo.toml b/programs/hexboosting/Cargo.toml index e07c7e6dc..8bf68abd3 100644 --- a/programs/hexboosting/Cargo.toml +++ b/programs/hexboosting/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "hexboosting" -version = "0.0.6" +version = "0.1.0" description = "Created with Anchor" edition = "2021" diff --git a/programs/hexboosting/src/instructions/boost_v0.rs b/programs/hexboosting/src/instructions/boost_v0.rs index 6d70816e6..74cfa0a7e 100644 --- a/programs/hexboosting/src/instructions/boost_v0.rs +++ b/programs/hexboosting/src/instructions/boost_v0.rs @@ -1,4 +1,4 @@ -use crate::error::ErrorCode; +use crate::{error::ErrorCode, DeviceTypeV0}; use anchor_lang::prelude::*; use anchor_spl::{ associated_token::AssociatedToken, @@ -8,7 +8,7 @@ use mobile_entity_manager::CarrierV0; use pyth_solana_receiver_sdk::price_update::{PriceUpdateV2, VerificationLevel}; use shared_utils::resize_to_fit; -use crate::{BoostConfigV0, BoostedHexV0}; +use crate::{BoostConfigV0, BoostedHexV1}; pub const TESTING: bool = std::option_env!("TESTING").is_some(); @@ -20,6 +20,7 @@ pub struct BoostArgsV0 { // invalid pub version: u32, pub amounts: Vec, + pub device_type: DeviceTypeV0, } #[derive(AnchorSerialize, AnchorDeserialize, Clone, Default)] @@ -30,7 +31,7 @@ pub struct BoostAmountV0 { fn get_space(boosted_hex: &AccountInfo) -> usize { if boosted_hex.data_len() == 0 { - 8 + 60 + std::mem::size_of::() + 8 + 60 + std::mem::size_of::() } else { boosted_hex.data_len() } @@ -71,11 +72,11 @@ pub struct BoostV0<'info> { init_if_needed, payer = payer, space = get_space(boosted_hex), - seeds = [b"boosted_hex", boost_config.key().as_ref(), &args.location.to_le_bytes()], + seeds = [b"boosted_hex", boost_config.key().as_ref(), &[(args.device_type as u8)], &args.location.to_le_bytes()], bump, constraint = boosted_hex.version == args.version @ ErrorCode::InvalidVersion, )] - pub boosted_hex: Box>, + pub boosted_hex: Box>, pub system_program: Program<'info, System>, pub token_program: Program<'info, Token>, pub associated_token_program: Program<'info, AssociatedToken>, @@ -89,6 +90,7 @@ pub fn handler(ctx: Context, args: BoostArgsV0) -> Result<()> { ctx.accounts.boosted_hex.location = args.location; ctx.accounts.boosted_hex.bump_seed = ctx.bumps["boosted_hex"]; ctx.accounts.boosted_hex.version += 1; + ctx.accounts.boosted_hex.device_type = args.device_type; // Insert the new periods let max_period = args @@ -104,6 +106,7 @@ pub fn handler(ctx: Context, args: BoostArgsV0) -> Result<()> { .boosts_by_period .resize(max_period + 1, 0); } + let now = Clock::get()?.unix_timestamp; for amount in args.amounts.clone() { diff --git a/programs/hexboosting/src/instructions/close_boost_v0.rs b/programs/hexboosting/src/instructions/close_boost_v0.rs index 09998e26d..26da47cff 100644 --- a/programs/hexboosting/src/instructions/close_boost_v0.rs +++ b/programs/hexboosting/src/instructions/close_boost_v0.rs @@ -1,6 +1,6 @@ use anchor_lang::prelude::*; -use crate::{BoostConfigV0, BoostedHexV0}; +use crate::{BoostConfigV0, BoostedHexV1}; #[derive(Accounts)] pub struct CloseBoostV0<'info> { @@ -15,7 +15,7 @@ pub struct CloseBoostV0<'info> { constraint = boosted_hex.is_expired(&boost_config), has_one = boost_config )] - pub boosted_hex: Box>, + pub boosted_hex: Box>, } pub fn handler(_ctx: Context) -> Result<()> { diff --git a/programs/hexboosting/src/instructions/start_boost_v0.rs b/programs/hexboosting/src/instructions/start_boost_v0.rs index 81e6e6689..98288359a 100644 --- a/programs/hexboosting/src/instructions/start_boost_v0.rs +++ b/programs/hexboosting/src/instructions/start_boost_v0.rs @@ -1,6 +1,6 @@ use anchor_lang::prelude::*; -use crate::{BoostConfigV0, BoostedHexV0}; +use crate::{BoostConfigV0, BoostedHexV1}; #[derive(AnchorSerialize, AnchorDeserialize, Clone, Default)] pub struct StartBoostArgsV0 { @@ -18,7 +18,7 @@ pub struct StartBoostV0<'info> { mut, has_one = boost_config, )] - pub boosted_hex: Box>, + pub boosted_hex: Box>, } pub fn handler(ctx: Context, args: StartBoostArgsV0) -> Result<()> { diff --git a/programs/hexboosting/src/state.rs b/programs/hexboosting/src/state.rs index f34425e65..27d03629c 100644 --- a/programs/hexboosting/src/state.rs +++ b/programs/hexboosting/src/state.rs @@ -20,6 +20,15 @@ pub struct BoostConfigV0 { pub start_authority: Pubkey, } +#[derive(AnchorSerialize, AnchorDeserialize, Clone, Copy, Default, PartialEq)] +pub enum DeviceTypeV0 { + #[default] + CbrsIndoor = 0, + CbrsOutdoor = 1, + WifiIndoor = 2, + WifiOutdoor = 3, +} + #[account] pub struct BoostedHexV0 { pub boost_config: Pubkey, @@ -36,7 +45,22 @@ pub struct BoostedHexV0 { pub version: u32, } -impl BoostedHexV0 { +#[account] +pub struct BoostedHexV1 { + pub device_type: DeviceTypeV0, + pub boost_config: Pubkey, + // Track changes to the boosted hex so client can pass what version it made a change to + pub version: u32, + pub location: u64, + // 0 if the boosting has not yet started. Avoding using an option here to keep serialization length + // consistent + pub start_ts: i64, + pub bump_seed: u8, + /// Each entry represents the boost multiplier for a given period + pub boosts_by_period: Vec, +} + +impl BoostedHexV1 { pub fn is_expired(&self, boost_config: &BoostConfigV0) -> bool { if self.start_ts == 0 { false diff --git a/tests/hexboosting.ts b/tests/hexboosting.ts index 7ea8726d4..c0f548a6c 100644 --- a/tests/hexboosting.ts +++ b/tests/hexboosting.ts @@ -207,11 +207,9 @@ describe("hexboosting", () => { const price = await pythProgram.account.priceUpdateV2.fetch( new PublicKey("DQ4C1tzvu28cwo1roN1Wm6TW35sfJEjLh517k3ZeWevx") ); - pythPrice = - price.priceMessage.emaPrice - .sub(price.priceMessage.emaConf.mul(new BN(2))) - .toNumber() * - 10 ** price.priceMessage.exponent; + pythPrice = price.priceMessage.emaPrice.sub( + price.priceMessage.emaConf.mul(new BN(2)) + ).toNumber() * 10 ** price.priceMessage.exponent; console.log(pythPrice); }); @@ -256,6 +254,7 @@ describe("hexboosting", () => { .boostV0({ location: new BN(1), version: 0, + deviceType: { wifiIndoor: {} }, amounts: [ { period: 0, @@ -304,8 +303,9 @@ describe("hexboosting", () => { expected ); - const hex = await program.account.boostedHexV0.fetch(boostedHex!); + const hex = await program.account.boostedHexV1.fetch(boostedHex!); + expect(Object.keys(hex.deviceType)[0]).to.eq("wifiIndoor"); expect(hex.location.toNumber()).to.eq(1); expect(hex.startTs.toNumber()).to.eq(0); expect(hex.boostsByPeriod.toJSON().data).to.deep.eq([1, 1, 1, 1, 1, 1]); @@ -317,6 +317,7 @@ describe("hexboosting", () => { .boostV0({ location: new BN(1), version: 0, + deviceType: { wifiIndoor: {} }, amounts: [ { period: 0, @@ -364,6 +365,7 @@ describe("hexboosting", () => { .boostV0({ location: new BN(1), version: 1, + deviceType: { wifiIndoor: {} }, amounts: [ { period: 2, @@ -395,7 +397,7 @@ describe("hexboosting", () => { Number(expected) ); - const hex = await program.account.boostedHexV0.fetch(boostedHex!); + const hex = await program.account.boostedHexV1.fetch(boostedHex!); expect(hex.boostsByPeriod.toJSON().data).to.deep.eq([ 1, 1, 2, 1, 1, 1, 2, @@ -403,7 +405,11 @@ describe("hexboosting", () => { }); it("allows starting a boost", async () => { - const boostedHex = boostedHexKey(boostConfigKey(mint)[0], new BN(1))[0]; + const boostedHex = boostedHexKey( + boostConfigKey(mint)[0], + { wifiIndoor: {} }, + new BN(1) + )[0]; await program.methods .startBoostV0({ startTs: new BN(1), @@ -412,7 +418,7 @@ describe("hexboosting", () => { boostedHex, }) .rpc({ skipPreflight: true }); - const acc = await program.account.boostedHexV0.fetch(boostedHex!); + const acc = await program.account.boostedHexV1.fetch(boostedHex!); expect(acc.startTs.toNumber()).to.not.eq(0); }); @@ -425,6 +431,7 @@ describe("hexboosting", () => { beforeEach(async () => { const boostedHex = boostedHexKey( boostConfigKey(mint)[0], + { wifiIndoor: {} }, new BN(1) )[0]; await program.methods @@ -440,6 +447,7 @@ describe("hexboosting", () => { it("allows closing the boost when it's done", async () => { const boostedHex = boostedHexKey( boostConfigKey(mint)[0], + { wifiIndoor: {} }, new BN(1) )[0]; // Wait 7 seconds so it is fully expired diff --git a/utils/bulk-claim-rewards/Cargo.lock b/utils/bulk-claim-rewards/Cargo.lock index cd6505543..e244a0d08 100644 --- a/utils/bulk-claim-rewards/Cargo.lock +++ b/utils/bulk-claim-rewards/Cargo.lock @@ -2285,7 +2285,7 @@ dependencies = [ [[package]] name = "helium-sub-daos" -version = "0.1.5" +version = "0.1.6" dependencies = [ "anchor-lang", "anchor-spl", diff --git a/utils/bulk-claim-rewards/src/claim_rewards.rs b/utils/bulk-claim-rewards/src/claim_rewards.rs index 32ccda7a1..00cee4517 100644 --- a/utils/bulk-claim-rewards/src/claim_rewards.rs +++ b/utils/bulk-claim-rewards/src/claim_rewards.rs @@ -33,6 +33,7 @@ use solana_sdk::signature::Keypair; use solana_sdk::{signer::Signer, transaction::Transaction}; use spl_associated_token_account::get_associated_token_address; use std::ops::Deref; +use std::rc::Rc; use std::str::FromStr; use tokio::runtime::Runtime;