Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
ChewingGlass committed Jan 31, 2025
2 parents 402e791 + 9d70388 commit e3c0066
Show file tree
Hide file tree
Showing 13 changed files with 1,305 additions and 6 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.

1,059 changes: 1,059 additions & 0 deletions packages/helium-admin-cli/delegatedPositions.txt

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion packages/helium-admin-cli/proxy-seasons.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
[
{ "start": "2023-07-01T00:00:00Z", "end": "2024-08-01T00:00:00Z" },
{ "start": "2024-07-01T00:00:00Z", "end": "2025-08-01T00:00:00Z" },
{ "start": "2025-07-01T00:00:00Z", "end": "2026-08-01T00:00:00Z" },
{ "start": "2026-07-01T00:00:00Z", "end": "2027-08-01T00:00:00Z" },
Expand Down
67 changes: 67 additions & 0 deletions packages/helium-admin-cli/src/fix-claimed-epochs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import * as anchor from "@coral-xyz/anchor";
import {
lazyDistributorKey
} from "@helium/lazy-distributor-sdk";
import { init as initHsd } from "@helium/helium-sub-daos-sdk";
import { organizationKey } from "@helium/organization-sdk";
import { oracleSignerKey } from "@helium/rewards-oracle-sdk";
import {
batchParallelInstructionsWithPriorityFee
} from "@helium/spl-utils";
import { getAssociatedTokenAddressSync } from "@solana/spl-token";
import { PublicKey, TransactionInstruction } from "@solana/web3.js";
import Squads from "@sqds/sdk";
import fs from "fs";
import os from "os";
import yargs from "yargs/yargs";
import {
loadKeypair,
parseEmissionsSchedule,
sendInstructionsOrSquads,
} from "./utils";

export async function run(args: any = process.argv) {
const yarg = yargs(args).options({
wallet: {
alias: "k",
describe: "Anchor wallet keypair",
default: `${os.homedir()}/.config/solana/id.json`,
},
url: {
alias: "u",
default: "http://127.0.0.1:8899",
describe: "The solana url",
},
delegatedPositions: {
type: "string",
describe: "Path to the delegated positions file",
default: __dirname + "/delegatedPositions.txt",
},
});
const argv = await yarg.argv;
process.env.ANCHOR_WALLET = argv.wallet;
process.env.ANCHOR_PROVIDER_URL = argv.url;
anchor.setProvider(anchor.AnchorProvider.local(argv.url));
const provider = anchor.getProvider() as anchor.AnchorProvider;
const wallet = new anchor.Wallet(loadKeypair(argv.wallet));
const hsdProgram = await initHsd(provider);

const delegatedPositions = fs.readFileSync(argv.delegatedPositions, "utf-8")
.split("\n")
.filter(line => line.trim() !== ""); // Remove empty lines

const instructions: TransactionInstruction[] = [];
for (const delegatedPosition of delegatedPositions) {
console.log(delegatedPosition, new PublicKey(delegatedPosition).toBase58());
instructions.push(
await hsdProgram.methods
.tempFixClaimedEpoch()
.accounts({
authority: wallet.publicKey,
delegatedPosition: new PublicKey(delegatedPosition),
})
.instruction()
);
}
await batchParallelInstructionsWithPriorityFee(provider, instructions, {maxSignatureBatch: 100});
}
100 changes: 100 additions & 0 deletions packages/helium-admin-cli/src/update-proxy-config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import * as anchor from "@coral-xyz/anchor";
import {
init as initProxy,
proxyConfigKey,
} from "@helium/nft-proxy-sdk";
import { PublicKey, TransactionInstruction } from "@solana/web3.js";
import Squads from "@sqds/sdk";
import fs from "fs";
import os from "os";
import yargs from "yargs/yargs";
import {
loadKeypair,
sendInstructionsOrSquads
} from "./utils";

export async function run(args: any = process.argv) {
const yarg = yargs(args).options({
wallet: {
alias: "k",
describe: "Anchor wallet keypair",
default: `${os.homedir()}/.config/solana/id.json`,
},
url: {
alias: "u",
default: "http://127.0.0.1:8899",
describe: "The solana url",
},
name: {
required: true,
type: "string",
describe: "Name of the proxy config to be updated",
},
maxProxyTime: {
required: false,
describe: "New max proxy time",
type: "string",
default: null,
},
proxySeasonsFile: {
type: "string",
default: `${__dirname}/../../proxy-seasons.json`,
},
executeTransaction: {
type: "boolean",
},
multisig: {
type: "string",
describe:
"Address of the squads multisig to be authority. If not provided, your wallet will be the authority",
},
authorityIndex: {
type: "number",
describe: "Authority index for squads. Defaults to 1",
default: 1,
},
});
const argv = await yarg.argv;
process.env.ANCHOR_WALLET = argv.wallet;
process.env.ANCHOR_PROVIDER_URL = argv.url;
anchor.setProvider(anchor.AnchorProvider.local(argv.url));
const provider = anchor.getProvider() as anchor.AnchorProvider;
const wallet = new anchor.Wallet(loadKeypair(argv.wallet));
const proxySeasonsFile = fs.readFileSync(argv.proxySeasonsFile, "utf8");
const seasons = JSON.parse(proxySeasonsFile).map((s) => ({
start: new anchor.BN(Math.floor(Date.parse(s.start) / 1000)),
end: new anchor.BN(Math.floor(Date.parse(s.end) / 1000)),
}));

const program = await initProxy(provider);

const instructions: TransactionInstruction[] = [];
const proxyConfig = proxyConfigKey(argv.name)[0];
const proxyConfigAcc = await program.account.proxyConfigV0.fetch(proxyConfig);

instructions.push(
await program.methods
.updateProxyConfigV0({
maxProxyTime: argv.maxProxyTime ? new anchor.BN(argv.maxProxyTime) : null,
seasons,
})
.accounts({
proxyConfig,
authority: proxyConfigAcc.authority,
})
.instruction()
);

const squads = Squads.endpoint(process.env.ANCHOR_PROVIDER_URL, wallet, {
commitmentOrConfig: "finalized",
});
await sendInstructionsOrSquads({
provider,
instructions,
executeTransaction: argv.executeTransaction,
squads,
multisig: argv.multisig ? new PublicKey(argv.multisig) : undefined,
authorityIndex: argv.authorityIndex,
signers: [],
});
}
2 changes: 1 addition & 1 deletion packages/helium-sub-daos-sdk/src/resolvers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ export const closingTimeEpochInfoResolver = resolveIndividual(
if (positionAcc && (proxyConfigAcc || delegatedPositionAcc)) {
const expirationTs =
!delegatedPositionAcc || delegatedPositionAcc.expirationTs.isZero()
? proxyConfigAcc?.seasons.find((s) =>
? proxyConfigAcc?.seasons?.reverse().find((s) =>
new BN(now.toString()).gte(s.start)
)?.end || positionAcc.lockup.endTs
: delegatedPositionAcc.expirationTs;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ export const useCreatePosition = () => {
registrar
);
const currTs = Number(unixTime) + registrarAcc.timeOffset.toNumber();
const endTs = proxyConfig.seasons.find(season => new BN(currTs).gte(season.start))?.end || (currTs + lockupPeriodsInDays * SECS_PER_DAY);
const endTs = proxyConfig.seasons.reverse().find(season => new BN(currTs).gte(season.start))?.end || (currTs + lockupPeriodsInDays * SECS_PER_DAY);
const [subDaoEpochInfo] = subDaoEpochInfoKey(subDao.pubkey, currTs);
const [endSubDaoEpochInfoKey] = subDaoEpochInfoKey(
subDao.pubkey,
Expand Down
2 changes: 1 addition & 1 deletion programs/helium-sub-daos/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "helium-sub-daos"
version = "0.2.4"
version = "0.2.6"
description = "Created with Anchor"
edition = "2021"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ pub struct ClaimRewardsV0<'info> {
#[account(
seeds = ["sub_dao_epoch_info".as_bytes(), sub_dao.key().as_ref(), &args.epoch.to_le_bytes()],
bump,
constraint = sub_dao_epoch_info.rewards_issued_at.is_some() @ ErrorCode::EpochNotClosed
constraint = sub_dao_epoch_info.rewards_issued_at.is_some() @ ErrorCode::EpochNotClosed,
constraint = sub_dao_epoch_info.hnt_rewards_issued == 0,
)]
pub sub_dao_epoch_info: Box<Account<'info, SubDaoEpochInfoV0>>,
#[account(mut)]
Expand Down
2 changes: 2 additions & 0 deletions programs/helium-sub-daos/src/instructions/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ pub mod initialize_hnt_delegator_pool;
pub mod initialize_sub_dao_v0;
pub mod issue_rewards_v0;
pub mod switch_mobile_ops_fund;
pub mod temp_fix_claimed_epoch;
pub mod temp_resize_account;
pub mod temp_update_sub_dao_epoch_info;
pub mod track_dc_burn_v0;
Expand All @@ -24,6 +25,7 @@ pub use initialize_hnt_delegator_pool::*;
pub use initialize_sub_dao_v0::*;
pub use issue_rewards_v0::*;
pub use switch_mobile_ops_fund::*;
pub use temp_fix_claimed_epoch::*;
pub use temp_resize_account::*;
pub use temp_update_sub_dao_epoch_info::*;
pub use track_dc_burn_v0::*;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
use std::str::FromStr;

use anchor_lang::prelude::*;

use crate::DelegatedPositionV0;

#[derive(Accounts)]
pub struct TempFixClaimedEpoch<'info> {
#[account(
mut,
address = Pubkey::from_str("hprdnjkbziK8NqhThmAn5Gu4XqrBbctX8du4PfJdgvW").unwrap()
)]
pub authority: Signer<'info>,
#[account(mut)]
pub delegated_position: Account<'info, DelegatedPositionV0>,
pub system_program: Program<'info, System>,
}

pub fn handler(ctx: Context<TempFixClaimedEpoch>) -> Result<()> {
ctx.accounts.delegated_position.set_unclaimed(20117)?;

Ok(())
}
4 changes: 4 additions & 0 deletions programs/helium-sub-daos/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,4 +147,8 @@ pub mod helium_sub_daos {
pub fn track_vote_v0(ctx: Context<TrackVoteV0>) -> Result<()> {
track_vote_v0::handler(ctx)
}

pub fn temp_fix_claimed_epoch(ctx: Context<TempFixClaimedEpoch>) -> Result<()> {
temp_fix_claimed_epoch::handler(ctx)
}
}
44 changes: 44 additions & 0 deletions programs/helium-sub-daos/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,21 @@ impl DelegatedPositionV0 {
}
}

pub fn set_unclaimed(&mut self, epoch: u64) -> Result<()> {
while epoch <= self.last_claimed_epoch {
self.last_claimed_epoch -= 1;
if self.claimed_epochs_bitmap & 1 != 0 {
return Err(error!(ErrorCode::InvalidClaimEpoch));
}
self.claimed_epochs_bitmap >>= 1;
}

let bit_index = (epoch - self.last_claimed_epoch - 1) as u128;
// Clear the bit at bit_index
self.claimed_epochs_bitmap &= !(1_u128 << (127_u128 - bit_index));
Ok(())
}

// Add a proposal to the recent proposals list
pub fn add_recent_proposal(&mut self, proposal: Pubkey, ts: i64) {
let new_proposal = RecentProposal { proposal, ts };
Expand Down Expand Up @@ -341,4 +356,33 @@ mod tests {
assert_eq!(position.last_claimed_epoch, 2);
assert_eq!(position.claimed_epochs_bitmap, 0);
}

#[test]
fn test_unclaimed() {
let mut position = DelegatedPositionV0::default();
let epoch = 1;

// First claim the epoch
position.set_claimed(epoch).unwrap();
assert!(position.is_claimed(epoch).unwrap());
assert!(position.last_claimed_epoch == 1);

// Then unclaim it
position.set_unclaimed(epoch).unwrap();
assert!(!position.is_claimed(epoch).unwrap());
assert!(!position.is_claimed(epoch + 1).unwrap());
assert!(position.last_claimed_epoch == 0);
assert!(position.claimed_epochs_bitmap == 0);

let epoch = 2;
position.set_claimed(epoch).unwrap();
assert!(position.is_claimed(epoch).unwrap());
assert!(position.last_claimed_epoch == 0);

// Then unclaim it
position.set_unclaimed(epoch).unwrap();
assert!(!position.is_claimed(epoch).unwrap());
assert!(position.last_claimed_epoch == 0);
assert!(position.claimed_epochs_bitmap == 0);
}
}

0 comments on commit e3c0066

Please sign in to comment.