diff --git a/programs/mint_governor/src/instructions/add_mint_authority.rs b/programs/mint_governor/src/instructions/add_mint_authority.rs index 91e08e964..24eeb52a4 100644 --- a/programs/mint_governor/src/instructions/add_mint_authority.rs +++ b/programs/mint_governor/src/instructions/add_mint_authority.rs @@ -10,6 +10,7 @@ pub struct AddMintAuthorityArgs { pub max_total: Option, } +#[event_cpi] #[derive(Accounts)] pub struct AddMintAuthority<'info> { #[account(mut)] @@ -57,7 +58,7 @@ impl AddMintAuthority<'_> { let clock = Clock::get()?; - emit!(MintAuthorityAddedEvent { + emit_cpi!(MintAuthorityAddedEvent { common: CommonFields { slot: clock.slot, unix_timestamp: clock.unix_timestamp, diff --git a/programs/mint_governor/src/instructions/initialize_mint_governor.rs b/programs/mint_governor/src/instructions/initialize_mint_governor.rs index 63461dd8c..c2f49cdd8 100644 --- a/programs/mint_governor/src/instructions/initialize_mint_governor.rs +++ b/programs/mint_governor/src/instructions/initialize_mint_governor.rs @@ -3,6 +3,7 @@ use anchor_spl::token::Mint; use crate::{CommonFields, MintGovernor, MintGovernorInitializedEvent, MINT_GOVERNOR_SEED}; +#[event_cpi] #[derive(Accounts)] pub struct InitializeMintGovernor<'info> { pub mint: Account<'info, Mint>, @@ -44,7 +45,7 @@ impl InitializeMintGovernor<'_> { let clock = Clock::get()?; let mint_governor = &ctx.accounts.mint_governor; - emit!(MintGovernorInitializedEvent { + emit_cpi!(MintGovernorInitializedEvent { common: CommonFields { slot: clock.slot, unix_timestamp: clock.unix_timestamp, diff --git a/programs/mint_governor/src/instructions/mint_tokens.rs b/programs/mint_governor/src/instructions/mint_tokens.rs index 29c882c61..01cdf0d96 100644 --- a/programs/mint_governor/src/instructions/mint_tokens.rs +++ b/programs/mint_governor/src/instructions/mint_tokens.rs @@ -11,6 +11,7 @@ pub struct MintTokensArgs { pub amount: u64, } +#[event_cpi] #[derive(Accounts)] pub struct MintTokens<'info> { #[account(mut)] @@ -93,7 +94,7 @@ impl MintTokens<'_> { // Reload mint to get post-mint supply ctx.accounts.mint.reload()?; - emit!(TokensMintedEvent { + emit_cpi!(TokensMintedEvent { common: CommonFields { slot: clock.slot, unix_timestamp: clock.unix_timestamp, diff --git a/programs/mint_governor/src/instructions/reclaim_authority.rs b/programs/mint_governor/src/instructions/reclaim_authority.rs index db0c18a00..e8f81430f 100644 --- a/programs/mint_governor/src/instructions/reclaim_authority.rs +++ b/programs/mint_governor/src/instructions/reclaim_authority.rs @@ -6,6 +6,7 @@ use crate::{ CommonFields, MintAuthorityReclaimedEvent, MintGovernor, MintGovernorError, MINT_GOVERNOR_SEED, }; +#[event_cpi] #[derive(Accounts)] pub struct ReclaimAuthority<'info> { #[account(mut)] @@ -68,7 +69,7 @@ impl ReclaimAuthority<'_> { // Emit event let clock = Clock::get()?; - emit!(MintAuthorityReclaimedEvent { + emit_cpi!(MintAuthorityReclaimedEvent { common: CommonFields { slot: clock.slot, unix_timestamp: clock.unix_timestamp, diff --git a/programs/mint_governor/src/instructions/remove_mint_authority.rs b/programs/mint_governor/src/instructions/remove_mint_authority.rs index cde94789b..bcb0cebe5 100644 --- a/programs/mint_governor/src/instructions/remove_mint_authority.rs +++ b/programs/mint_governor/src/instructions/remove_mint_authority.rs @@ -4,6 +4,7 @@ use crate::{ CommonFields, MintAuthority, MintAuthorityRemovedEvent, MintGovernor, MintGovernorError, }; +#[event_cpi] #[derive(Accounts)] pub struct RemoveMintAuthority<'info> { #[account(mut)] @@ -39,7 +40,7 @@ impl RemoveMintAuthority<'_> { // Emit event let clock = Clock::get()?; - emit!(MintAuthorityRemovedEvent { + emit_cpi!(MintAuthorityRemovedEvent { common: CommonFields { slot: clock.slot, unix_timestamp: clock.unix_timestamp, diff --git a/programs/mint_governor/src/instructions/transfer_authority_to_governor.rs b/programs/mint_governor/src/instructions/transfer_authority_to_governor.rs index f62719f6b..35ce81449 100644 --- a/programs/mint_governor/src/instructions/transfer_authority_to_governor.rs +++ b/programs/mint_governor/src/instructions/transfer_authority_to_governor.rs @@ -4,6 +4,7 @@ use anchor_spl::token::{self, Mint, SetAuthority, Token}; use crate::{CommonFields, MintAuthorityTransferredEvent, MintGovernor, MintGovernorError}; +#[event_cpi] #[derive(Accounts)] pub struct TransferAuthorityToGovernor<'info> { #[account(mut)] @@ -47,7 +48,7 @@ impl TransferAuthorityToGovernor<'_> { // Emit event let clock = Clock::get()?; - emit!(MintAuthorityTransferredEvent { + emit_cpi!(MintAuthorityTransferredEvent { common: CommonFields { slot: clock.slot, unix_timestamp: clock.unix_timestamp, diff --git a/programs/mint_governor/src/instructions/update_mint_authority.rs b/programs/mint_governor/src/instructions/update_mint_authority.rs index 72960a28c..df1d1ca5f 100644 --- a/programs/mint_governor/src/instructions/update_mint_authority.rs +++ b/programs/mint_governor/src/instructions/update_mint_authority.rs @@ -9,6 +9,7 @@ pub struct UpdateMintAuthorityArgs { pub max_total: Option, } +#[event_cpi] #[derive(Accounts)] pub struct UpdateMintAuthority<'info> { #[account(mut)] @@ -42,7 +43,7 @@ impl UpdateMintAuthority<'_> { // Emit event let clock = Clock::get()?; - emit!(MintAuthorityUpdatedEvent { + emit_cpi!(MintAuthorityUpdatedEvent { common: CommonFields { slot: clock.slot, unix_timestamp: clock.unix_timestamp, diff --git a/programs/mint_governor/src/instructions/update_mint_governor_admin.rs b/programs/mint_governor/src/instructions/update_mint_governor_admin.rs index 561525aaf..2d16288c4 100644 --- a/programs/mint_governor/src/instructions/update_mint_governor_admin.rs +++ b/programs/mint_governor/src/instructions/update_mint_governor_admin.rs @@ -2,6 +2,7 @@ use anchor_lang::prelude::*; use crate::{CommonFields, MintGovernor, MintGovernorAdminUpdatedEvent, MintGovernorError}; +#[event_cpi] #[derive(Accounts)] pub struct UpdateMintGovernorAdmin<'info> { #[account(mut)] @@ -27,7 +28,7 @@ impl UpdateMintGovernorAdmin<'_> { let clock = Clock::get()?; - emit!(MintGovernorAdminUpdatedEvent { + emit_cpi!(MintGovernorAdminUpdatedEvent { common: CommonFields { slot: clock.slot, unix_timestamp: clock.unix_timestamp, diff --git a/programs/performance_package_v2/src/constants.rs b/programs/performance_package_v2/src/constants.rs index 1146d282e..871f1a05e 100644 --- a/programs/performance_package_v2/src/constants.rs +++ b/programs/performance_package_v2/src/constants.rs @@ -5,3 +5,6 @@ pub const CHANGE_REQUEST_SEED: &[u8] = b"change_request"; #[constant] pub const MAX_TRANCHES: usize = 10; + +#[constant] +pub const MAX_MIN_DURATION: u32 = 60 * 60 * 24 * 365; // 365 days in seconds diff --git a/programs/performance_package_v2/src/error.rs b/programs/performance_package_v2/src/error.rs index e6d170ca7..87075943e 100644 --- a/programs/performance_package_v2/src/error.rs +++ b/programs/performance_package_v2/src/error.rs @@ -2,7 +2,6 @@ use anchor_lang::prelude::*; #[error_code] pub enum PerformancePackageError { - // Authorization #[msg("Signer is neither authority nor recipient")] Unauthorized, #[msg("Executor is not the opposite party from proposer")] @@ -11,20 +10,14 @@ pub enum PerformancePackageError { InvalidAuthority, #[msg("Signer is not the admin")] InvalidAdmin, - - // Account validation #[msg("Mint governor does not match the provided mint")] InvalidMintGovernor, #[msg("Mint authority does not match expected configuration")] InvalidMintAuthority, - - // State #[msg("Expected Locked status")] NotLocked, #[msg("Expected Unlocking status")] NotUnlocking, - - // Oracle #[msg("Expected remaining_accounts not provided")] OracleMissingAccount, #[msg("Account pubkey doesn't match expected")] @@ -35,24 +28,18 @@ pub enum PerformancePackageError { OracleInvalidState, #[msg("Minimum duration hasn't passed yet")] OracleMinDurationNotReached, - - // Time #[msg("Minimum unlock timestamp not yet reached")] UnlockTimestampNotReached, - - // Rewards #[msg("Math overflow in reward function")] RewardCalculationOverflow, - - // Configuration #[msg("Tranches should be sorted and non-empty")] InvalidTranches, #[msg("Invalid vesting schedule configuration")] InvalidVestingSchedule, - - // Change Requests #[msg("Missing proposal for execute")] ChangeRequestNotFound, #[msg("All optional change fields are None")] NoChangesProposed, + #[msg("min_duration exceeds maximum allowed (365 days)")] + MinDurationTooLarge, } diff --git a/programs/performance_package_v2/src/instructions/change_authority.rs b/programs/performance_package_v2/src/instructions/change_authority.rs index a7265b68c..80c558f39 100644 --- a/programs/performance_package_v2/src/instructions/change_authority.rs +++ b/programs/performance_package_v2/src/instructions/change_authority.rs @@ -5,6 +5,7 @@ use crate::{ PERFORMANCE_PACKAGE_SEED, }; +#[event_cpi] #[derive(Accounts)] pub struct ChangeAuthority<'info> { #[account( @@ -37,7 +38,7 @@ impl ChangeAuthority<'_> { let clock = Clock::get()?; - emit!(AuthorityChangedEvent { + emit_cpi!(AuthorityChangedEvent { common: CommonFields { slot: clock.slot, unix_timestamp: clock.unix_timestamp, diff --git a/programs/performance_package_v2/src/instructions/close_performance_package.rs b/programs/performance_package_v2/src/instructions/close_performance_package.rs index 98e645f05..9c885f44d 100644 --- a/programs/performance_package_v2/src/instructions/close_performance_package.rs +++ b/programs/performance_package_v2/src/instructions/close_performance_package.rs @@ -12,6 +12,7 @@ pub mod admin { declare_id!("6awyHMshBGVjJ3ozdSJdyyDE1CTAXUwrpNMaRGMsb4sf"); } +#[event_cpi] #[derive(Accounts)] pub struct ClosePerformancePackage<'info> { #[account( @@ -51,7 +52,7 @@ impl ClosePerformancePackage<'_> { let pp = &ctx.accounts.performance_package; let clock = Clock::get()?; - emit!(PerformancePackageClosedEvent { + emit_cpi!(PerformancePackageClosedEvent { common: CommonFields { slot: clock.slot, unix_timestamp: clock.unix_timestamp, diff --git a/programs/performance_package_v2/src/instructions/complete_unlock.rs b/programs/performance_package_v2/src/instructions/complete_unlock.rs index 41ca42aec..209cea06c 100644 --- a/programs/performance_package_v2/src/instructions/complete_unlock.rs +++ b/programs/performance_package_v2/src/instructions/complete_unlock.rs @@ -15,6 +15,7 @@ use crate::{ PERFORMANCE_PACKAGE_SEED, }; +#[event_cpi] #[derive(Accounts)] pub struct CompleteUnlock<'info> { #[account( @@ -56,6 +57,9 @@ pub struct CompleteUnlock<'info> { pub associated_token_program: Program<'info, AssociatedToken>, pub mint_governor_program: Program<'info, MintGovernorProgram>, + + /// CHECK: checked by mint_governor program + pub mint_governor_event_authority: UncheckedAccount<'info>, } impl CompleteUnlock<'_> { @@ -120,6 +124,8 @@ impl CompleteUnlock<'_> { destination_ata: ctx.accounts.recipient_ata.to_account_info(), authorized_minter: ctx.accounts.performance_package.to_account_info(), token_program: ctx.accounts.token_program.to_account_info(), + event_authority: ctx.accounts.mint_governor_event_authority.to_account_info(), + program: ctx.accounts.mint_governor_program.to_account_info(), }, signer_seeds, ); @@ -151,7 +157,7 @@ impl CompleteUnlock<'_> { let clock = Clock::get()?; - emit!(UnlockCompletedEvent { + emit_cpi!(UnlockCompletedEvent { common: CommonFields { slot: clock.slot, unix_timestamp: clock.unix_timestamp, diff --git a/programs/performance_package_v2/src/instructions/execute_change.rs b/programs/performance_package_v2/src/instructions/execute_change.rs index 44b5b5944..7163ef79f 100644 --- a/programs/performance_package_v2/src/instructions/execute_change.rs +++ b/programs/performance_package_v2/src/instructions/execute_change.rs @@ -5,6 +5,7 @@ use crate::{ PerformancePackageError, ProposerType, }; +#[event_cpi] #[derive(Accounts)] pub struct ExecuteChange<'info> { #[account(mut)] @@ -92,7 +93,7 @@ impl ExecuteChange<'_> { let clock = Clock::get()?; - emit!(ChangeExecutedEvent { + emit_cpi!(ChangeExecutedEvent { common: CommonFields { slot: clock.slot, unix_timestamp: clock.unix_timestamp, diff --git a/programs/performance_package_v2/src/instructions/initialize_performance_package.rs b/programs/performance_package_v2/src/instructions/initialize_performance_package.rs index 21544dc98..5b24451f7 100644 --- a/programs/performance_package_v2/src/instructions/initialize_performance_package.rs +++ b/programs/performance_package_v2/src/instructions/initialize_performance_package.rs @@ -14,6 +14,7 @@ pub struct InitializePerformancePackageArgs { pub min_unlock_timestamp: i64, } +#[event_cpi] #[derive(Accounts)] pub struct InitializePerformancePackage<'info> { #[account( @@ -81,7 +82,7 @@ impl InitializePerformancePackage<'_> { let clock = Clock::get()?; let pp = &ctx.accounts.performance_package; - emit!(PerformancePackageCreatedEvent { + emit_cpi!(PerformancePackageCreatedEvent { common: CommonFields { slot: clock.slot, unix_timestamp: clock.unix_timestamp, diff --git a/programs/performance_package_v2/src/instructions/propose_change.rs b/programs/performance_package_v2/src/instructions/propose_change.rs index f6158eef5..8a6f80caf 100644 --- a/programs/performance_package_v2/src/instructions/propose_change.rs +++ b/programs/performance_package_v2/src/instructions/propose_change.rs @@ -13,6 +13,7 @@ pub struct ProposeChangeArgs { pub new_reward_function: Option, } +#[event_cpi] #[derive(Accounts)] #[instruction(args: ProposeChangeArgs)] pub struct ProposeChange<'info> { @@ -102,7 +103,7 @@ impl ProposeChange<'_> { // Increment seq_num for event tracking pp.seq_num += 1; - emit!(ChangeProposedEvent { + emit_cpi!(ChangeProposedEvent { common: CommonFields { slot: clock.slot, unix_timestamp: clock.unix_timestamp, diff --git a/programs/performance_package_v2/src/instructions/start_unlock.rs b/programs/performance_package_v2/src/instructions/start_unlock.rs index 288e86f06..f20db405d 100644 --- a/programs/performance_package_v2/src/instructions/start_unlock.rs +++ b/programs/performance_package_v2/src/instructions/start_unlock.rs @@ -5,6 +5,7 @@ use crate::{ PERFORMANCE_PACKAGE_SEED, }; +#[event_cpi] #[derive(Accounts)] pub struct StartUnlock<'info> { #[account( @@ -21,9 +22,10 @@ impl StartUnlock<'_> { pub fn validate(&self) -> Result<()> { let pp = &self.performance_package; - // Signer must be authority or recipient - require!( - self.signer.key() == pp.authority || self.signer.key() == pp.recipient, + // Only the recipient can start an unlock + require_keys_eq!( + self.signer.key(), + pp.recipient, PerformancePackageError::Unauthorized ); @@ -58,7 +60,7 @@ impl StartUnlock<'_> { let clock = Clock::get()?; - emit!(UnlockStartedEvent { + emit_cpi!(UnlockStartedEvent { common: CommonFields { slot: clock.slot, unix_timestamp: clock.unix_timestamp, diff --git a/programs/performance_package_v2/src/state/performance_package.rs b/programs/performance_package_v2/src/state/performance_package.rs index aa12dcf50..df8a0aaa1 100644 --- a/programs/performance_package_v2/src/state/performance_package.rs +++ b/programs/performance_package_v2/src/state/performance_package.rs @@ -1,7 +1,7 @@ use anchor_lang::prelude::*; use futarchy::state::{Dao, PoolState}; -use crate::{PerformancePackageError, MAX_TRANCHES}; +use crate::{PerformancePackageError, MAX_MIN_DURATION, MAX_TRANCHES}; /// Lifecycle state for the performance package. #[derive(AnchorSerialize, AnchorDeserialize, Debug, Clone, Copy, PartialEq, Eq, InitSpace)] @@ -59,26 +59,27 @@ fn read_futarchy_aggregator( let dao = Dao::try_deserialize(&mut &dao_data[..]) .map_err(|_| PerformancePackageError::OracleParseError)?; - // Read the oracle data from the spot pool - let (aggregator, last_updated_timestamp, last_observation) = match &dao.amm.state { - PoolState::Spot { spot } => ( - spot.oracle.aggregator, - spot.oracle.last_updated_timestamp, - spot.oracle.last_observation, - ), - PoolState::Futarchy { spot, .. } => ( - spot.oracle.aggregator, - spot.oracle.last_updated_timestamp, - spot.oracle.last_observation, - ), + // Read the spot oracle + let oracle = match &dao.amm.state { + PoolState::Spot { spot } | PoolState::Futarchy { spot, .. } => &spot.oracle, }; - // Compute effective aggregator at current time by extrapolating - // from the last update using the last observation value + // Ensure the oracle's start delay has passed before reading the aggregator. + // During the delay period, the aggregator stays at zero while the observation + // tracks price changes. Reading it during or right after the delay would + // produce an artificially low effective aggregator, distorting the TWAP. let clock = Clock::get()?; - let time_since_update = clock.unix_timestamp.saturating_sub(last_updated_timestamp) as u128; - let effective_aggregator = - aggregator.wrapping_add(last_observation.saturating_mul(time_since_update)); + let twap_start_timestamp = oracle.created_at_timestamp + oracle.start_delay_seconds as i64; + require!( + clock.unix_timestamp >= twap_start_timestamp, + PerformancePackageError::OracleInvalidState + ); + let time_since_update = clock + .unix_timestamp + .saturating_sub(oracle.last_updated_timestamp) as u128; + let effective_aggregator = oracle + .aggregator + .wrapping_add(oracle.last_observation.saturating_mul(time_since_update)); Ok((effective_aggregator, clock.unix_timestamp)) } @@ -97,6 +98,11 @@ impl OracleReader { min_duration > 0, PerformancePackageError::InvalidVestingSchedule ); + require_gte!( + MAX_MIN_DURATION, + min_duration, + PerformancePackageError::MinDurationTooLarge + ); Ok(()) } } @@ -162,6 +168,10 @@ impl OracleReader { start_time, .. } => { + // record_start() has not been called yet + if *start_time == 0 { + return false; + } let clock = Clock::get(); match clock { Ok(clock) => { diff --git a/programs/price_based_performance_package/src/instructions/propose_change.rs b/programs/price_based_performance_package/src/instructions/propose_change.rs index 1c4a5f0b2..2430dad21 100644 --- a/programs/price_based_performance_package/src/instructions/propose_change.rs +++ b/programs/price_based_performance_package/src/instructions/propose_change.rs @@ -95,7 +95,7 @@ impl<'info> ProposeChange<'info> { performance_package.seq_num += 1; // Emit event - emit!(ChangeProposed { + emit_cpi!(ChangeProposed { common: CommonFields::new(&clock, performance_package.seq_num), locker: performance_package.key(), change_request: change_request.key(), diff --git a/sdk/src/v0.6/LaunchpadClient.ts b/sdk/src/v0.6/LaunchpadClient.ts index c1e8def39..3a7423820 100644 --- a/sdk/src/v0.6/LaunchpadClient.ts +++ b/sdk/src/v0.6/LaunchpadClient.ts @@ -480,7 +480,7 @@ export class LaunchpadClient { // poolCreatorAuthority, }) .preInstructions([ - ComputeBudgetProgram.setComputeUnitLimit({ units: 800_000 }), + ComputeBudgetProgram.setComputeUnitLimit({ units: 850_000 }), ComputeBudgetProgram.requestHeapFrame({ bytes: 255 * 1024 }), ]); } diff --git a/sdk/src/v0.7/PerformancePackageV2Client.ts b/sdk/src/v0.7/PerformancePackageV2Client.ts index 0e807c702..9eec8f7a7 100644 --- a/sdk/src/v0.7/PerformancePackageV2Client.ts +++ b/sdk/src/v0.7/PerformancePackageV2Client.ts @@ -13,6 +13,7 @@ import { import { getPerformancePackageV2Addr, getChangeRequestV2Addr, + getEventAuthorityAddr, } from "./utils/pda.js"; import { PerformancePackageV2 as PerformancePackageV2Program, @@ -193,6 +194,10 @@ export class PerformancePackageV2Client { }) { const recipientAta = getAssociatedTokenAddressSync(mint, recipient, true); + const [mintGovernorEventAuthority] = getEventAuthorityAddr( + MINT_GOVERNOR_PROGRAM_ID, + ); + const builder = this.program.methods.completeUnlock().accounts({ performancePackage, mintGovernor, @@ -203,6 +208,7 @@ export class PerformancePackageV2Client { tokenProgram: TOKEN_PROGRAM_ID, associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID, mintGovernorProgram: MINT_GOVERNOR_PROGRAM_ID, + mintGovernorEventAuthority, }); if (dao) { diff --git a/sdk/src/v0.7/types/mint_governor.ts b/sdk/src/v0.7/types/mint_governor.ts index b6107843a..b2d9b02c2 100644 --- a/sdk/src/v0.7/types/mint_governor.ts +++ b/sdk/src/v0.7/types/mint_governor.ts @@ -35,6 +35,16 @@ export type MintGovernor = { isMut: false; isSigner: false; }, + { + name: "eventAuthority"; + isMut: false; + isSigner: false; + }, + { + name: "program"; + isMut: false; + isSigner: false; + }, ]; args: []; }, @@ -61,6 +71,16 @@ export type MintGovernor = { isMut: false; isSigner: false; }, + { + name: "eventAuthority"; + isMut: false; + isSigner: false; + }, + { + name: "program"; + isMut: false; + isSigner: false; + }, ]; args: []; }, @@ -97,6 +117,16 @@ export type MintGovernor = { isMut: false; isSigner: false; }, + { + name: "eventAuthority"; + isMut: false; + isSigner: false; + }, + { + name: "program"; + isMut: false; + isSigner: false; + }, ]; args: [ { @@ -140,6 +170,16 @@ export type MintGovernor = { isMut: false; isSigner: false; }, + { + name: "eventAuthority"; + isMut: false; + isSigner: false; + }, + { + name: "program"; + isMut: false; + isSigner: false; + }, ]; args: [ { @@ -168,6 +208,16 @@ export type MintGovernor = { isMut: false; isSigner: true; }, + { + name: "eventAuthority"; + isMut: false; + isSigner: false; + }, + { + name: "program"; + isMut: false; + isSigner: false; + }, ]; args: [ { @@ -201,6 +251,16 @@ export type MintGovernor = { isMut: true; isSigner: false; }, + { + name: "eventAuthority"; + isMut: false; + isSigner: false; + }, + { + name: "program"; + isMut: false; + isSigner: false; + }, ]; args: []; }, @@ -222,6 +282,16 @@ export type MintGovernor = { isMut: false; isSigner: false; }, + { + name: "eventAuthority"; + isMut: false; + isSigner: false; + }, + { + name: "program"; + isMut: false; + isSigner: false; + }, ]; args: []; }, @@ -253,6 +323,16 @@ export type MintGovernor = { isMut: false; isSigner: false; }, + { + name: "eventAuthority"; + isMut: false; + isSigner: false; + }, + { + name: "program"; + isMut: false; + isSigner: false; + }, ]; args: []; }, @@ -692,6 +772,16 @@ export const IDL: MintGovernor = { isMut: false, isSigner: false, }, + { + name: "eventAuthority", + isMut: false, + isSigner: false, + }, + { + name: "program", + isMut: false, + isSigner: false, + }, ], args: [], }, @@ -718,6 +808,16 @@ export const IDL: MintGovernor = { isMut: false, isSigner: false, }, + { + name: "eventAuthority", + isMut: false, + isSigner: false, + }, + { + name: "program", + isMut: false, + isSigner: false, + }, ], args: [], }, @@ -754,6 +854,16 @@ export const IDL: MintGovernor = { isMut: false, isSigner: false, }, + { + name: "eventAuthority", + isMut: false, + isSigner: false, + }, + { + name: "program", + isMut: false, + isSigner: false, + }, ], args: [ { @@ -797,6 +907,16 @@ export const IDL: MintGovernor = { isMut: false, isSigner: false, }, + { + name: "eventAuthority", + isMut: false, + isSigner: false, + }, + { + name: "program", + isMut: false, + isSigner: false, + }, ], args: [ { @@ -825,6 +945,16 @@ export const IDL: MintGovernor = { isMut: false, isSigner: true, }, + { + name: "eventAuthority", + isMut: false, + isSigner: false, + }, + { + name: "program", + isMut: false, + isSigner: false, + }, ], args: [ { @@ -858,6 +988,16 @@ export const IDL: MintGovernor = { isMut: true, isSigner: false, }, + { + name: "eventAuthority", + isMut: false, + isSigner: false, + }, + { + name: "program", + isMut: false, + isSigner: false, + }, ], args: [], }, @@ -879,6 +1019,16 @@ export const IDL: MintGovernor = { isMut: false, isSigner: false, }, + { + name: "eventAuthority", + isMut: false, + isSigner: false, + }, + { + name: "program", + isMut: false, + isSigner: false, + }, ], args: [], }, @@ -910,6 +1060,16 @@ export const IDL: MintGovernor = { isMut: false, isSigner: false, }, + { + name: "eventAuthority", + isMut: false, + isSigner: false, + }, + { + name: "program", + isMut: false, + isSigner: false, + }, ], args: [], }, diff --git a/sdk/src/v0.7/types/performance_package_v2.ts b/sdk/src/v0.7/types/performance_package_v2.ts index 9f9bc7fd2..e246f6498 100644 --- a/sdk/src/v0.7/types/performance_package_v2.ts +++ b/sdk/src/v0.7/types/performance_package_v2.ts @@ -9,6 +9,11 @@ export type PerformancePackageV2 = { }; value: "10"; }, + { + name: "MAX_MIN_DURATION"; + type: "u32"; + value: "60 * 60 * 24 * 365"; + }, ]; instructions: [ { @@ -59,6 +64,16 @@ export type PerformancePackageV2 = { isMut: false; isSigner: false; }, + { + name: "eventAuthority"; + isMut: false; + isSigner: false; + }, + { + name: "program"; + isMut: false; + isSigner: false; + }, ]; args: [ { @@ -82,6 +97,16 @@ export type PerformancePackageV2 = { isMut: false; isSigner: true; }, + { + name: "eventAuthority"; + isMut: false; + isSigner: false; + }, + { + name: "program"; + isMut: false; + isSigner: false; + }, ]; args: []; }, @@ -133,6 +158,21 @@ export type PerformancePackageV2 = { isMut: false; isSigner: false; }, + { + name: "mintGovernorEventAuthority"; + isMut: false; + isSigner: false; + }, + { + name: "eventAuthority"; + isMut: false; + isSigner: false; + }, + { + name: "program"; + isMut: false; + isSigner: false; + }, ]; args: []; }, @@ -156,6 +196,16 @@ export type PerformancePackageV2 = { isSigner: false; docs: ["The new authority address"]; }, + { + name: "eventAuthority"; + isMut: false; + isSigner: false; + }, + { + name: "program"; + isMut: false; + isSigner: false; + }, ]; args: []; }, @@ -187,6 +237,16 @@ export type PerformancePackageV2 = { isMut: false; isSigner: false; }, + { + name: "eventAuthority"; + isMut: false; + isSigner: false; + }, + { + name: "program"; + isMut: false; + isSigner: false; + }, ]; args: [ { @@ -220,6 +280,16 @@ export type PerformancePackageV2 = { isMut: true; isSigner: false; }, + { + name: "eventAuthority"; + isMut: false; + isSigner: false; + }, + { + name: "program"; + isMut: false; + isSigner: false; + }, ]; args: []; }, @@ -241,6 +311,16 @@ export type PerformancePackageV2 = { isMut: true; isSigner: false; }, + { + name: "eventAuthority"; + isMut: false; + isSigner: false; + }, + { + name: "program"; + isMut: false; + isSigner: false; + }, ]; args: []; }, @@ -989,6 +1069,11 @@ export type PerformancePackageV2 = { name: "NoChangesProposed"; msg: "All optional change fields are None"; }, + { + code: 6019; + name: "MinDurationTooLarge"; + msg: "min_duration exceeds maximum allowed (365 days)"; + }, ]; }; @@ -1003,6 +1088,11 @@ export const IDL: PerformancePackageV2 = { }, value: "10", }, + { + name: "MAX_MIN_DURATION", + type: "u32", + value: "60 * 60 * 24 * 365", + }, ], instructions: [ { @@ -1053,6 +1143,16 @@ export const IDL: PerformancePackageV2 = { isMut: false, isSigner: false, }, + { + name: "eventAuthority", + isMut: false, + isSigner: false, + }, + { + name: "program", + isMut: false, + isSigner: false, + }, ], args: [ { @@ -1076,6 +1176,16 @@ export const IDL: PerformancePackageV2 = { isMut: false, isSigner: true, }, + { + name: "eventAuthority", + isMut: false, + isSigner: false, + }, + { + name: "program", + isMut: false, + isSigner: false, + }, ], args: [], }, @@ -1127,6 +1237,21 @@ export const IDL: PerformancePackageV2 = { isMut: false, isSigner: false, }, + { + name: "mintGovernorEventAuthority", + isMut: false, + isSigner: false, + }, + { + name: "eventAuthority", + isMut: false, + isSigner: false, + }, + { + name: "program", + isMut: false, + isSigner: false, + }, ], args: [], }, @@ -1150,6 +1275,16 @@ export const IDL: PerformancePackageV2 = { isSigner: false, docs: ["The new authority address"], }, + { + name: "eventAuthority", + isMut: false, + isSigner: false, + }, + { + name: "program", + isMut: false, + isSigner: false, + }, ], args: [], }, @@ -1181,6 +1316,16 @@ export const IDL: PerformancePackageV2 = { isMut: false, isSigner: false, }, + { + name: "eventAuthority", + isMut: false, + isSigner: false, + }, + { + name: "program", + isMut: false, + isSigner: false, + }, ], args: [ { @@ -1214,6 +1359,16 @@ export const IDL: PerformancePackageV2 = { isMut: true, isSigner: false, }, + { + name: "eventAuthority", + isMut: false, + isSigner: false, + }, + { + name: "program", + isMut: false, + isSigner: false, + }, ], args: [], }, @@ -1235,6 +1390,16 @@ export const IDL: PerformancePackageV2 = { isMut: true, isSigner: false, }, + { + name: "eventAuthority", + isMut: false, + isSigner: false, + }, + { + name: "program", + isMut: false, + isSigner: false, + }, ], args: [], }, @@ -1983,5 +2148,10 @@ export const IDL: PerformancePackageV2 = { name: "NoChangesProposed", msg: "All optional change fields are None", }, + { + code: 6019, + name: "MinDurationTooLarge", + msg: "min_duration exceeds maximum allowed (365 days)", + }, ], }; diff --git a/tests/performancePackageV2/unit/completeUnlock.test.ts b/tests/performancePackageV2/unit/completeUnlock.test.ts index a8edca147..b22e461ea 100644 --- a/tests/performancePackageV2/unit/completeUnlock.test.ts +++ b/tests/performancePackageV2/unit/completeUnlock.test.ts @@ -94,9 +94,9 @@ export default function suite() { await ppClient .startUnlockIx({ performancePackage, - signer: authority.publicKey, + signer: recipient.publicKey, }) - .signers([authority]) + .signers([recipient]) .rpc(); // Advance time by 500 seconds (halfway between cliff and end) @@ -179,9 +179,9 @@ export default function suite() { await ppClient .startUnlockIx({ performancePackage, - signer: authority.publicKey, + signer: recipient.publicKey, }) - .signers([authority]) + .signers([recipient]) .rpc(); // Advance time by 150 seconds (should hit second threshold) @@ -254,9 +254,9 @@ export default function suite() { await ppClient .startUnlockIx({ performancePackage, - signer: authority.publicKey, + signer: recipient.publicKey, }) - .signers([authority]) + .signers([recipient]) .rpc(); await ppClient @@ -284,9 +284,9 @@ export default function suite() { await ppClient .startUnlockIx({ performancePackage, - signer: authority.publicKey, + signer: recipient.publicKey, }) - .signers([authority]) + .signers([recipient]) .rpc(); await ppClient @@ -346,9 +346,9 @@ export default function suite() { await ppClient .startUnlockIx({ performancePackage, - signer: authority.publicKey, + signer: recipient.publicKey, }) - .signers([authority]) + .signers([recipient]) .rpc(); await ppClient @@ -404,9 +404,9 @@ export default function suite() { await ppClient .startUnlockIx({ performancePackage, - signer: authority.publicKey, + signer: recipient.publicKey, }) - .signers([authority]) + .signers([recipient]) .rpc(); await ppClient @@ -472,9 +472,9 @@ export default function suite() { await ppClient .startUnlockIx({ performancePackage, - signer: authority.publicKey, + signer: recipient.publicKey, }) - .signers([authority]) + .signers([recipient]) .rpc(); await ppClient @@ -521,9 +521,9 @@ export default function suite() { await ppClient .startUnlockIx({ performancePackage, - signer: authority.publicKey, + signer: recipient.publicKey, }) - .signers([authority]) + .signers([recipient]) .rpc(); await ppClient @@ -599,17 +599,14 @@ export default function suite() { await createRecipientAta(this, mint, recipient.publicKey); - // Advance time so effective aggregator will be non-zero - await this.advanceBySeconds(10); - // === FIRST UNLOCK CYCLE === await ppClient .startUnlockIx({ performancePackage, - signer: authority.publicKey, + signer: recipient.publicKey, dao, }) - .signers([authority]) + .signers([recipient]) .rpc(); // Record the start snapshot for later manipulation @@ -650,10 +647,10 @@ export default function suite() { await ppClient .startUnlockIx({ performancePackage, - signer: authority.publicKey, + signer: recipient.publicKey, dao, }) - .signers([authority]) + .signers([recipient]) .rpc(); // Get the start snapshot value for second cycle @@ -766,9 +763,9 @@ export default function suite() { await ppClient .startUnlockIx({ performancePackage, - signer: authority.publicKey, + signer: recipient.publicKey, }) - .signers([authority]) + .signers([recipient]) .rpc(); await ppClient @@ -794,9 +791,9 @@ export default function suite() { await ppClient .startUnlockIx({ performancePackage, - signer: authority.publicKey, + signer: recipient.publicKey, }) - .signers([authority]) + .signers([recipient]) .rpc(); // Advance just a tiny bit (not enough to hit second threshold) @@ -869,9 +866,9 @@ export default function suite() { await ppClient .startUnlockIx({ performancePackage, - signer: authority.publicKey, + signer: recipient.publicKey, }) - .signers([authority]) + .signers([recipient]) .rpc(); await ppClient @@ -903,9 +900,9 @@ export default function suite() { await ppClient .startUnlockIx({ performancePackage, - signer: authority.publicKey, + signer: recipient.publicKey, }) - .signers([authority]) + .signers([recipient]) .rpc(); ppAccount = await ppClient.fetchPerformancePackage(performancePackage); @@ -937,9 +934,9 @@ export default function suite() { await ppClient .startUnlockIx({ performancePackage, - signer: authority.publicKey, + signer: recipient.publicKey, }) - .signers([authority]) + .signers([recipient]) .rpc(); await ppClient @@ -1005,25 +1002,19 @@ export default function suite() { // Create recipient ATA await createRecipientAta(this, mint, recipient.publicKey); - // Advance time so the effective aggregator will be non-zero - await this.advanceBySeconds(10); - // Start unlock await ppClient .startUnlockIx({ performancePackage, - signer: authority.publicKey, + signer: recipient.publicKey, dao, }) - .signers([authority]) + .signers([recipient]) .rpc(); // Verify start snapshot was recorded let ppAccount = await ppClient.fetchPerformancePackage(performancePackage); - const startValue = - ppAccount.oracleReader.futarchyTwap.startValue.toString(); const startTime = ppAccount.oracleReader.futarchyTwap.startTime.toString(); - assert.notEqual(startValue, "0"); assert.notEqual(startTime, "0"); assert.equal(ppAccount.oracleReader.futarchyTwap.endValue.toString(), "0"); assert.equal(ppAccount.oracleReader.futarchyTwap.endTime.toString(), "0"); @@ -1104,17 +1095,14 @@ export default function suite() { // Create recipient ATA await createRecipientAta(this, mint, recipient.publicKey); - // Advance time so the effective aggregator will be non-zero - await this.advanceBySeconds(10); - // Start unlock await ppClient .startUnlockIx({ performancePackage, - signer: authority.publicKey, + signer: recipient.publicKey, dao, }) - .signers([authority]) + .signers([recipient]) .rpc(); // Advance time past min_duration @@ -1199,10 +1187,10 @@ export default function suite() { await ppClient .startUnlockIx({ performancePackage, - signer: authority.publicKey, + signer: recipient.publicKey, dao, }) - .signers([authority]) + .signers([recipient]) .rpc(); // Advance time, but NOT past min_duration (only 10 seconds instead of 3600) @@ -1323,9 +1311,9 @@ export default function suite() { await ppClient .startUnlockIx({ performancePackage, - signer: authority.publicKey, + signer: recipient.publicKey, }) - .signers([authority]) + .signers([recipient]) .rpc(); // Try to complete unlock with an unauthorized signer @@ -1428,9 +1416,9 @@ export default function suite() { await ppClient .startUnlockIx({ performancePackage, - signer: authority.publicKey, + signer: recipient.publicKey, }) - .signers([authority]) + .signers([recipient]) .rpc(); // Try to complete unlock with wrong mint - should fail @@ -1501,9 +1489,9 @@ export default function suite() { await ppClient .startUnlockIx({ performancePackage, - signer: authority.publicKey, + signer: recipient.publicKey, }) - .signers([authority]) + .signers([recipient]) .rpc(); // Try to complete unlock with wrong mint governor - should fail diff --git a/tests/performancePackageV2/unit/executeChange.test.ts b/tests/performancePackageV2/unit/executeChange.test.ts index faaabb7dd..2745fba09 100644 --- a/tests/performancePackageV2/unit/executeChange.test.ts +++ b/tests/performancePackageV2/unit/executeChange.test.ts @@ -578,12 +578,12 @@ export default function suite() { await ppClient .startUnlockIx({ performancePackage, - signer: authority.publicKey, + signer: recipient.publicKey, }) .postInstructions([ ComputeBudgetProgram.setComputeUnitLimit({ units: 200_000 }), ]) - .signers([authority]) + .signers([recipient]) .rpc(); // Verify status is Unlocking @@ -653,12 +653,12 @@ export default function suite() { await ppClient .startUnlockIx({ performancePackage, - signer: authority.publicKey, + signer: recipient.publicKey, }) .postInstructions([ ComputeBudgetProgram.setComputeUnitLimit({ units: 200_000 }), ]) - .signers([authority]) + .signers([recipient]) .rpc(); // Verify status is Unlocking diff --git a/tests/performancePackageV2/unit/initializePerformancePackage.test.ts b/tests/performancePackageV2/unit/initializePerformancePackage.test.ts index 9307f13ee..29ae7714e 100644 --- a/tests/performancePackageV2/unit/initializePerformancePackage.test.ts +++ b/tests/performancePackageV2/unit/initializePerformancePackage.test.ts @@ -703,6 +703,95 @@ export default function suite() { .then(callbacks[0], callbacks[1]); }); + it("fails with excessive min_duration", async function () { + const dao = await setupDaoForTwapTests(this); + + const createKey = Keypair.generate(); + const [performancePackage] = getPerformancePackageV2Addr({ + createKey: createKey.publicKey, + }); + + const { mint, mintGovernor, mintAuthority } = + await setupMintGovernorWithAuthority( + this.banksClient, + mintGovernorClient, + this.payer, + performancePackage, + ); + + // 365 days + 1 second - exceeds maximum + const minDuration = 365 * 24 * 60 * 60 + 1; + const oracleReader = createFutarchyTwapOracle({ amm: dao, minDuration }); + const rewardFunction = createCliffLinearReward(); + + const callbacks = expectError( + "MinDurationTooLarge", + "Should have failed because min_duration exceeds maximum allowed", + ); + + await ppClient + .initializePerformancePackageIx({ + createKey: createKey.publicKey, + mint, + mintGovernor, + mintAuthority, + authority: this.payer.publicKey, + recipient: this.payer.publicKey, + payer: this.payer.publicKey, + oracleReader, + rewardFunction, + minUnlockTimestamp: new BN(0), + }) + .signers([createKey]) + .rpc() + .then(callbacks[0], callbacks[1]); + }); + + it("succeeds with max allowed min_duration", async function () { + const dao = await setupDaoForTwapTests(this); + + const createKey = Keypair.generate(); + const [performancePackage] = getPerformancePackageV2Addr({ + createKey: createKey.publicKey, + }); + + const { mint, mintGovernor, mintAuthority } = + await setupMintGovernorWithAuthority( + this.banksClient, + mintGovernorClient, + this.payer, + performancePackage, + ); + + // Exactly 365 days - should succeed + const minDuration = 365 * 24 * 60 * 60; + const oracleReader = createFutarchyTwapOracle({ amm: dao, minDuration }); + const rewardFunction = createCliffLinearReward(); + + await ppClient + .initializePerformancePackageIx({ + createKey: createKey.publicKey, + mint, + mintGovernor, + mintAuthority, + authority: this.payer.publicKey, + recipient: this.payer.publicKey, + payer: this.payer.publicKey, + oracleReader, + rewardFunction, + minUnlockTimestamp: new BN(0), + }) + .signers([createKey]) + .rpc(); + + const ppAccount = + await ppClient.fetchPerformancePackage(performancePackage); + + assert.isNotNull(ppAccount); + assert.isDefined(ppAccount.oracleReader.futarchyTwap); + assert.equal(ppAccount.oracleReader.futarchyTwap.minDuration, minDuration); + }); + it("fails with invalid CliffLinear config - start_value > cliff_value", async function () { const createKey = Keypair.generate(); const [performancePackage] = getPerformancePackageV2Addr({ diff --git a/tests/performancePackageV2/unit/proposeChange.test.ts b/tests/performancePackageV2/unit/proposeChange.test.ts index 9f178a521..09ef04aae 100644 --- a/tests/performancePackageV2/unit/proposeChange.test.ts +++ b/tests/performancePackageV2/unit/proposeChange.test.ts @@ -9,6 +9,8 @@ import { setupPerformancePackageV2, createCliffLinearReward, createThresholdReward, + createFutarchyTwapOracle, + setupDaoForTwapTests, } from "../utils.js"; import { expectError } from "../../utils.js"; @@ -434,6 +436,49 @@ export default function suite() { .then(callbacks[0], callbacks[1]); }); + it("fails when proposing oracle change with excessive min_duration", async function () { + const authority = Keypair.generate(); + const recipient = Keypair.generate(); + + const { performancePackage } = await setupPerformancePackageV2( + this.banksClient, + mintGovernorClient, + ppClient, + this.payer, + { + authority: authority.publicKey, + recipient: recipient.publicKey, + rewardFunction: createCliffLinearReward(), + minUnlockTimestamp: new BN(0), + }, + ); + + const dao = await setupDaoForTwapTests(this); + + // 365 days + 1 second - exceeds maximum + const minDuration = 365 * 24 * 60 * 60 + 1; + const newOracleReader = createFutarchyTwapOracle({ amm: dao, minDuration }); + + const pdaNonce = 1; + + const callbacks = expectError( + "MinDurationTooLarge", + "Should have failed because proposed oracle min_duration exceeds maximum allowed", + ); + + await ppClient + .proposeChangeIx({ + performancePackage, + proposer: authority.publicKey, + payer: this.payer.publicKey, + pdaNonce, + newOracleReader, + }) + .signers([authority]) + .rpc() + .then(callbacks[0], callbacks[1]); + }); + it("fails when signer is neither authority nor recipient", async function () { const authority = Keypair.generate(); const recipient = Keypair.generate(); diff --git a/tests/performancePackageV2/unit/startUnlock.test.ts b/tests/performancePackageV2/unit/startUnlock.test.ts index fe9334559..753ad53bd 100644 --- a/tests/performancePackageV2/unit/startUnlock.test.ts +++ b/tests/performancePackageV2/unit/startUnlock.test.ts @@ -24,7 +24,7 @@ export default function suite() { ppClient = this.performancePackageV2; }); - it("successfully starts when called by authority", async function () { + it("fails when called by authority", async function () { const authority = Keypair.generate(); const recipient = Keypair.generate(); @@ -45,19 +45,20 @@ export default function suite() { let ppAccount = await ppClient.fetchPerformancePackage(performancePackage); assert.isDefined(ppAccount.status.locked); - // Call start_unlock as authority + // Call start_unlock as authority - should fail + const callbacks = expectError( + "Unauthorized", + "Should have failed because only recipient can start unlock", + ); + await ppClient .startUnlockIx({ performancePackage, signer: authority.publicKey, }) .signers([authority]) - .rpc(); - - // Verify status is now Unlocking - ppAccount = await ppClient.fetchPerformancePackage(performancePackage); - assert.isDefined(ppAccount.status.unlocking); - assert.equal(ppAccount.seqNum.toString(), "1"); + .rpc() + .then(callbacks[0], callbacks[1]); }); it("successfully starts when called by recipient", async function () { @@ -117,9 +118,9 @@ export default function suite() { await ppClient .startUnlockIx({ performancePackage, - signer: authority.publicKey, + signer: recipient.publicKey, }) - .signers([authority]) + .signers([recipient]) .rpc(); // Verify status is now Unlocking @@ -137,12 +138,12 @@ export default function suite() { await ppClient .startUnlockIx({ performancePackage, - signer: authority.publicKey, + signer: recipient.publicKey, }) .postInstructions([ ComputeBudgetProgram.setComputeUnitLimit({ units: 200_000 }), ]) - .signers([authority]) + .signers([recipient]) .rpc() .then(callbacks[0], callbacks[1]); }); @@ -180,9 +181,9 @@ export default function suite() { await ppClient .startUnlockIx({ performancePackage, - signer: authority.publicKey, + signer: recipient.publicKey, }) - .signers([authority]) + .signers([recipient]) .rpc() .then(callbacks[0], callbacks[1]); }); @@ -218,9 +219,9 @@ export default function suite() { await ppClient .startUnlockIx({ performancePackage, - signer: authority.publicKey, + signer: recipient.publicKey, }) - .signers([authority]) + .signers([recipient]) .rpc(); // Verify status is now Unlocking @@ -278,12 +279,6 @@ export default function suite() { ); assert.equal(ppAccount.oracleReader.futarchyTwap.startTime.toString(), "0"); - // Advance time so the effective aggregator will be non-zero - // The effective_aggregator = aggregator + last_observation * time_since_update - // After DAO init, aggregator is 0 but last_observation = twapInitialObservation - // We need time_since_update > 0 for effective_aggregator to be non-zero - await this.advanceBySeconds(10); - // Get current time before starting unlock const currentClock = await this.banksClient.getClock(); const currentTimestamp = Number(currentClock.unixTimestamp); @@ -292,10 +287,10 @@ export default function suite() { await ppClient .startUnlockIx({ performancePackage, - signer: authority.publicKey, + signer: recipient.publicKey, dao, }) - .signers([authority]) + .signers([recipient]) .rpc(); // Verify start snapshot was recorded @@ -304,11 +299,7 @@ export default function suite() { assert.isDefined(ppAccount.oracleReader.futarchyTwap); const futarchyTwap = ppAccount.oracleReader.futarchyTwap; - // start_value should be non-zero (the aggregator value from the DAO) - assert.notEqual(futarchyTwap.startValue.toString(), "0"); - // start_time should be close to current timestamp - const startTime = Number(futarchyTwap.startTime.toString()); - assert.isAtLeast(startTime, currentTimestamp); + assert.equal(Number(futarchyTwap.startTime.toString()), currentTimestamp); // end values should still be 0 (not recorded yet) assert.equal(futarchyTwap.endValue.toString(), "0"); assert.equal(futarchyTwap.endTime.toString(), "0"); @@ -367,10 +358,10 @@ export default function suite() { await ppClient .startUnlockIx({ performancePackage, - signer: authority.publicKey, + signer: recipient.publicKey, dao: wrongDao, // Wrong DAO! }) - .signers([authority]) + .signers([recipient]) .rpc() .then(callbacks[0], callbacks[1]); });