Skip to content

Commit

Permalink
Feat/632 hip 109 (#634)
Browse files Browse the repository at this point in the history
HIP 109 implementation
  • Loading branch information
ChewingGlass authored Jun 3, 2024
1 parent 66f5242 commit 10bbfcd
Show file tree
Hide file tree
Showing 14 changed files with 92 additions and 41 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

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

2 changes: 1 addition & 1 deletion packages/helium-admin-cli/src/create-boost-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ export async function run(args: any = process.argv) {
rentReclaimAuthority: new PublicKey(argv.rentReclaimAuthority),
authority: subDaoAuth,
subDao,
startAuthority: new PublicKey(argv.startAuthority)
startAuthority: new PublicKey(argv.startAuthority),
})
.instruction(),
];
Expand Down
4 changes: 2 additions & 2 deletions packages/helium-admin-cli/src/update-boost-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,11 @@ export async function run(args: any = process.argv) {
},
minimumPeriods: {
type: "number",
describe: "The new minimum number of periods"
describe: "The new minimum number of periods",
},
boostPrice: {
type: "string",
describe: "The boost price in bones"
describe: "The boost price in bones",
},
dntMint: {
type: "string",
Expand Down
17 changes: 16 additions & 1 deletion packages/hexboosting-sdk/src/pdas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
);
}
Expand Down
10 changes: 9 additions & 1 deletion packages/hexboosting-sdk/src/resolvers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
2 changes: 1 addition & 1 deletion programs/hexboosting/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "hexboosting"
version = "0.0.5"
version = "0.1.0"
description = "Created with Anchor"
edition = "2021"

Expand Down
17 changes: 10 additions & 7 deletions programs/hexboosting/src/instructions/boost_v0.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::error::ErrorCode;
use crate::{error::ErrorCode, DeviceTypeV0};
use anchor_lang::prelude::*;
use anchor_spl::{
associated_token::AssociatedToken,
Expand All @@ -8,7 +8,7 @@ use mobile_entity_manager::CarrierV0;
use pyth_sdk_solana::load_price_feed_from_account_info;
use shared_utils::resize_to_fit;

use crate::{BoostConfigV0, BoostedHexV0};
use crate::{BoostConfigV0, BoostedHexV1};

pub const TESTING: bool = std::option_env!("TESTING").is_some();

Expand All @@ -20,6 +20,7 @@ pub struct BoostArgsV0 {
// invalid
pub version: u32,
pub amounts: Vec<BoostAmountV0>,
pub device_type: DeviceTypeV0,
}

#[derive(AnchorSerialize, AnchorDeserialize, Clone, Default)]
Expand All @@ -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::<BoostedHexV0>()
8 + 60 + std::mem::size_of::<BoostedHexV1>()
} else {
boosted_hex.data_len()
}
Expand Down Expand Up @@ -69,11 +70,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<Account<'info, BoostedHexV0>>,
pub boosted_hex: Box<Account<'info, BoostedHexV1>>,
pub system_program: Program<'info, System>,
pub token_program: Program<'info, Token>,
pub associated_token_program: Program<'info, AssociatedToken>,
Expand All @@ -87,6 +88,7 @@ pub fn handler(ctx: Context<BoostV0>, 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
Expand All @@ -102,6 +104,7 @@ pub fn handler(ctx: Context<BoostV0>, args: BoostArgsV0) -> Result<()> {
.boosts_by_period
.resize(max_period + 1, 0);
}

let now = Clock::get()?.unix_timestamp;

for amount in args.amounts.clone() {
Expand Down Expand Up @@ -163,8 +166,8 @@ pub fn handler(ctx: Context<BoostV0>, args: BoostArgsV0) -> Result<()> {
let total_fee: u64 = args
.amounts
.iter()
.map(|amount| amount.amount as u64 * ctx.accounts.boost_config.boost_price)
.sum();
.map(|amount| (amount.amount as u64 * ctx.accounts.boost_config.boost_price))
.sum::<u64>();
let mobile_price_oracle =
load_price_feed_from_account_info(&ctx.accounts.price_oracle).map_err(|e| {
msg!("Pyth error {}", e);
Expand Down
4 changes: 2 additions & 2 deletions programs/hexboosting/src/instructions/close_boost_v0.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use anchor_lang::prelude::*;

use crate::{BoostConfigV0, BoostedHexV0};
use crate::{BoostConfigV0, BoostedHexV1};

#[derive(Accounts)]
pub struct CloseBoostV0<'info> {
Expand All @@ -15,7 +15,7 @@ pub struct CloseBoostV0<'info> {
constraint = boosted_hex.is_expired(&boost_config),
has_one = boost_config
)]
pub boosted_hex: Box<Account<'info, BoostedHexV0>>,
pub boosted_hex: Box<Account<'info, BoostedHexV1>>,
}

pub fn handler(_ctx: Context<CloseBoostV0>) -> Result<()> {
Expand Down
4 changes: 2 additions & 2 deletions programs/hexboosting/src/instructions/start_boost_v0.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use anchor_lang::prelude::*;

use crate::{BoostConfigV0, BoostedHexV0};
use crate::{BoostConfigV0, BoostedHexV1};

#[derive(AnchorSerialize, AnchorDeserialize, Clone, Default)]
pub struct StartBoostArgsV0 {
Expand All @@ -18,7 +18,7 @@ pub struct StartBoostV0<'info> {
mut,
has_one = boost_config,
)]
pub boosted_hex: Box<Account<'info, BoostedHexV0>>,
pub boosted_hex: Box<Account<'info, BoostedHexV1>>,
}

pub fn handler(ctx: Context<StartBoostV0>, args: StartBoostArgsV0) -> Result<()> {
Expand Down
26 changes: 25 additions & 1 deletion programs/hexboosting/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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<u8>,
}

impl BoostedHexV1 {
pub fn is_expired(&self, boost_config: &BoostConfigV0) -> bool {
if self.start_ts == 0 {
false
Expand Down
36 changes: 19 additions & 17 deletions tests/hexboosting.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,11 @@ import {
} from "@solana/web3.js";
import { BN } from "bn.js";
import { expect } from "chai";
import {
init as initHeliumEntityManager
} from "../packages/helium-entity-manager-sdk/src";
import { init as initHeliumEntityManager } from "../packages/helium-entity-manager-sdk/src";
import {
boostConfigKey,
boostedHexKey,
init
init,
} from "../packages/hexboosting-sdk";
import { init as initMobileEntityManager } from "../packages/mobile-entity-manager-sdk/src";
import { DataCredits } from "../target/types/data_credits";
Expand All @@ -39,10 +37,11 @@ import {
ensureHEMIdl,
ensureHSDIdl,
ensureMemIdl,
initTestDataCredits
initTestDataCredits,
} from "./utils/fixtures";
import { random } from "./utils/string";


describe("hexboosting", () => {
anchor.setProvider(anchor.AnchorProvider.local("http://127.0.0.1:8899"));

Expand Down Expand Up @@ -253,6 +252,7 @@ describe("hexboosting", () => {
.boostV0({
location: new BN(1),
version: 0,
deviceType: { wifiIndoor: {} },
amounts: [
{
period: 0,
Expand Down Expand Up @@ -293,7 +293,6 @@ describe("hexboosting", () => {
)
).amount;

console.log(pythPrice);
const expected = Number(
BigInt(toBN((6 * 0.005) / pythPrice, 6).toNumber())
);
Expand All @@ -302,8 +301,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]);
Expand All @@ -315,6 +315,7 @@ describe("hexboosting", () => {
.boostV0({
location: new BN(1),
version: 0,
deviceType: { wifiIndoor: {} },
amounts: [
{
period: 0,
Expand Down Expand Up @@ -362,6 +363,7 @@ describe("hexboosting", () => {
.boostV0({
location: new BN(1),
version: 1,
deviceType: { wifiIndoor: {} },
amounts: [
{
period: 2,
Expand Down Expand Up @@ -393,21 +395,19 @@ 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,
1, 1, 2, 1, 1, 1, 2,
]);
});

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),
Expand All @@ -416,7 +416,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);
});

Expand All @@ -429,6 +429,7 @@ describe("hexboosting", () => {
beforeEach(async () => {
const boostedHex = boostedHexKey(
boostConfigKey(mint)[0],
{ wifiIndoor: {} },
new BN(1)
)[0];
await program.methods
Expand All @@ -444,6 +445,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
Expand Down
6 changes: 3 additions & 3 deletions tests/utils/compression.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ export async function createCompressionNft({
creators: [],
editionNonce: 0,
tokenProgramVersion: TokenProgramVersion.Original,
tokenStandard: TokenStandard.Fungible,
tokenStandard: TokenStandard.NonFungible,
uses: null,
collection: null,
primarySaleHappened: false,
Expand Down Expand Up @@ -126,7 +126,7 @@ export async function createCompressionNft({
await bubblegum.methods
.mintToCollectionV1({
...metadata,
tokenStandard: { fungible: {} },
tokenStandard: { nonFungible: {} },
tokenProgramVersion: { original: {} },
})
.accounts({
Expand All @@ -144,7 +144,7 @@ export async function createCompressionNft({
await bubblegum.methods
.mintV1({
...metadata,
tokenStandard: { fungible: {} },
tokenStandard: { nonFungible: {} },
tokenProgramVersion: { original: {} },
})
.accounts({
Expand Down
Loading

0 comments on commit 10bbfcd

Please sign in to comment.