From f63d53a4952af2119723113f052c1b402cc3aa6a Mon Sep 17 00:00:00 2001 From: Pileks Date: Sun, 29 Mar 2026 14:44:42 +0200 Subject: [PATCH 1/3] add extend_launch instruction for admin to extend live launch duration --- Anchor.toml | 1 + programs/v07_launchpad/src/error.rs | 2 + programs/v07_launchpad/src/events.rs | 8 + .../src/instructions/extend_launch.rs | 73 +++++++++ .../v07_launchpad/src/instructions/mod.rs | 2 + programs/v07_launchpad/src/lib.rs | 12 ++ scripts/v0.7/extendLaunch.ts | 118 ++++++++++++++ sdk/src/v0.7/LaunchpadClient.ts | 15 ++ sdk/src/v0.7/types/launchpad_v7.ts | 154 ++++++++++++++++++ tests/launchpad_v7/main.test.ts | 2 + tests/launchpad_v7/unit/extendLaunch.test.ts | 141 ++++++++++++++++ 11 files changed, 528 insertions(+) create mode 100644 programs/v07_launchpad/src/instructions/extend_launch.rs create mode 100644 scripts/v0.7/extendLaunch.ts create mode 100644 tests/launchpad_v7/unit/extendLaunch.test.ts diff --git a/Anchor.toml b/Anchor.toml index e8494edd..01faabd9 100644 --- a/Anchor.toml +++ b/Anchor.toml @@ -69,6 +69,7 @@ v07-dump-launches-funding-records = "yarn run tsx scripts/v0.7/dumpLaunchesAndFu v07-resize-launches-funding-records = "yarn run tsx scripts/v0.7/resizeLaunchesAndFundingRecords.ts" v07-dump-launches = "yarn run tsx scripts/v0.7/dumpLaunches.ts" v07-resize-launches = "yarn run tsx scripts/v0.7/resizeLaunches.ts" +v07-extend-launch = "yarn run tsx scripts/v0.7/extendLaunch.ts" [test] startup_wait = 5000 diff --git a/programs/v07_launchpad/src/error.rs b/programs/v07_launchpad/src/error.rs index 73fd0b95..3a8252e9 100644 --- a/programs/v07_launchpad/src/error.rs +++ b/programs/v07_launchpad/src/error.rs @@ -64,4 +64,6 @@ pub enum LaunchpadError { InvalidDao, #[msg("Accumulator activation delay must be less than the launch duration")] InvalidAccumulatorActivationDelaySeconds, + #[msg("The extend duration would exceed the maximum allowed launch duration")] + ExtendDurationExceedsMax, } diff --git a/programs/v07_launchpad/src/events.rs b/programs/v07_launchpad/src/events.rs index 914b4262..dabd9467 100644 --- a/programs/v07_launchpad/src/events.rs +++ b/programs/v07_launchpad/src/events.rs @@ -125,3 +125,11 @@ pub struct LaunchPerformancePackageInitializedEvent { pub launch: Pubkey, pub performance_package: Pubkey, } + +#[event] +pub struct LaunchExtendedEvent { + pub common: CommonFields, + pub launch: Pubkey, + pub old_seconds_for_launch: u32, + pub new_seconds_for_launch: u32, +} diff --git a/programs/v07_launchpad/src/instructions/extend_launch.rs b/programs/v07_launchpad/src/instructions/extend_launch.rs new file mode 100644 index 00000000..3f1b1971 --- /dev/null +++ b/programs/v07_launchpad/src/instructions/extend_launch.rs @@ -0,0 +1,73 @@ +use anchor_lang::prelude::*; + +use crate::error::LaunchpadError; +use crate::events::{CommonFields, LaunchExtendedEvent}; +use crate::state::{Launch, LaunchState}; + +#[cfg(feature = "production")] +use crate::metadao_multisig_vault; + +#[derive(AnchorSerialize, AnchorDeserialize, Clone)] +pub struct ExtendLaunchArgs { + pub duration_seconds: u32, +} + +#[event_cpi] +#[derive(Accounts)] +pub struct ExtendLaunch<'info> { + #[account(mut)] + pub launch: Account<'info, Launch>, + + pub admin: Signer<'info>, +} + +impl ExtendLaunch<'_> { + pub fn validate(&self, args: &ExtendLaunchArgs) -> Result<()> { + #[cfg(feature = "production")] + require_keys_eq!( + self.admin.key(), + metadao_multisig_vault::ID, + LaunchpadError::InvalidLaunchState + ); + + require!( + self.launch.state == LaunchState::Live, + LaunchpadError::InvalidLaunchState + ); + + require_gt!(args.duration_seconds, 0, LaunchpadError::InvalidAmount); + + require!( + self.launch + .seconds_for_launch + .checked_add(args.duration_seconds) + .is_some(), + LaunchpadError::ExtendDurationExceedsMax + ); + + Ok(()) + } + + pub fn handle(ctx: Context, args: ExtendLaunchArgs) -> Result<()> { + let launch = &mut ctx.accounts.launch; + let clock = Clock::get()?; + + let old_seconds_for_launch = launch.seconds_for_launch; + + launch.seconds_for_launch = launch + .seconds_for_launch + .checked_add(args.duration_seconds) + .unwrap(); + + launch.seq_num += 1; + + emit_cpi!(LaunchExtendedEvent { + common: CommonFields::new(&clock, launch.seq_num), + launch: launch.key(), + old_seconds_for_launch, + new_seconds_for_launch: launch.seconds_for_launch, + }); + + Ok(()) + } +} diff --git a/programs/v07_launchpad/src/instructions/mod.rs b/programs/v07_launchpad/src/instructions/mod.rs index e3441167..14702976 100644 --- a/programs/v07_launchpad/src/instructions/mod.rs +++ b/programs/v07_launchpad/src/instructions/mod.rs @@ -2,6 +2,7 @@ pub mod claim; pub mod claim_additional_token_allocation; pub mod close_launch; pub mod complete_launch; +pub mod extend_launch; pub mod fund; pub mod initialize_launch; pub mod initialize_performance_package; @@ -15,6 +16,7 @@ pub use claim::*; pub use claim_additional_token_allocation::*; pub use close_launch::*; pub use complete_launch::*; +pub use extend_launch::*; pub use fund::*; pub use initialize_launch::*; pub use initialize_performance_package::*; diff --git a/programs/v07_launchpad/src/lib.rs b/programs/v07_launchpad/src/lib.rs index 63134f9d..6dbe26a9 100644 --- a/programs/v07_launchpad/src/lib.rs +++ b/programs/v07_launchpad/src/lib.rs @@ -58,6 +58,13 @@ pub mod fee_recipient { declare_id!("6awyHMshBGVjJ3ozdSJdyyDE1CTAXUwrpNMaRGMsb4sf"); } +pub mod metadao_multisig_vault { + use anchor_lang::prelude::declare_id; + + // MetaDAO operations multisig vault + declare_id!("6awyHMshBGVjJ3ozdSJdyyDE1CTAXUwrpNMaRGMsb4sf"); +} + #[program] pub mod launchpad_v7 { use super::*; @@ -129,4 +136,9 @@ pub mod launchpad_v7 { pub fn resize_launch(ctx: Context) -> Result<()> { ResizeLaunch::handle(ctx) } + + #[access_control(ctx.accounts.validate(&args))] + pub fn extend_launch(ctx: Context, args: ExtendLaunchArgs) -> Result<()> { + ExtendLaunch::handle(ctx, args) + } } diff --git a/scripts/v0.7/extendLaunch.ts b/scripts/v0.7/extendLaunch.ts new file mode 100644 index 00000000..8d94cfa4 --- /dev/null +++ b/scripts/v0.7/extendLaunch.ts @@ -0,0 +1,118 @@ +import * as anchor from "@coral-xyz/anchor"; +import * as multisig from "@sqds/multisig"; +import { + LaunchpadClient, + METADAO_MULTISIG_VAULT, +} from "@metadaoproject/futarchy/v0.7"; +import { PublicKey, Transaction, TransactionMessage } from "@solana/web3.js"; + +// Set the launch address before running the script +const launch = new PublicKey(""); + +// Set the number of seconds to extend the launch by +const durationSeconds = 60 * 60 * 24; // 1 day + +const provider = anchor.AnchorProvider.env(); + +// Payer MUST be a signer with permissions to propose transactions on MetaDAO's multisig +const payer = provider.wallet["payer"]; + +const launchpad: LaunchpadClient = LaunchpadClient.createClient({ provider }); + +// MetaDAO Squads multisig and vault addresses +const metadaoSquadsMultisig = new PublicKey( + "8N3Tvc6B1wEVKVC6iD4s6eyaCNqX2ovj2xze2q3Q9DWH", +); +const metadaoSquadsMultisigVault = METADAO_MULTISIG_VAULT; + +export const extendLaunch = async () => { + const launchAccount = await launchpad.getLaunch(launch); + + console.log(`Extending launch: ${launch.toBase58()}`); + console.log(`Current seconds_for_launch: ${launchAccount.secondsForLaunch}`); + console.log(`Extension: ${durationSeconds} seconds`); + console.log( + `New seconds_for_launch: ${launchAccount.secondsForLaunch + durationSeconds}`, + ); + + // Build the extend_launch instruction + const extendLaunchIx = await launchpad + .extendLaunchIx({ + launch, + durationSeconds, + admin: metadaoSquadsMultisigVault, + }) + .instruction(); + + // Build the transaction message with the multisig vault as payer + const transactionMessage = new TransactionMessage({ + instructions: [extendLaunchIx], + payerKey: metadaoSquadsMultisigVault, + recentBlockhash: (await provider.connection.getLatestBlockhash()).blockhash, + }); + + // Log the transaction message as base64 + const compiledMessage = transactionMessage.compileToLegacyMessage(); + const base64Message = Buffer.from(compiledMessage.serialize()).toString( + "base64", + ); + console.log("\nTransaction message (base64):"); + console.log(base64Message); + + // TODO: Uncomment this when ready to extend the launch + return; + + // Fetch the current multisig state to get the next transaction index + const metaDaoSquadsMultisigAccount = + await multisig.accounts.Multisig.fromAccountAddress( + provider.connection, + metadaoSquadsMultisig, + ); + + const transactionIndex = + BigInt(metaDaoSquadsMultisigAccount.transactionIndex.toString()) + 1n; + + // Create vault transaction instruction + const vaultTxCreateIx = multisig.instructions.vaultTransactionCreate({ + multisigPda: metadaoSquadsMultisig, + transactionIndex, + creator: payer.publicKey, + rentPayer: payer.publicKey, + vaultIndex: 0, + ephemeralSigners: 0, + transactionMessage, + }); + + // Create proposal instruction + const proposalCreateIx = multisig.instructions.proposalCreate({ + multisigPda: metadaoSquadsMultisig, + transactionIndex, + creator: payer.publicKey, + rentPayer: payer.publicKey, + isDraft: false, + }); + + // Build, sign, and send the transaction + const tx = new Transaction().add(vaultTxCreateIx, proposalCreateIx); + tx.recentBlockhash = ( + await provider.connection.getLatestBlockhash() + ).blockhash; + tx.feePayer = payer.publicKey; + tx.sign(payer); + + const txHash = await provider.connection.sendRawTransaction(tx.serialize()); + await provider.connection.confirmTransaction(txHash, "confirmed"); + + const [proposalPda] = multisig.getProposalPda({ + multisigPda: metadaoSquadsMultisig, + transactionIndex, + }); + + console.log("\nVault transaction + proposal created successfully!"); + console.log("Transaction signature:", txHash); + console.log("Proposal index:", transactionIndex.toString()); + console.log("Proposal PDA:", proposalPda.toBase58()); + console.log("Go ahead and approve/execute the transaction through Squads."); +}; + +extendLaunch().catch(console.error); diff --git a/sdk/src/v0.7/LaunchpadClient.ts b/sdk/src/v0.7/LaunchpadClient.ts index 47922e99..70c31f45 100644 --- a/sdk/src/v0.7/LaunchpadClient.ts +++ b/sdk/src/v0.7/LaunchpadClient.ts @@ -715,6 +715,21 @@ export class LaunchpadClient { }); } + extendLaunchIx({ + launch, + durationSeconds, + admin = METADAO_MULTISIG_VAULT, + }: { + launch: PublicKey; + durationSeconds: number; + admin?: PublicKey; + }) { + return this.launchpad.methods.extendLaunch({ durationSeconds }).accounts({ + launch, + admin, + }); + } + getLaunchAddress({ baseMint }: { baseMint: PublicKey }): PublicKey { return getLaunchAddr(this.launchpad.programId, baseMint)[0]; } diff --git a/sdk/src/v0.7/types/launchpad_v7.ts b/sdk/src/v0.7/types/launchpad_v7.ts index fb82a3b6..e5b1bf7e 100644 --- a/sdk/src/v0.7/types/launchpad_v7.ts +++ b/sdk/src/v0.7/types/launchpad_v7.ts @@ -808,6 +808,39 @@ export type LaunchpadV7 = { ]; args: []; }, + { + name: "extendLaunch"; + accounts: [ + { + name: "launch"; + isMut: true; + isSigner: false; + }, + { + name: "admin"; + isMut: false; + isSigner: true; + }, + { + name: "eventAuthority"; + isMut: false; + isSigner: false; + }, + { + name: "program"; + isMut: false; + isSigner: false; + }, + ]; + args: [ + { + name: "args"; + type: { + defined: "ExtendLaunchArgs"; + }; + }, + ]; + }, ]; accounts: [ { @@ -1358,6 +1391,18 @@ export type LaunchpadV7 = { ]; }; }, + { + name: "ExtendLaunchArgs"; + type: { + kind: "struct"; + fields: [ + { + name: "durationSeconds"; + type: "u32"; + }, + ]; + }; + }, { name: "InitializeLaunchArgs"; type: { @@ -1873,6 +1918,33 @@ export type LaunchpadV7 = { }, ]; }, + { + name: "LaunchExtendedEvent"; + fields: [ + { + name: "common"; + type: { + defined: "CommonFields"; + }; + index: false; + }, + { + name: "launch"; + type: "publicKey"; + index: false; + }, + { + name: "oldSecondsForLaunch"; + type: "u32"; + index: false; + }, + { + name: "newSecondsForLaunch"; + type: "u32"; + index: false; + }, + ]; + }, ]; errors: [ { @@ -2030,6 +2102,11 @@ export type LaunchpadV7 = { name: "InvalidAccumulatorActivationDelaySeconds"; msg: "Accumulator activation delay must be less than the launch duration"; }, + { + code: 6031; + name: "ExtendDurationExceedsMax"; + msg: "The extend duration would exceed the maximum allowed launch duration"; + }, ]; }; @@ -2843,6 +2920,39 @@ export const IDL: LaunchpadV7 = { ], args: [], }, + { + name: "extendLaunch", + accounts: [ + { + name: "launch", + isMut: true, + isSigner: false, + }, + { + name: "admin", + isMut: false, + isSigner: true, + }, + { + name: "eventAuthority", + isMut: false, + isSigner: false, + }, + { + name: "program", + isMut: false, + isSigner: false, + }, + ], + args: [ + { + name: "args", + type: { + defined: "ExtendLaunchArgs", + }, + }, + ], + }, ], accounts: [ { @@ -3393,6 +3503,18 @@ export const IDL: LaunchpadV7 = { ], }, }, + { + name: "ExtendLaunchArgs", + type: { + kind: "struct", + fields: [ + { + name: "durationSeconds", + type: "u32", + }, + ], + }, + }, { name: "InitializeLaunchArgs", type: { @@ -3908,6 +4030,33 @@ export const IDL: LaunchpadV7 = { }, ], }, + { + name: "LaunchExtendedEvent", + fields: [ + { + name: "common", + type: { + defined: "CommonFields", + }, + index: false, + }, + { + name: "launch", + type: "publicKey", + index: false, + }, + { + name: "oldSecondsForLaunch", + type: "u32", + index: false, + }, + { + name: "newSecondsForLaunch", + type: "u32", + index: false, + }, + ], + }, ], errors: [ { @@ -4065,5 +4214,10 @@ export const IDL: LaunchpadV7 = { name: "InvalidAccumulatorActivationDelaySeconds", msg: "Accumulator activation delay must be less than the launch duration", }, + { + code: 6031, + name: "ExtendDurationExceedsMax", + msg: "The extend duration would exceed the maximum allowed launch duration", + }, ], }; diff --git a/tests/launchpad_v7/main.test.ts b/tests/launchpad_v7/main.test.ts index 53bbf1d0..2398a586 100644 --- a/tests/launchpad_v7/main.test.ts +++ b/tests/launchpad_v7/main.test.ts @@ -8,6 +8,7 @@ import closeLaunch from "./unit/closeLaunch.test.js"; import setFundingRecordApproval from "./unit/setFundingRecordApproval.test.js"; import claimAdditionalTokenAllocation from "./unit/claimAdditionalTokenAllocation.test.js"; import initializePerformancePackage from "./unit/initializePerformancePackage.test.js"; +import extendLaunch from "./unit/extendLaunch.test.js"; import { PublicKey } from "@solana/web3.js"; import { LAUNCHPAD_PROGRAM_ID, @@ -85,4 +86,5 @@ export default function suite() { "#claim_additional_token_allocation_v7", claimAdditionalTokenAllocation, ); + describe("#extend_launch_v7", extendLaunch); } diff --git a/tests/launchpad_v7/unit/extendLaunch.test.ts b/tests/launchpad_v7/unit/extendLaunch.test.ts new file mode 100644 index 00000000..7b0490c0 --- /dev/null +++ b/tests/launchpad_v7/unit/extendLaunch.test.ts @@ -0,0 +1,141 @@ +import { + ComputeBudgetProgram, + Keypair, + PublicKey, + Signer, +} from "@solana/web3.js"; +import { assert } from "chai"; +import { LaunchpadClient, MAINNET_USDC } from "@metadaoproject/futarchy/v0.7"; +import { BN } from "bn.js"; +import { initializeMintWithSeeds } from "../utils.js"; + +export default function suite() { + let launchpadClient: LaunchpadClient; + let META: PublicKey; + let launch: PublicKey; + let launchSigner: PublicKey; + let launchAuthority: Signer; + + const secondsForLaunch = 60 * 60 * 24 * 4; // 4 days + + before(async function () { + launchpadClient = this.launchpad_v7; + }); + + beforeEach(async function () { + const result = await initializeMintWithSeeds( + this.banksClient, + this.launchpad_v7, + this.payer, + ); + + META = result.tokenMint; + launch = result.launch; + launchSigner = result.launchSigner; + launchAuthority = new Keypair(); + + await this.setupBasicLaunch({ + baseMint: META, + founders: [this.payer.publicKey], + launchAuthority: launchAuthority.publicKey, + }); + + await launchpadClient + .startLaunchIx({ launch, launchAuthority: launchAuthority.publicKey }) + .signers([launchAuthority]) + .rpc(); + }); + + it("successfully extends a live launch", async function () { + const launchBefore = await launchpadClient.getLaunch(launch); + const originalSeconds = launchBefore.secondsForLaunch; + + const extensionSeconds = 60 * 60 * 24; // 1 day + + await launchpadClient + .extendLaunchIx({ + launch, + durationSeconds: extensionSeconds, + admin: this.payer.publicKey, + }) + .rpc(); + + const launchAfter = await launchpadClient.getLaunch(launch); + assert.equal( + launchAfter.secondsForLaunch, + originalSeconds + extensionSeconds, + ); + assert.equal( + launchAfter.seqNum.toNumber(), + launchBefore.seqNum.toNumber() + 1, + ); + }); + + it("funders can still fund after original deadline if extended", async function () { + const extensionSeconds = 60 * 60 * 24 * 2; // 2 extra days + + await launchpadClient + .extendLaunchIx({ + launch, + durationSeconds: extensionSeconds, + admin: this.payer.publicKey, + }) + .rpc(); + + // Advance past the *original* deadline but still within extended window + await this.advanceBySeconds(secondsForLaunch + 100); + + // Funding should still work + const fundAmount = new BN(100_000_000); // 100 USDC + await launchpadClient.fundIx({ launch, amount: fundAmount }).rpc(); + + const launchAccount = await launchpadClient.getLaunch(launch); + assert.equal( + launchAccount.totalCommittedAmount.toString(), + fundAmount.toString(), + ); + }); + + it("close_launch respects new extended deadline", async function () { + const extensionSeconds = 60 * 60 * 24 * 2; // 2 extra days + + await launchpadClient + .extendLaunchIx({ + launch, + durationSeconds: extensionSeconds, + admin: this.payer.publicKey, + }) + .rpc(); + + // Fund the launch + const fundAmount = new BN(100_000_000); // 100 USDC + await launchpadClient.fundIx({ launch, amount: fundAmount }).rpc(); + + // Advance past original deadline but before extended deadline + await this.advanceBySeconds(secondsForLaunch + 100); + + // close_launch should fail — still within extended window + try { + await launchpadClient.closeLaunchIx({ launch }).rpc(); + assert.fail("Should have thrown error"); + } catch (e) { + assert.include(e.message, "LaunchPeriodNotOver"); + } + + // Advance past the extended deadline + await this.advanceBySeconds(extensionSeconds); + + // close_launch should now succeed + await launchpadClient + .closeLaunchIx({ launch }) + .preInstructions([ + ComputeBudgetProgram.setComputeUnitLimit({ units: 200_001 }), + ]) + .rpc(); + + const launchAccount = await launchpadClient.getLaunch(launch); + assert.isDefined( + launchAccount.state.refunding || launchAccount.state.closed, + ); + }); +} From 5e9d8d721b990e42b818cd5f10f1622ccbc0e6f4 Mon Sep 17 00:00:00 2001 From: Pileks Date: Sun, 29 Mar 2026 14:51:21 +0200 Subject: [PATCH 2/3] unify fee recipient into metadao operational multisig vault --- .../v07_launchpad/src/instructions/complete_launch.rs | 7 ++++--- programs/v07_launchpad/src/lib.rs | 8 -------- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/programs/v07_launchpad/src/instructions/complete_launch.rs b/programs/v07_launchpad/src/instructions/complete_launch.rs index a5e8796d..39be1f37 100644 --- a/programs/v07_launchpad/src/instructions/complete_launch.rs +++ b/programs/v07_launchpad/src/instructions/complete_launch.rs @@ -17,8 +17,9 @@ use crate::error::LaunchpadError; use crate::events::{CommonFields, LaunchCloseEvent, LaunchCompletedEvent}; use crate::state::{Launch, LaunchState}; use crate::{ - fee_recipient, PRICE_SCALE, PROPOSAL_MIN_STAKE_TOKENS, TOKENS_TO_DAMM_V2_LIQUIDITY_UNSCALED, - TOKENS_TO_FUTARCHY_LIQUIDITY, TOKENS_TO_PARTICIPANTS, TOKEN_SCALE, + metadao_multisig_vault, PRICE_SCALE, PROPOSAL_MIN_STAKE_TOKENS, + TOKENS_TO_DAMM_V2_LIQUIDITY_UNSCALED, TOKENS_TO_FUTARCHY_LIQUIDITY, TOKENS_TO_PARTICIPANTS, + TOKEN_SCALE, }; use anchor_spl::metadata::{ mpl_token_metadata::ID as MPL_TOKEN_METADATA_PROGRAM_ID, update_metadata_accounts_v2, Metadata, @@ -213,7 +214,7 @@ pub struct CompleteLaunch<'info> { pub bid_wall_quote_token_account: UncheckedAccount<'info>, /// CHECK: The fee recipient of bid wall fees, a fixed address - #[account(address = fee_recipient::id())] + #[account(address = metadao_multisig_vault::id())] pub fee_recipient: AccountInfo<'info>, pub system_program: Program<'info, System>, diff --git a/programs/v07_launchpad/src/lib.rs b/programs/v07_launchpad/src/lib.rs index 6dbe26a9..ccd3f3be 100644 --- a/programs/v07_launchpad/src/lib.rs +++ b/programs/v07_launchpad/src/lib.rs @@ -50,14 +50,6 @@ pub mod usdc_mint { declare_id!("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"); } -// TODO - Pileks: Set this to the correct fee recipient address -pub mod fee_recipient { - use anchor_lang::prelude::declare_id; - - // MetaDAO multisig vault - declare_id!("6awyHMshBGVjJ3ozdSJdyyDE1CTAXUwrpNMaRGMsb4sf"); -} - pub mod metadao_multisig_vault { use anchor_lang::prelude::declare_id; From b698443a89f7047ad0fa8ada2c4b904557dda384 Mon Sep 17 00:00:00 2001 From: Pileks Date: Sun, 29 Mar 2026 17:00:40 +0200 Subject: [PATCH 3/3] remove incorrect error message --- programs/v07_launchpad/src/instructions/extend_launch.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/programs/v07_launchpad/src/instructions/extend_launch.rs b/programs/v07_launchpad/src/instructions/extend_launch.rs index 3f1b1971..6e4f891f 100644 --- a/programs/v07_launchpad/src/instructions/extend_launch.rs +++ b/programs/v07_launchpad/src/instructions/extend_launch.rs @@ -24,11 +24,7 @@ pub struct ExtendLaunch<'info> { impl ExtendLaunch<'_> { pub fn validate(&self, args: &ExtendLaunchArgs) -> Result<()> { #[cfg(feature = "production")] - require_keys_eq!( - self.admin.key(), - metadao_multisig_vault::ID, - LaunchpadError::InvalidLaunchState - ); + require_keys_eq!(self.admin.key(), metadao_multisig_vault::ID); require!( self.launch.state == LaunchState::Live,